Skip to content

Commit

Permalink
netlink: minimal Linux rtnetlink support
Browse files Browse the repository at this point in the history
This 1st of the 10 patches brings support of the minimal subset of
the rtnetlink (Linux routing socket) interface as described here -
https://man7.org/linux/man-pages/man7/rtnetlink.7.html.
The rtnetlink is actually a subset of even richer netlink interface
described here - https://man7.org/linux/man-pages/man7/netlink.7.html.
In other words, rtnetlink covers a NETLINK_ROUTE family of the broader
netlink interface.

We need rtnetlink in order to support the implemetation of
if_nameindex() and getifaddrs() in modern musl 1.1.24. In addition
Golang uses the netlink interface to discover the interfaces and IP
address as well.

Please note this is an original copy of the Charles Myers' two commits:
f1cd48e except of the modifications to
bsd/net.cc that are part of the last commit and subset of the
64a0c1a that adds lltable_foreach()
and lltable_foreach_lle(). The next 8 much smaller patches fix various
small bugs and enhance slightly this implementation.
The last one enables the netlink support and adds a unit test.

The netlink interface is pretty rich and not very precisely documented.
I have actually used a unit test to discover in more details how the
netlink responses should look like.

In general, the application would use standard socket API to open a
socket with the domain and protocol equal to AF_NETLINK and NETLINK_ROUTE
respectively and typically use SOCK_RAW as type. Then it would
optionally bind the socket and build a request sent using standard
sendmsg(). Finally it would receive all replies from kernel using
recvmsg().

To illustrate, the incomplete code might look like this:

////////////////////////////////////////////////////////
//step 1
int s = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);

//step 2
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = pid; // if 0 kernel will assign unique id
bind(s, (struct sockaddr*) &src_addr, sizeof(src_addr))

// step 3
dst_addr.nl_family = AF_NETLINK;
dst_addr.nl_pid = 0; // should be 0 if destination is kernel

iov[0].iov_base = req;
iov[0].iov_len = req->nlmsg_len;

snd_msg.msg_iov = iov;
snd_msg.msg_iovlen = 1;
snd_msg.msg_name = &dst_addr;
snd_msg.msg_namelen = sizeof(dst_addr);

sendmsg(s, &snd_msg, 0)

//step 4
rcv_msg.msg_iov[0].iov_base = buf;
rcv_msg.msg_iov[0].iov_len = BUFSIZE;
recvmsg(s, &rcv_msg, 0)
//process replies received in buf
////////////////////////////////////////////////////////

This patch implements support of only 3 rtnetlink types of requests:
- RTM_GETLINK
- RTM_GETADDR
- RTM_GETNEIGH

The bulk of the implementation is in the linux_netlink.cc and
mostly centers around following functions:
- netlink_attach()
- netlink_bind()
- netlink_output()
- netlink_process_msg()
- netlink_process_getlink_msg()
- netlink_process_getaddr_msg()
- netlink_process_getneigh_msg()

Most other pru_* functions delegate to raw_usrreqs as is.

Authored-by: Charles Myers <[email protected]>
Signed-off-by: Waldemar Kozaczuk <[email protected]>
  • Loading branch information
wkozaczuk committed Jun 13, 2022
1 parent 47e10f3 commit 3f49602
Show file tree
Hide file tree
Showing 8 changed files with 1,143 additions and 3 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@ bsd += bsd/porting/bus_dma.o
bsd += bsd/sys/netinet/if_ether.o
bsd += bsd/sys/compat/linux/linux_socket.o
bsd += bsd/sys/compat/linux/linux_ioctl.o
bsd += bsd/sys/compat/linux/linux_netlink.o
bsd += bsd/sys/net/if_ethersubr.o
bsd += bsd/sys/net/if_llatbl.o
bsd += bsd/sys/net/radix.o
Expand Down
Loading

0 comments on commit 3f49602

Please sign in to comment.