1 /* -*- mode: c; c-file-style: "openbsd" -*- */
2 /*
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 /* Grabbing interfaces information with netlink only. */
19
20 #include "lldpd.h"
21
22 #include <errno.h>
23 #include <sys/socket.h>
24 #include <netdb.h>
25 #include <net/if_arp.h>
26 #include <linux/netlink.h>
27 #include <linux/rtnetlink.h>
28 #include <linux/if_bridge.h>
29
30 #define NETLINK_BUFFER 4096
31
32 struct netlink_req {
33 struct nlmsghdr hdr;
34 struct ifinfomsg ifm;
35 /* attribute has to be NLMSG aligned */
36 struct rtattr ext_req __attribute__ ((aligned(NLMSG_ALIGNTO)));
37 __u32 ext_filter_mask;
38 };
39
40 struct lldpd_netlink {
41 int nl_socket;
42 int nl_socket_recv_size;
43 /* Cache */
44 struct interfaces_device_list *devices;
45 struct interfaces_address_list *addresses;
46 };
47
48 /**
49 * Set netlink socket buffer size.
50 *
51 * This returns the effective size on success. If the provided value is 0, this
52 * returns the current size instead. It returns -1 on system errors and -2 if
53 * the size was not changed appropriately (when reaching the max).
54 */
55 static int
netlink_socket_set_buffer_size(int s,int optname,const char * optname_str,int bufsize)56 netlink_socket_set_buffer_size(int s, int optname, const char *optname_str, int bufsize)
57 {
58 socklen_t size = sizeof(int);
59 int got = 0;
60
61 if (bufsize > 0 && setsockopt(s, SOL_SOCKET, optname, &bufsize, sizeof(bufsize)) < 0) {
62 log_warn("netlink", "unable to set %s to '%d'", optname_str, bufsize);
63 return -1;
64 }
65
66 /* Now read them back from kernel.
67 * SO_SNDBUF & SO_RCVBUF are cap-ed at sysctl `net.core.rmem_max` &
68 * `net.core.wmem_max`. This it the easiest [probably sanest too]
69 * to validate that our socket buffers were set properly.
70 */
71 if (getsockopt(s, SOL_SOCKET, optname, &got, &size) < 0) {
72 log_warn("netlink", "unable to get %s", optname_str);
73 return -1;
74 }
75 if (bufsize > 0 && got < bufsize) {
76 log_warnx("netlink", "tried to set %s to '%d' "
77 "but got '%d'", optname_str, bufsize, got);
78 return -2;
79 }
80
81 return got;
82 }
83
84 /**
85 * Connect to netlink.
86 *
87 * Open a Netlink socket and connect to it.
88 *
89 * @param protocol Which protocol to use (eg NETLINK_ROUTE).
90 * @param groups Which groups we want to subscribe to
91 * @return 0 on success, -1 otherwise
92 */
93 static int
netlink_connect(struct lldpd * cfg,int protocol,unsigned groups)94 netlink_connect(struct lldpd *cfg, int protocol, unsigned groups)
95 {
96 int s;
97 struct sockaddr_nl local = {
98 .nl_family = AF_NETLINK,
99 .nl_pid = 0,
100 .nl_groups = groups
101 };
102
103 /* Open Netlink socket */
104 log_debug("netlink", "opening netlink socket");
105 s = socket(AF_NETLINK, SOCK_RAW, protocol);
106 if (s == -1) {
107 log_warn("netlink", "unable to open netlink socket");
108 return -1;
109 }
110 if (NETLINK_SEND_BUFSIZE &&
111 netlink_socket_set_buffer_size(s,
112 SO_SNDBUF, "SO_SNDBUF", NETLINK_SEND_BUFSIZE) == -1)
113 return -1;
114
115 int rc = netlink_socket_set_buffer_size(s,
116 SO_RCVBUF, "SO_RCVBUF", NETLINK_RECEIVE_BUFSIZE);
117 switch (rc) {
118 case -1: return -1;
119 case -2: cfg->g_netlink->nl_socket_recv_size = 0; break;
120 default: cfg->g_netlink->nl_socket_recv_size = rc; break;
121 }
122 if (groups && bind(s, (struct sockaddr *)&local, sizeof(struct sockaddr_nl)) < 0) {
123 log_warn("netlink", "unable to bind netlink socket");
124 close(s);
125 return -1;
126 }
127 cfg->g_netlink->nl_socket = s;
128 return 0;
129 }
130
131 /**
132 * Send a netlink message.
133 *
134 * The type of the message can be chosen as well the route family. The
135 * mesage will always be NLM_F_REQUEST | NLM_F_DUMP.
136 *
137 * @param s the netlink socket
138 * @param type the request type (eg RTM_GETLINK)
139 * @param family the rt family (eg AF_PACKET)
140 * @return 0 on success, -1 otherwise
141 */
142 static int
netlink_send(int s,int type,int family,int seq)143 netlink_send(int s, int type, int family, int seq)
144 {
145 struct netlink_req req = {
146 .hdr = {
147 .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
148 .nlmsg_type = type,
149 .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
150 .nlmsg_seq = seq,
151 .nlmsg_pid = getpid() },
152 .ifm = { .ifi_family = family }
153 };
154 struct iovec iov = {
155 .iov_base = &req,
156 .iov_len = req.hdr.nlmsg_len
157 };
158 struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
159 struct msghdr rtnl_msg = {
160 .msg_iov = &iov,
161 .msg_iovlen = 1,
162 .msg_name = &peer,
163 .msg_namelen = sizeof(struct sockaddr_nl)
164 };
165
166 if (family == AF_BRIDGE) {
167 unsigned int len = RTA_LENGTH(sizeof(__u32));
168 /* request bridge vlan attributes */
169 req.ext_req.rta_type = IFLA_EXT_MASK;
170 req.ext_req.rta_len = len;
171 req.ext_filter_mask = RTEXT_FILTER_BRVLAN;
172 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_ALIGN(len);
173 iov.iov_len = req.hdr.nlmsg_len;
174 }
175
176 /* Send netlink message. This is synchronous but we are guaranteed
177 * to not block. */
178 log_debug("netlink", "sending netlink message");
179 if (sendmsg(s, (struct msghdr *)&rtnl_msg, 0) == -1) {
180 log_warn("netlink", "unable to send netlink message");
181 return -1;
182 }
183
184 return 0;
185 }
186
187 static void
netlink_parse_rtattr(struct rtattr * tb[],int max,struct rtattr * rta,int len)188 netlink_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
189 {
190 while (RTA_OK(rta, len)) {
191 if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
192 tb[rta->rta_type] = rta;
193 rta = RTA_NEXT(rta,len);
194 }
195 }
196
197 /**
198 * Parse a `linkinfo` attributes.
199 *
200 * @param iff where to put the result
201 * @param rta linkinfo attribute
202 * @param len length of attributes
203 */
204 static void
netlink_parse_linkinfo(struct interfaces_device * iff,struct rtattr * rta,int len)205 netlink_parse_linkinfo(struct interfaces_device *iff, struct rtattr *rta, int len)
206 {
207 struct rtattr *link_info_attrs[IFLA_INFO_MAX+1] = {};
208 char *kind = NULL;
209 uint16_t vlan_id;
210
211 netlink_parse_rtattr(link_info_attrs, IFLA_INFO_MAX, rta, len);
212
213 if (link_info_attrs[IFLA_INFO_KIND]) {
214 kind = strdup(RTA_DATA(link_info_attrs[IFLA_INFO_KIND]));
215 if (kind) {
216 if (!strcmp(kind, "vlan")) {
217 log_debug("netlink", "interface %s is a VLAN",
218 iff->name);
219 iff->type |= IFACE_VLAN_T;
220 } else if (!strcmp(kind, "bridge")) {
221 log_debug("netlink", "interface %s is a bridge",
222 iff->name);
223 iff->type |= IFACE_BRIDGE_T;
224 } else if (!strcmp(kind, "bond")) {
225 log_debug("netlink", "interface %s is a bond",
226 iff->name);
227 iff->type |= IFACE_BOND_T;
228 } else if (!strcmp(kind, "team")) {
229 log_debug("netlink", "interface %s is a team",
230 iff->name);
231 iff->type |= IFACE_BOND_T;
232 }
233 }
234 }
235
236 if (kind && !strcmp(kind, "vlan") && link_info_attrs[IFLA_INFO_DATA]) {
237 struct rtattr *vlan_link_info_data_attrs[IFLA_VLAN_MAX+1] = {};
238 netlink_parse_rtattr(vlan_link_info_data_attrs, IFLA_VLAN_MAX,
239 RTA_DATA(link_info_attrs[IFLA_INFO_DATA]),
240 RTA_PAYLOAD(link_info_attrs[IFLA_INFO_DATA]));
241
242 if (vlan_link_info_data_attrs[IFLA_VLAN_ID]) {
243 vlan_id = *(uint16_t *)RTA_DATA(vlan_link_info_data_attrs[IFLA_VLAN_ID]);
244 bitmap_set(iff->vlan_bmap, vlan_id);
245 log_debug("netlink", "VLAN ID for interface %s is %d",
246 iff->name, vlan_id);
247 }
248 }
249
250 if (kind && !strcmp(kind, "bridge") && link_info_attrs[IFLA_INFO_DATA]) {
251 struct rtattr *bridge_link_info_data_attrs[IFLA_BR_MAX+1] = {};
252 netlink_parse_rtattr(bridge_link_info_data_attrs, IFLA_BR_MAX,
253 RTA_DATA(link_info_attrs[IFLA_INFO_DATA]),
254 RTA_PAYLOAD(link_info_attrs[IFLA_INFO_DATA]));
255
256 if (bridge_link_info_data_attrs[IFLA_BR_VLAN_FILTERING] &&
257 *(uint8_t *)RTA_DATA(bridge_link_info_data_attrs[IFLA_BR_VLAN_FILTERING]) > 0) {
258 iff->type |= IFACE_BRIDGE_VLAN_T;
259 }
260 }
261
262 free(kind);
263 }
264
265 /**
266 * Parse a `afspec` attributes.
267 *
268 * @param iff where to put the result
269 * @param rta afspec attribute
270 * @param len length of attributes
271 */
272 static void
netlink_parse_afspec(struct interfaces_device * iff,struct rtattr * rta,int len)273 netlink_parse_afspec(struct interfaces_device *iff, struct rtattr *rta, int len)
274 {
275 while (RTA_OK(rta, len)) {
276 struct bridge_vlan_info *vinfo;
277 switch (rta->rta_type) {
278 case IFLA_BRIDGE_VLAN_INFO:
279 vinfo = RTA_DATA(rta);
280 log_debug("netlink", "found VLAN %d on interface %s",
281 vinfo->vid, iff->name ? iff->name : "(unknown)");
282
283 bitmap_set(iff->vlan_bmap, vinfo->vid);
284 if (vinfo->flags & (BRIDGE_VLAN_INFO_PVID | BRIDGE_VLAN_INFO_UNTAGGED))
285 iff->pvid = vinfo->vid;
286 break;
287 default:
288 log_debug("netlink", "unknown afspec attribute type %d for iface %s",
289 rta->rta_type, iff->name ? iff->name : "(unknown)");
290 break;
291 }
292 rta = RTA_NEXT(rta, len);
293 }
294 /* All enbridged interfaces will have VLAN 1 by default, ignore it */
295 if (iff->vlan_bmap[0] == 2 && (bitmap_numbits(iff->vlan_bmap) == 1)
296 && iff->pvid == 1) {
297 log_debug("netlink", "found only default VLAN 1 on interface %s, removing",
298 iff->name ? iff->name : "(unknown)");
299 iff->vlan_bmap[0] = iff->pvid = 0;
300 }
301 }
302
303 /**
304 * Parse a `link` netlink message.
305 *
306 * @param msg message to be parsed
307 * @param iff where to put the result
308 * return 0 if the interface is worth it, -1 otherwise
309 */
310 static int
netlink_parse_link(struct nlmsghdr * msg,struct interfaces_device * iff)311 netlink_parse_link(struct nlmsghdr *msg,
312 struct interfaces_device *iff)
313 {
314 struct ifinfomsg *ifi;
315 struct rtattr *attribute;
316 int len;
317 ifi = NLMSG_DATA(msg);
318 len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
319
320 if (ifi->ifi_type != ARPHRD_ETHER) {
321 log_debug("netlink", "skip non Ethernet interface at index %d",
322 ifi->ifi_index);
323 return -1;
324 }
325
326 iff->index = ifi->ifi_index;
327 iff->flags = ifi->ifi_flags;
328 iff->lower_idx = -1;
329 iff->upper_idx = -1;
330
331 for (attribute = IFLA_RTA(ifi);
332 RTA_OK(attribute, len);
333 attribute = RTA_NEXT(attribute, len)) {
334 switch(attribute->rta_type) {
335 case IFLA_IFNAME:
336 /* Interface name */
337 iff->name = strdup(RTA_DATA(attribute));
338 break;
339 case IFLA_IFALIAS:
340 /* Interface alias */
341 iff->alias = strdup(RTA_DATA(attribute));
342 break;
343 case IFLA_ADDRESS:
344 /* Interface MAC address */
345 iff->address = malloc(RTA_PAYLOAD(attribute));
346 if (iff->address)
347 memcpy(iff->address, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
348 break;
349 case IFLA_LINK:
350 /* Index of "lower" interface */
351 if (iff->lower_idx == -1) {
352 iff->lower_idx = *(int*)RTA_DATA(attribute);
353 log_debug("netlink", "attribute IFLA_LINK for %s: %d",
354 iff->name ? iff->name : "(unknown)", iff->lower_idx);
355 } else {
356 log_debug("netlink", "attribute IFLA_LINK for %s: %d (ignored)",
357 iff->name ? iff->name : "(unknown)", iff->lower_idx);
358 }
359 break;
360 case IFLA_LINK_NETNSID:
361 /* Is the lower interface into another namesapce? */
362 iff->lower_idx = -2;
363 log_debug("netlink", "attribute IFLA_LINK_NETNSID received for %s",
364 iff->name ? iff->name : "(unknown)");
365 break;
366 case IFLA_MASTER:
367 /* Index of master interface */
368 iff->upper_idx = *(int*)RTA_DATA(attribute);
369 break;
370 case IFLA_MTU:
371 /* Maximum Transmission Unit */
372 iff->mtu = *(int*)RTA_DATA(attribute);
373 break;
374 case IFLA_LINKINFO:
375 netlink_parse_linkinfo(iff, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
376 break;
377 case IFLA_AF_SPEC:
378 if (ifi->ifi_family != AF_BRIDGE) break;
379 netlink_parse_afspec(iff, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
380 break;
381 default:
382 log_debug("netlink", "unhandled link attribute type %d for iface %s",
383 attribute->rta_type, iff->name ? iff->name : "(unknown)");
384 break;
385 }
386 }
387 if (!iff->name || !iff->address) {
388 log_debug("netlink", "interface %d does not have a name or an address, skip",
389 iff->index);
390 return -1;
391 }
392 if (iff->upper_idx == -1) {
393 /* No upper interface, we cannot be enslaved. We need to clear
394 * the flag because the appropriate information may come later
395 * and we don't want to miss it. */
396 iff->flags &= ~IFF_SLAVE;
397 }
398 if (iff->lower_idx == -2)
399 iff->lower_idx = -1;
400
401 if (ifi->ifi_family == AF_BRIDGE && msg->nlmsg_type == RTM_DELLINK && iff->upper_idx != -1) {
402 log_debug("netlink", "removal of %s from bridge %d",
403 iff->name, iff->upper_idx);
404 msg->nlmsg_type = RTM_NEWLINK;
405 iff->upper_idx = -1;
406 }
407
408 log_debug("netlink", "parsed link %d (%s, flags: %d)",
409 iff->index, iff->name, iff->flags);
410 return 0;
411 }
412
413 /**
414 * Parse a `address` netlink message.
415 *
416 * @param msg message to be parsed
417 * @param ifa where to put the result
418 * return 0 if the address is worth it, -1 otherwise
419 */
420 static int
netlink_parse_address(struct nlmsghdr * msg,struct interfaces_address * ifa)421 netlink_parse_address(struct nlmsghdr *msg,
422 struct interfaces_address *ifa)
423 {
424 struct ifaddrmsg *ifi;
425 struct rtattr *attribute;
426 int len;
427 ifi = NLMSG_DATA(msg);
428 len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
429
430 ifa->index = ifi->ifa_index;
431 ifa->flags = ifi->ifa_flags;
432 switch (ifi->ifa_family) {
433 case AF_INET:
434 case AF_INET6: break;
435 default:
436 log_debug("netlink", "got a non IP address on if %d (family: %d)",
437 ifa->index, ifi->ifa_family);
438 return -1;
439 }
440
441 for (attribute = IFA_RTA(ifi);
442 RTA_OK(attribute, len);
443 attribute = RTA_NEXT(attribute, len)) {
444 switch(attribute->rta_type) {
445 case IFA_ADDRESS:
446 /* Address */
447 if (ifi->ifa_family == AF_INET) {
448 struct sockaddr_in ip;
449 memset(&ip, 0, sizeof(struct sockaddr_in));
450 ip.sin_family = AF_INET;
451 memcpy(&ip.sin_addr, RTA_DATA(attribute),
452 sizeof(struct in_addr));
453 memcpy(&ifa->address, &ip, sizeof(struct sockaddr_in));
454 } else {
455 struct sockaddr_in6 ip6;
456 memset(&ip6, 0, sizeof(struct sockaddr_in6));
457 ip6.sin6_family = AF_INET6;
458 memcpy(&ip6.sin6_addr, RTA_DATA(attribute),
459 sizeof(struct in6_addr));
460 memcpy(&ifa->address, &ip6, sizeof(struct sockaddr_in6));
461 }
462 break;
463 default:
464 log_debug("netlink", "unhandled address attribute type %d for iface %d",
465 attribute->rta_type, ifa->index);
466 break;
467 }
468 }
469 if (ifa->address.ss_family == AF_UNSPEC) {
470 log_debug("netlink", "no IP for interface %d",
471 ifa->index);
472 return -1;
473 }
474 return 0;
475 }
476
477 /**
478 * Merge an old interface with a new one.
479 *
480 * Some properties may be absent in the new interface that should be copied over
481 * from the old one.
482 */
483 void
netlink_merge(struct interfaces_device * old,struct interfaces_device * new)484 netlink_merge(struct interfaces_device *old, struct interfaces_device *new)
485 {
486 if (new->alias == NULL) {
487 new->alias = old->alias;
488 old->alias = NULL;
489 }
490 if (new->address == NULL) {
491 new->address = old->address;
492 old->address = NULL;
493 }
494 if (new->mtu == 0)
495 new->mtu = old->mtu;
496 if (new->type == 0)
497 new->type = old->type;
498
499 if (bitmap_isempty(new->vlan_bmap) && new->type == IFACE_VLAN_T)
500 memcpy((void *)new->vlan_bmap, (void *)old->vlan_bmap,
501 sizeof(uint32_t) * VLAN_BITMAP_LEN);
502
503 /* It's not possible for lower link to change */
504 new->lower_idx = old->lower_idx;
505 }
506
507 /**
508 * Receive netlink answer from the kernel.
509 *
510 * @param ifs list to store interface list or NULL if we don't
511 * @param ifas list to store address list or NULL if we don't
512 * @return 0 on success, -1 on error
513 */
514 static int
netlink_recv(struct lldpd * cfg,struct interfaces_device_list * ifs,struct interfaces_address_list * ifas)515 netlink_recv(struct lldpd *cfg,
516 struct interfaces_device_list *ifs,
517 struct interfaces_address_list *ifas)
518 {
519 int end = 0, ret = 0, flags, retry = 0;
520 struct iovec iov;
521 int link_update = 0;
522 int s = cfg->g_netlink->nl_socket;
523
524 struct interfaces_device *ifdold;
525 struct interfaces_device *ifdnew;
526 struct interfaces_address *ifaold;
527 struct interfaces_address *ifanew;
528 char addr[INET6_ADDRSTRLEN + 1];
529
530 iov.iov_len = NETLINK_BUFFER;
531 iov.iov_base = malloc(iov.iov_len);
532 if (!iov.iov_base) {
533 log_warn("netlink", "not enough memory");
534 return -1;
535 }
536
537 while (!end) {
538 ssize_t len;
539 struct nlmsghdr *msg;
540 struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
541 struct msghdr rtnl_reply = {
542 .msg_iov = &iov,
543 .msg_iovlen = 1,
544 .msg_name = &peer,
545 .msg_namelen = sizeof(struct sockaddr_nl)
546 };
547 flags = MSG_PEEK | MSG_TRUNC;
548 retry:
549 len = recvmsg(s, &rtnl_reply, flags);
550 if (len == -1) {
551 if (errno == EAGAIN || errno == EWOULDBLOCK) {
552 if (retry++ == 0) {
553 levent_recv_error(s, "netlink socket");
554 goto retry;
555 }
556 log_warnx("netlink", "should have received something, but didn't");
557 ret = 0;
558 goto out;
559 }
560 int rsize = cfg->g_netlink->nl_socket_recv_size;
561 if (errno == ENOBUFS &&
562 rsize > 0 && rsize < NETLINK_MAX_RECEIVE_BUFSIZE) {
563 /* Try to increase buffer size */
564 rsize *= 2;
565 if (rsize > NETLINK_MAX_RECEIVE_BUFSIZE) {
566 rsize = NETLINK_MAX_RECEIVE_BUFSIZE;
567 }
568 int rc = netlink_socket_set_buffer_size(s,
569 SO_RCVBUF, "SO_RCVBUF",
570 rsize);
571 if (rc < 0)
572 cfg->g_netlink->nl_socket_recv_size = 0;
573 else
574 cfg->g_netlink->nl_socket_recv_size = rsize;
575 if (rc > 0 || rc == -2) {
576 log_info("netlink",
577 "netlink receive buffer too small, retry with larger one (%d)",
578 rsize);
579 flags = 0;
580 goto retry;
581 }
582 }
583 log_warn("netlink", "unable to receive netlink answer");
584 ret = -1;
585 goto out;
586 }
587 if (!len) {
588 ret = 0;
589 goto out;
590 }
591
592 if (iov.iov_len < len || (rtnl_reply.msg_flags & MSG_TRUNC)) {
593 void *tmp;
594
595 /* Provided buffer is not large enough, enlarge it
596 * to size of len (which should be total length of the message)
597 * and try again. */
598 iov.iov_len = len;
599 tmp = realloc(iov.iov_base, iov.iov_len);
600 if (!tmp) {
601 log_warn("netlink", "not enough memory");
602 ret = -1;
603 goto out;
604 }
605 log_debug("netlink", "enlarge message size to %zu bytes", len);
606 iov.iov_base = tmp;
607 flags = 0;
608 goto retry;
609 }
610
611 if (flags != 0) {
612 /* Buffer is big enough, do the actual reading */
613 flags = 0;
614 goto retry;
615 }
616
617 for (msg = (struct nlmsghdr*)(void*)(iov.iov_base);
618 NLMSG_OK(msg, len);
619 msg = NLMSG_NEXT(msg, len)) {
620 if (!(msg->nlmsg_flags & NLM_F_MULTI))
621 end = 1;
622 switch (msg->nlmsg_type) {
623 case NLMSG_DONE:
624 log_debug("netlink", "received done message");
625 end = 1;
626 break;
627 case RTM_NEWLINK:
628 case RTM_DELLINK:
629 if (!ifs) break;
630 log_debug("netlink", "received link information");
631 ifdnew = calloc(1, sizeof(struct interfaces_device));
632 if (ifdnew == NULL) {
633 log_warn("netlink", "not enough memory for another interface, give up what we have");
634 goto end;
635 }
636 if (netlink_parse_link(msg, ifdnew) == 0) {
637 /* We need to find if we already have this interface */
638 TAILQ_FOREACH(ifdold, ifs, next) {
639 if (ifdold->index == ifdnew->index) break;
640 }
641
642 if (msg->nlmsg_type == RTM_NEWLINK) {
643 if (ifdold == NULL) {
644 log_debug("netlink", "interface %s is new",
645 ifdnew->name);
646 TAILQ_INSERT_TAIL(ifs, ifdnew, next);
647 } else {
648 log_debug("netlink", "interface %s/%s is updated",
649 ifdold->name, ifdnew->name);
650 netlink_merge(ifdold, ifdnew);
651 TAILQ_INSERT_AFTER(ifs, ifdold, ifdnew, next);
652 TAILQ_REMOVE(ifs, ifdold, next);
653 interfaces_free_device(ifdold);
654 }
655 } else {
656 if (ifdold == NULL) {
657 log_warnx("netlink",
658 "removal request for %s, but no knowledge of it",
659 ifdnew->name);
660 } else {
661 log_debug("netlink", "interface %s is to be removed",
662 ifdold->name);
663 TAILQ_REMOVE(ifs, ifdold, next);
664 interfaces_free_device(ifdold);
665 }
666 interfaces_free_device(ifdnew);
667 }
668 link_update = 1;
669 } else {
670 interfaces_free_device(ifdnew);
671 }
672 break;
673 case RTM_NEWADDR:
674 case RTM_DELADDR:
675 if (!ifas) break;
676 log_debug("netlink", "received address information");
677 ifanew = calloc(1, sizeof(struct interfaces_address));
678 if (ifanew == NULL) {
679 log_warn("netlink", "not enough memory for another address, give what we have");
680 goto end;
681 }
682 if (netlink_parse_address(msg, ifanew) == 0) {
683 TAILQ_FOREACH(ifaold, ifas, next) {
684 if ((ifaold->index == ifanew->index) &&
685 !memcmp(&ifaold->address, &ifanew->address,
686 sizeof(ifaold->address))) break;
687 }
688 if (getnameinfo((struct sockaddr *)&ifanew->address,
689 sizeof(ifanew->address),
690 addr, sizeof(addr),
691 NULL, 0, NI_NUMERICHOST) != 0) {
692 strlcpy(addr, "(unknown)", sizeof(addr));
693 }
694
695 if (msg->nlmsg_type == RTM_NEWADDR) {
696 if (ifaold == NULL) {
697 log_debug("netlink", "new address %s%%%d",
698 addr, ifanew->index);
699 TAILQ_INSERT_TAIL(ifas, ifanew, next);
700 } else {
701 log_debug("netlink", "updated address %s%%%d",
702 addr, ifaold->index);
703 TAILQ_INSERT_AFTER(ifas, ifaold, ifanew, next);
704 TAILQ_REMOVE(ifas, ifaold, next);
705 interfaces_free_address(ifaold);
706 }
707 } else {
708 if (ifaold == NULL) {
709 log_info("netlink",
710 "removal request for address of %s%%%d, but no knowledge of it",
711 addr, ifanew->index);
712 } else {
713 log_debug("netlink", "address %s%%%d is to be removed",
714 addr, ifaold->index);
715 TAILQ_REMOVE(ifas, ifaold, next);
716 interfaces_free_address(ifaold);
717 }
718 interfaces_free_address(ifanew);
719 }
720 } else {
721 interfaces_free_address(ifanew);
722 }
723 break;
724 default:
725 log_debug("netlink",
726 "received unhandled message type %d (len: %d)",
727 msg->nlmsg_type, msg->nlmsg_len);
728 }
729 }
730 }
731 end:
732 if (link_update) {
733 /* Fill out lower/upper */
734 struct interfaces_device *iface1, *iface2;
735 TAILQ_FOREACH(iface1, ifs, next) {
736 if (iface1->upper_idx != -1 && iface1->upper_idx != iface1->index) {
737 TAILQ_FOREACH(iface2, ifs, next) {
738 if (iface1->upper_idx == iface2->index) {
739 log_debug("netlink",
740 "upper interface for %s is %s",
741 iface1->name, iface2->name);
742 iface1->upper = iface2;
743 break;
744 }
745 }
746 if (iface2 == NULL)
747 iface1->upper = NULL;
748 } else {
749 iface1->upper = NULL;
750 }
751 if (iface1->lower_idx != -1 && iface1->lower_idx != iface1->index) {
752 TAILQ_FOREACH(iface2, ifs, next) {
753 if (iface1->lower_idx == iface2->index) {
754 /* Workaround a bug introduced
755 * in Linux 4.1: a pair of veth
756 * will be lower interface of
757 * each other. Do not modify
758 * index as if one of them is
759 * updated, we will loose the
760 * information about the
761 * loop. */
762 if (iface2->lower_idx == iface1->index) {
763 iface1->lower = NULL;
764 log_debug("netlink",
765 "link loop detected between %s(%d) and %s(%d)",
766 iface1->name,
767 iface1->index,
768 iface2->name,
769 iface2->index);
770 } else {
771 log_debug("netlink",
772 "lower interface for %s is %s",
773 iface1->name, iface2->name);
774 iface1->lower = iface2;
775 }
776 break;
777 }
778 if (iface2 == NULL)
779 iface1->lower = NULL;
780 }
781 } else {
782 iface1->lower = NULL;
783 }
784 }
785 }
786
787 out:
788 free(iov.iov_base);
789 return ret;
790 }
791
792 static int
netlink_group_mask(int group)793 netlink_group_mask(int group)
794 {
795 return group ? (1 << (group - 1)) : 0;
796 }
797
798 /**
799 * Subscribe to link changes.
800 *
801 * @return 0 on success, -1 otherwise
802 */
803 static int
netlink_subscribe_changes(struct lldpd * cfg)804 netlink_subscribe_changes(struct lldpd *cfg)
805 {
806 unsigned int groups;
807
808 log_debug("netlink", "listening on interface changes");
809
810 groups = netlink_group_mask(RTNLGRP_LINK) |
811 netlink_group_mask(RTNLGRP_IPV4_IFADDR) |
812 netlink_group_mask(RTNLGRP_IPV6_IFADDR);
813
814 return netlink_connect(cfg, NETLINK_ROUTE, groups);
815 }
816
817 /**
818 * Receive changes from netlink */
819 static void
netlink_change_cb(struct lldpd * cfg)820 netlink_change_cb(struct lldpd *cfg)
821 {
822 if (cfg->g_netlink == NULL)
823 return;
824 netlink_recv(cfg,
825 cfg->g_netlink->devices,
826 cfg->g_netlink->addresses);
827 }
828
829 /**
830 * Initialize netlink subsystem.
831 *
832 * This can be called several times but will have effect only the first time.
833 *
834 * @return 0 on success, -1 otherwise
835 */
836 static int
netlink_initialize(struct lldpd * cfg)837 netlink_initialize(struct lldpd *cfg)
838 {
839 #ifdef ENABLE_DOT1
840 struct interfaces_device *iff;
841 #endif
842
843 if (cfg->g_netlink) return 0;
844
845 log_debug("netlink", "initialize netlink subsystem");
846 if ((cfg->g_netlink = calloc(sizeof(struct lldpd_netlink), 1)) == NULL) {
847 log_warn("netlink", "unable to allocate memory for netlink subsystem");
848 goto end;
849 }
850
851 /* Connect to netlink (by requesting to get notified on updates) and
852 * request updated information right now */
853 if (netlink_subscribe_changes(cfg) == -1)
854 goto end;
855
856 struct interfaces_address_list *ifaddrs = cfg->g_netlink->addresses =
857 malloc(sizeof(struct interfaces_address_list));
858 if (ifaddrs == NULL) {
859 log_warn("netlink", "not enough memory for address list");
860 goto end;
861 }
862 TAILQ_INIT(ifaddrs);
863
864 struct interfaces_device_list *ifs = cfg->g_netlink->devices =
865 malloc(sizeof(struct interfaces_device_list));
866 if (ifs == NULL) {
867 log_warn("netlink", "not enough memory for interface list");
868 goto end;
869 }
870 TAILQ_INIT(ifs);
871
872 if (netlink_send(cfg->g_netlink->nl_socket, RTM_GETADDR, AF_UNSPEC, 1) == -1)
873 goto end;
874 netlink_recv(cfg, NULL, ifaddrs);
875 if (netlink_send(cfg->g_netlink->nl_socket, RTM_GETLINK, AF_PACKET, 2) == -1)
876 goto end;
877 netlink_recv(cfg, ifs, NULL);
878 #ifdef ENABLE_DOT1
879 /* If we have a bridge, search for VLAN-aware bridges */
880 TAILQ_FOREACH(iff, ifs, next) {
881 if (iff->type & IFACE_BRIDGE_T) {
882 log_debug("netlink", "interface %s is a bridge, check for VLANs", iff->name);
883 if (netlink_send(cfg->g_netlink->nl_socket, RTM_GETLINK, AF_BRIDGE, 3) == -1)
884 goto end;
885 netlink_recv(cfg, ifs, NULL);
886 break;
887 }
888 }
889 #endif
890
891 /* Listen to any future change */
892 cfg->g_iface_cb = netlink_change_cb;
893 if (levent_iface_subscribe(cfg, cfg->g_netlink->nl_socket) == -1) {
894 goto end;
895 }
896
897 return 0;
898 end:
899 netlink_cleanup(cfg);
900 return -1;
901 }
902
903 /**
904 * Cleanup netlink subsystem.
905 */
906 void
netlink_cleanup(struct lldpd * cfg)907 netlink_cleanup(struct lldpd *cfg)
908 {
909 if (cfg->g_netlink == NULL) return;
910 if (cfg->g_netlink->nl_socket != -1)
911 close(cfg->g_netlink->nl_socket);
912 interfaces_free_devices(cfg->g_netlink->devices);
913 interfaces_free_addresses(cfg->g_netlink->addresses);
914
915 free(cfg->g_netlink);
916 cfg->g_netlink = NULL;
917 }
918
919 /**
920 * Receive the list of interfaces.
921 *
922 * @return a list of interfaces.
923 */
924 struct interfaces_device_list*
netlink_get_interfaces(struct lldpd * cfg)925 netlink_get_interfaces(struct lldpd *cfg)
926 {
927 if (netlink_initialize(cfg) == -1) return NULL;
928 struct interfaces_device *ifd;
929 TAILQ_FOREACH(ifd, cfg->g_netlink->devices, next) {
930 ifd->ignore = 0;
931 }
932 return cfg->g_netlink->devices;
933 }
934
935 /**
936 * Receive the list of addresses.
937 *
938 * @return a list of addresses.
939 */
940 struct interfaces_address_list*
netlink_get_addresses(struct lldpd * cfg)941 netlink_get_addresses(struct lldpd *cfg)
942 {
943 if (netlink_initialize(cfg) == -1) return NULL;
944 return cfg->g_netlink->addresses;
945 }
946