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