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