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