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