26 #if !LELY_NO_STDIO && defined(HAVE_LINUX_RTNETLINK_H)
35 #define RTNL_BUFSIZE 8192
38 static int io_rtnl_getattr_func(
struct ifinfomsg *ifi,
struct rtattr *rta,
39 unsigned short rtalen,
void *data);
41 static int io_rtnl_recv(
int fd,
int (*func)(
struct nlmsghdr *nlh,
void *data),
43 static int io_rtnl_recv_ack(
int fd);
44 static int io_rtnl_recv_newlink(
46 static int io_rtnl_recv_newlink_func(
struct nlmsghdr *nlh,
void *data);
48 static ssize_t io_rtnl_send(
int fd,
struct iovec *iov,
int iovlen);
49 static ssize_t io_rtnl_send_getlink(
int fd, __u32 seq, __u32 pid);
50 static ssize_t io_rtnl_send_newlink(
int fd, __u32 seq, __u32 pid,
int ifi_index,
51 unsigned int ifi_flags,
struct rtattr *rta,
59 int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
65 struct sockaddr_nl addr = {
66 .nl_family = AF_NETLINK, .nl_pid = pid, .nl_groups = groups
69 if (bind(fd, (
struct sockaddr *)&addr,
sizeof(addr)) == -1) {
85 unsigned int ifi_flags,
struct rtattr *rta,
86 unsigned short rtalen)
89 if (io_rtnl_send_newlink(fd, seq, pid, ifi_index, ifi_flags, rta,
93 return io_rtnl_recv_ack(fd);
100 if (io_rtnl_send_getlink(fd, seq, pid) == -1)
102 return io_rtnl_recv_newlink(fd, func, data);
107 unsigned int *pifi_flags,
unsigned short type,
void *data,
108 unsigned short payload)
110 assert(data || !payload);
112 if (ifi_index <= 0) {
119 unsigned int *pifi_flags;
122 unsigned short payload;
123 } args = { ifi_index, pifi_flags, type, data, payload };
129 if (args.ifi_index) {
139 io_rtnl_getattr_func(
struct ifinfomsg *ifi,
struct rtattr *rta,
140 unsigned short rtalen,
void *data)
146 unsigned int *pifi_flags;
149 unsigned short payload;
156 if (!pargs->ifi_index || pargs->ifi_index != ifi->ifi_index)
158 pargs->ifi_index = 0;
160 if (pargs->pifi_flags)
161 *pargs->pifi_flags = ifi->ifi_flags;
169 unsigned short payload = RTA_PAYLOAD(rta);
171 memcpy(pargs->data, RTA_DATA(rta),
172 MIN(pargs->payload, payload));
173 pargs->payload = payload;
180 unsigned int ifi_flags,
unsigned short type,
const void *data,
181 unsigned short payload)
183 assert(data || !payload);
185 char buf[RTA_SPACE(payload)];
187 struct rtattr *rta = (
struct rtattr *)buf;
188 *rta = (
struct rtattr){ .rta_len = RTA_LENGTH(payload),
191 memcpy(RTA_DATA(rta), data, payload);
194 fd, seq, pid, ifi_index, ifi_flags, rta, rta->rta_len);
198 io_rtnl_recv(
int fd,
int (*func)(
struct nlmsghdr *nlh,
void *data),
void *data)
200 char buf[RTNL_BUFSIZE] = { 0 };
210 len = recv(fd, buf,
sizeof(buf), 0);
211 }
while (len == -1 && errno == EINTR);
220 struct nlmsghdr *nlh = (
struct nlmsghdr *)buf;
221 for (; NLMSG_OK(nlh, len); nlh = NLMSG_NEXT(nlh, len)) {
222 if (nlh->nlmsg_type == NLMSG_DONE
223 || !(nlh->nlmsg_flags & NLM_F_MULTI))
225 if (nlh->nlmsg_type == NLMSG_ERROR) {
226 struct nlmsgerr *err = NLMSG_DATA(nlh);
227 if (err->error < 0 && !result) {
232 if (nlh->nlmsg_type < NLMSG_MIN_TYPE)
234 if (func && func(nlh, data) && !result) {
246 io_rtnl_recv_ack(
int fd)
248 return io_rtnl_recv(fd, NULL, NULL);
257 } args = { func, data };
259 return io_rtnl_recv(fd, &io_rtnl_recv_newlink_func, &args);
263 io_rtnl_recv_newlink_func(
struct nlmsghdr *nlh,
void *data)
272 if (nlh->nlmsg_type != RTM_NEWLINK)
278 return pargs->func(NLMSG_DATA(nlh), IFLA_RTA(NLMSG_DATA(nlh)),
279 IFLA_PAYLOAD(nlh), pargs->data);
283 io_rtnl_send(
int fd,
struct iovec *iov,
int iovlen)
285 struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
287 struct msghdr msg = { .msg_name = &addr,
288 .msg_namelen =
sizeof(addr),
290 .msg_iovlen = iovlen };
296 result = sendmsg(fd, &msg, 0);
297 }
while (result == -1 && errno == EINTR);
302 io_rtnl_send_getlink(
int fd, __u32 seq, __u32 pid)
304 char buf[NLMSG_SPACE(
sizeof(
struct rtgenmsg))] = { 0 };
306 struct nlmsghdr *nlh = (
struct nlmsghdr *)buf;
308 *nlh = (
struct nlmsghdr){
309 .nlmsg_len = NLMSG_SPACE(
sizeof(
struct rtgenmsg)),
310 .nlmsg_type = RTM_GETLINK,
311 .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
316 struct rtgenmsg *rtgen = NLMSG_DATA(nlh);
317 *rtgen = (
struct rtgenmsg){ .rtgen_family = AF_UNSPEC };
319 struct iovec iov[] = { { buf,
sizeof(buf) } };
320 return io_rtnl_send(fd, iov,
sizeof(iov) /
sizeof(*iov));
324 io_rtnl_send_newlink(
int fd, __u32 seq, __u32 pid,
int ifi_index,
325 unsigned int ifi_flags,
struct rtattr *rta,
unsigned int rtalen)
327 assert(rta || !rtalen);
329 char buf[NLMSG_SPACE(
sizeof(
struct ifinfomsg))] = { 0 };
331 struct nlmsghdr *nlh = (
struct nlmsghdr *)buf;
332 *nlh = (
struct nlmsghdr){
333 .nlmsg_len = NLMSG_SPACE(
sizeof(
struct ifinfomsg)) + rtalen,
334 .nlmsg_type = RTM_NEWLINK,
335 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
340 struct ifinfomsg *ifi = NLMSG_DATA(nlh);
341 *ifi = (
struct ifinfomsg){ .ifi_family = AF_UNSPEC,
342 .ifi_index = ifi_index,
343 .ifi_flags = ifi_flags,
344 .ifi_change = 0xffffffffu };
346 struct iovec iov[] = { { buf,
sizeof(buf) }, { rta, rtalen } };
347 return io_rtnl_send(fd, iov,
sizeof(iov) /
sizeof(*iov));
350 #endif // !LELY_NO_STDIO && HAVE_LINUX_RTNETLINK_H