]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/netlink.c
Merge pull request #218 from vincentbernat/feature/netlink-autoadapt
[thirdparty/lldpd.git] / src / daemon / netlink.c
CommitLineData
e12c2365
VB
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
adbb6e54
VB
18/* Grabbing interfaces information with netlink only. */
19
e12c2365
VB
20#include "lldpd.h"
21
0fa2254b 22#include <errno.h>
e12c2365 23#include <sys/socket.h>
0fa2254b 24#include <netdb.h>
13181ede 25#include <net/if_arp.h>
0fa2254b
VB
26#include <linux/netlink.h>
27#include <linux/rtnetlink.h>
28
29#define NETLINK_BUFFER 4096
02c91f0a 30
0fa2254b
VB
31struct netlink_req {
32 struct nlmsghdr hdr;
33 struct rtgenmsg gen;
34};
13181ede
VB
35
36struct lldpd_netlink {
0fa2254b 37 int nl_socket;
960541eb 38 int nl_socket_recv_size;
0fa2254b
VB
39 /* Cache */
40 struct interfaces_device_list *devices;
41 struct interfaces_address_list *addresses;
e12c2365
VB
42};
43
c9f0ee58 44
960541eb
VB
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 */
c9f0ee58 52static int
960541eb 53netlink_socket_set_buffer_size(int s, int optname, const char *optname_str, int bufsize)
c9f0ee58 54{
e8ee1d9d 55 socklen_t size = sizeof(int);
c9f0ee58
AA
56 int got = 0;
57
960541eb
VB
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);
c9f0ee58
AA
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 */
960541eb
VB
68 if (getsockopt(s, SOL_SOCKET, optname, &got, &size) < 0) {
69 log_warn("netlink", "unable to get %s", optname_str);
0cb979c7
VB
70 return -1;
71 }
960541eb
VB
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;
0cb979c7 76 }
960541eb
VB
77
78 return got;
0cb979c7
VB
79}
80
e12c2365 81/**
0fa2254b
VB
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
960541eb 88 * @return 0 on success, -1 otherwise
e12c2365 89 */
0fa2254b 90static int
960541eb 91netlink_connect(struct lldpd *cfg, int protocol, unsigned groups)
e12c2365 92{
0fa2254b
VB
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;
13181ede 106 }
960541eb
VB
107 if (NETLINK_SEND_BUFSIZE &&
108 netlink_socket_set_buffer_size(s,
109 SO_SNDBUF, "SO_SNDBUF", NETLINK_SEND_BUFSIZE) == -1)
c9f0ee58 110 return -1;
960541eb
VB
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 }
0fa2254b
VB
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 }
960541eb
VB
124 cfg->g_netlink->nl_socket = s;
125 return 0;
e12c2365
VB
126}
127
128/**
0fa2254b 129 * Send a netlink message.
e12c2365 130 *
0fa2254b
VB
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.
e12c2365 133 *
0fa2254b
VB
134 * @param s the netlink socket
135 * @param type the request type (eg RTM_GETLINK)
136 * @param family the rt family (eg AF_PACKET)
e12c2365
VB
137 * @return 0 on success, -1 otherwise
138 */
139static int
0fa2254b 140netlink_send(int s, int type, int family, int seq)
e12c2365 141{
0fa2254b
VB
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;
16eacc5b
VB
169 }
170
0fa2254b
VB
171 return 0;
172}
16eacc5b 173
0fa2254b
VB
174static void
175netlink_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);
16eacc5b 181 }
16eacc5b
VB
182}
183
e12c2365 184/**
0fa2254b
VB
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
e12c2365 190 */
0fa2254b
VB
191static void
192netlink_parse_linkinfo(struct interfaces_device *iff, struct rtattr *rta, int len)
e12c2365 193{
0fa2254b
VB
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 }
13181ede 217
0fa2254b
VB
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);
e12c2365
VB
232}
233
234/**
13181ede 235 * Parse a `link` netlink message.
e12c2365 236 *
0fa2254b
VB
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
e12c2365 240 */
0fa2254b
VB
241static int
242netlink_parse_link(struct nlmsghdr *msg,
243 struct interfaces_device *iff)
e12c2365 244{
0fa2254b
VB
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;
13181ede
VB
255 }
256
0fa2254b
VB
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);
d2e6f750
VB
283 log_debug("netlink", "attribute IFLA_LINK for %s: %d",
284 iff->name ? iff->name : "(unknown)", iff->lower_idx);
0fa2254b 285 break;
c04fafa7
VB
286 case IFLA_LINK_NETNSID:
287 /* Is the lower interface into another namesapce? */
288 iff->lower_idx = -1;
d2e6f750
VB
289 log_debug("netlink", "attribute IFLA_LINK_NETNSID received for %s",
290 iff->name ? iff->name : "(unknown)");
c04fafa7 291 break;
0fa2254b
VB
292 case IFLA_MASTER:
293 /* Index of master interface */
294 iff->upper_idx = *(int*)RTA_DATA(attribute);
295 break;
0fa2254b
VB
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 }
13181ede 308 }
0fa2254b
VB
309 if (!iff->name || !iff->address) {
310 log_info("netlink", "interface %d does not have a name or an address, skip",
13181ede 311 iff->index);
0fa2254b 312 return -1;
13181ede
VB
313 }
314
0fa2254b
VB
315 log_debug("netlink", "parsed link %d (%s, flags: %d)",
316 iff->index, iff->name, iff->flags);
317 return 0;
e12c2365
VB
318}
319
320/**
13181ede 321 * Parse a `address` netlink message.
e12c2365 322 *
0fa2254b
VB
323 * @param msg message to be parsed
324 * @param ifa where to put the result
325 * return 0 if the address is worth it, -1 otherwise
e12c2365 326 */
0fa2254b
VB
327static int
328netlink_parse_address(struct nlmsghdr *msg,
329 struct interfaces_address *ifa)
e12c2365 330{
0fa2254b
VB
331 struct ifaddrmsg *ifi;
332 struct rtattr *attribute;
333 int len;
334 ifi = NLMSG_DATA(msg);
335 len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
336
337 ifa->index = ifi->ifa_index;
338 ifa->flags = ifi->ifa_flags;
339 switch (ifi->ifa_family) {
13181ede
VB
340 case AF_INET:
341 case AF_INET6: break;
342 default:
343 log_debug("netlink", "got a non IP address on if %d (family: %d)",
0fa2254b
VB
344 ifa->index, ifi->ifa_family);
345 return -1;
13181ede
VB
346 }
347
0fa2254b
VB
348 for (attribute = IFA_RTA(ifi);
349 RTA_OK(attribute, len);
350 attribute = RTA_NEXT(attribute, len)) {
351 switch(attribute->rta_type) {
352 case IFA_ADDRESS:
353 /* Address */
354 if (ifi->ifa_family == AF_INET) {
355 struct sockaddr_in ip;
356 memset(&ip, 0, sizeof(struct sockaddr_in));
357 ip.sin_family = AF_INET;
358 memcpy(&ip.sin_addr, RTA_DATA(attribute),
359 sizeof(struct in_addr));
360 memcpy(&ifa->address, &ip, sizeof(struct sockaddr_in));
361 } else {
362 struct sockaddr_in6 ip6;
363 memset(&ip6, 0, sizeof(struct sockaddr_in6));
364 ip6.sin6_family = AF_INET6;
365 memcpy(&ip6.sin6_addr, RTA_DATA(attribute),
366 sizeof(struct in6_addr));
367 memcpy(&ifa->address, &ip6, sizeof(struct sockaddr_in6));
368 }
369 break;
370 default:
371 log_debug("netlink", "unhandled address attribute type %d for iface %d",
372 attribute->rta_type, ifa->index);
373 break;
374 }
13181ede 375 }
0fa2254b 376 if (ifa->address.ss_family == AF_UNSPEC) {
13181ede
VB
377 log_debug("netlink", "no IP for interface %d",
378 ifa->index);
0fa2254b 379 return -1;
13181ede 380 }
0fa2254b 381 return 0;
e12c2365
VB
382}
383
58e30b5a
VB
384/**
385 * Merge an old interface with a new one.
386 *
387 * Some properties may be absent in the new interface that should be copied over
388 * from the old one.
389 */
390void
391netlink_merge(struct interfaces_device *old, struct interfaces_device *new)
392{
393 if (new->alias == NULL) {
394 new->alias = old->alias;
395 old->alias = NULL;
396 }
397 if (new->address == NULL) {
398 new->address = old->address;
399 old->address = NULL;
400 }
401 if (new->mtu == 0)
402 new->mtu = old->mtu;
403 if (new->type == 0)
404 new->type = old->type;
405 if (new->vlanid == 0)
406 new->vlanid = old->vlanid;
d2e6f750
VB
407
408 /* It's not possible for lower link to change */
409 new->lower_idx = old->lower_idx;
58e30b5a
VB
410}
411
e12c2365 412/**
0fa2254b 413 * Receive netlink answer from the kernel.
e12c2365 414 *
0fa2254b
VB
415 * @param ifs list to store interface list or NULL if we don't
416 * @param ifas list to store address list or NULL if we don't
417 * @return 0 on success, -1 on error
e12c2365 418 */
0fa2254b 419static int
960541eb 420netlink_recv(struct lldpd *cfg,
0fa2254b 421 struct interfaces_device_list *ifs,
960541eb 422 struct interfaces_address_list *ifas)
e12c2365 423{
85b72fe0
DM
424 int end = 0, ret = 0;
425 int flags = MSG_PEEK | MSG_TRUNC;
426 struct iovec iov;
0fa2254b 427 int link_update = 0;
960541eb 428 int s = cfg->g_netlink->nl_socket;
0fa2254b
VB
429
430 struct interfaces_device *ifdold;
431 struct interfaces_device *ifdnew;
432 struct interfaces_address *ifaold;
433 struct interfaces_address *ifanew;
434 char addr[INET6_ADDRSTRLEN + 1];
435
85b72fe0
DM
436 iov.iov_len = NETLINK_BUFFER;
437 iov.iov_base = malloc(iov.iov_len);
438 if (!iov.iov_base) {
439 log_warn("netlink", "not enough memory");
440 return -1;
441 }
442
0fa2254b
VB
443 while (!end) {
444 ssize_t len;
445 struct nlmsghdr *msg;
0fa2254b
VB
446 struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
447 struct msghdr rtnl_reply = {
448 .msg_iov = &iov,
449 .msg_iovlen = 1,
450 .msg_name = &peer,
451 .msg_namelen = sizeof(struct sockaddr_nl)
452 };
453
85b72fe0
DM
454retry:
455 len = recvmsg(s, &rtnl_reply, flags);
0fa2254b
VB
456 if (len == -1) {
457 if (errno == EAGAIN || errno == EWOULDBLOCK) {
458 log_debug("netlink", "should have received something, but didn't");
85b72fe0
DM
459 ret = 0;
460 goto out;
0fa2254b 461 }
960541eb
VB
462 int rsize = cfg->g_netlink->nl_socket_recv_size;
463 if (errno == ENOBUFS &&
464 rsize > 0 && rsize < NETLINK_MAX_RECEIVE_BUFSIZE) {
465 /* Try to increase buffer size */
466 rsize *= 2;
467 if (rsize > NETLINK_MAX_RECEIVE_BUFSIZE) {
468 rsize = NETLINK_MAX_RECEIVE_BUFSIZE;
469 }
470 int rc = netlink_socket_set_buffer_size(s,
471 SO_RCVBUF, "SO_RCVBUF",
472 rsize);
473 if (rc < 0)
474 cfg->g_netlink->nl_socket_recv_size = 0;
475 else
476 cfg->g_netlink->nl_socket_recv_size = rsize;
477 if (rc > 0 || rc == -2) {
478 log_info("netlink",
479 "netlink receive buffer too small, retry with larger one (%d)",
480 rsize);
0cb979c7
VB
481 flags = 0;
482 goto retry;
0cb979c7
VB
483 }
484 }
644cd42d 485 log_warn("netlink", "unable to receive netlink answer");
85b72fe0
DM
486 ret = -1;
487 goto out;
0fa2254b 488 }
85b72fe0
DM
489 if (!len) {
490 ret = 0;
491 goto out;
492 }
493
494 if (iov.iov_len < len || (rtnl_reply.msg_flags & MSG_TRUNC)) {
495 void *tmp;
496
497 /* Provided buffer is not large enough, enlarge it
498 * to size of len (which should be total length of the message)
499 * and try again. */
500 iov.iov_len = len;
501 tmp = realloc(iov.iov_base, iov.iov_len);
502 if (!tmp) {
503 log_warn("netlink", "not enough memory");
504 ret = -1;
505 goto out;
506 }
507 log_debug("netlink", "enlarge message size to %zu bytes", len);
508 iov.iov_base = tmp;
509 flags = 0;
510 goto retry;
511 }
512
513 if (flags != 0) {
514 /* Buffer is big enough, do the actual reading */
515 flags = 0;
516 goto retry;
517 }
518
519 for (msg = (struct nlmsghdr*)(void*)(iov.iov_base);
0fa2254b
VB
520 NLMSG_OK(msg, len);
521 msg = NLMSG_NEXT(msg, len)) {
522 if (!(msg->nlmsg_flags & NLM_F_MULTI))
523 end = 1;
524 switch (msg->nlmsg_type) {
525 case NLMSG_DONE:
526 log_debug("netlink", "received done message");
527 end = 1;
528 break;
529 case RTM_NEWLINK:
530 case RTM_DELLINK:
531 if (!ifs) break;
532 log_debug("netlink", "received link information");
533 ifdnew = calloc(1, sizeof(struct interfaces_device));
534 if (ifdnew == NULL) {
535 log_warn("netlink", "not enough memory for another interface, give up what we have");
536 goto end;
537 }
538 if (netlink_parse_link(msg, ifdnew) == 0) {
539 /* We need to find if we already have this interface */
540 TAILQ_FOREACH(ifdold, ifs, next) {
541 if (ifdold->index == ifdnew->index) break;
542 }
543 if (msg->nlmsg_type == RTM_NEWLINK) {
544 if (ifdold == NULL) {
545 log_debug("netlink", "interface %s is new",
546 ifdnew->name);
547 TAILQ_INSERT_TAIL(ifs, ifdnew, next);
548 } else {
549 log_debug("netlink", "interface %s/%s is updated",
550 ifdold->name, ifdnew->name);
58e30b5a 551 netlink_merge(ifdold, ifdnew);
0fa2254b
VB
552 TAILQ_INSERT_AFTER(ifs, ifdold, ifdnew, next);
553 TAILQ_REMOVE(ifs, ifdold, next);
554 interfaces_free_device(ifdold);
555 }
556 } else {
557 if (ifdold == NULL) {
558 log_warnx("netlink",
559 "removal request for %s, but no knowledge of it",
560 ifdnew->name);
561 } else {
562 log_debug("netlink", "interface %s is to be removed",
563 ifdold->name);
564 TAILQ_REMOVE(ifs, ifdold, next);
565 interfaces_free_device(ifdold);
566 }
567 interfaces_free_device(ifdnew);
568 }
569 link_update = 1;
570 } else {
571 interfaces_free_device(ifdnew);
572 }
573 break;
574 case RTM_NEWADDR:
575 case RTM_DELADDR:
576 if (!ifas) break;
577 log_debug("netlink", "received address information");
578 ifanew = calloc(1, sizeof(struct interfaces_address));
579 if (ifanew == NULL) {
580 log_warn("netlink", "not enough memory for another address, give what we have");
581 goto end;
582 }
583 if (netlink_parse_address(msg, ifanew) == 0) {
584 TAILQ_FOREACH(ifaold, ifas, next) {
585 if ((ifaold->index == ifanew->index) &&
586 !memcmp(&ifaold->address, &ifanew->address,
587 sizeof(ifaold->address))) continue;
588 }
589 if (getnameinfo((struct sockaddr *)&ifanew->address,
590 sizeof(ifanew->address),
591 addr, sizeof(addr),
592 NULL, 0, NI_NUMERICHOST) != 0) {
593 strlcpy(addr, "(unknown)", sizeof(addr));
594 }
13181ede 595
0fa2254b
VB
596 if (msg->nlmsg_type == RTM_NEWADDR) {
597 if (ifaold == NULL) {
598 log_debug("netlink", "new address %s%%%d",
599 addr, ifanew->index);
600 TAILQ_INSERT_TAIL(ifas, ifanew, next);
601 } else {
602 log_debug("netlink", "updated address %s%%%d",
603 addr, ifaold->index);
604 TAILQ_INSERT_AFTER(ifas, ifaold, ifanew, next);
605 TAILQ_REMOVE(ifas, ifaold, next);
606 interfaces_free_address(ifaold);
607 }
608 } else {
609 if (ifaold == NULL) {
8027d907 610 log_info("netlink",
0fa2254b
VB
611 "removal request for address of %s%%%d, but no knowledge of it",
612 addr, ifanew->index);
613 } else {
614 log_debug("netlink", "address %s%%%d is to be removed",
615 addr, ifaold->index);
616 TAILQ_REMOVE(ifas, ifaold, next);
617 interfaces_free_address(ifaold);
618 }
619 interfaces_free_address(ifanew);
620 }
621 } else {
622 interfaces_free_address(ifanew);
623 }
624 break;
625 default:
626 log_debug("netlink",
627 "received unhandled message type %d (len: %d)",
628 msg->nlmsg_type, msg->nlmsg_len);
629 }
630 }
85b72fe0 631 flags = MSG_PEEK | MSG_TRUNC;
13181ede 632 }
0fa2254b
VB
633end:
634 if (link_update) {
635 /* Fill out lower/upper */
636 struct interfaces_device *iface1, *iface2;
637 TAILQ_FOREACH(iface1, ifs, next) {
638 if (iface1->upper_idx != -1 && iface1->upper_idx != iface1->index) {
639 TAILQ_FOREACH(iface2, ifs, next) {
640 if (iface1->upper_idx == iface2->index) {
c04fafa7
VB
641 log_debug("netlink",
642 "upper interface for %s is %s",
643 iface1->name, iface2->name);
0fa2254b
VB
644 iface1->upper = iface2;
645 break;
646 }
13181ede 647 }
100266c1
VB
648 if (iface2 == NULL)
649 iface1->upper = NULL;
0fa2254b
VB
650 } else {
651 iface1->upper = NULL;
13181ede 652 }
0fa2254b
VB
653 if (iface1->lower_idx != -1 && iface1->lower_idx != iface1->index) {
654 TAILQ_FOREACH(iface2, ifs, next) {
655 if (iface1->lower_idx == iface2->index) {
100266c1
VB
656 /* Workaround a bug introduced
657 * in Linux 4.1: a pair of veth
658 * will be lower interface of
659 * each other. Do not modify
660 * index as if one of them is
661 * updated, we will loose the
662 * information about the
663 * loop. */
0fa2254b 664 if (iface2->lower_idx == iface1->index) {
100266c1 665 iface1->lower = NULL;
c04fafa7
VB
666 log_debug("netlink",
667 "link loop detected between %s and %s",
668 iface1->name, iface2->name);
669 } else {
670 log_debug("netlink",
671 "lower interface for %s is %s",
672 iface1->name, iface2->name);
673 iface1->lower = iface2;
674 }
0fa2254b 675 break;
7d0a4975 676 }
100266c1
VB
677 if (iface2 == NULL)
678 iface1->lower = NULL;
13181ede 679 }
0fa2254b
VB
680 } else {
681 iface1->lower = NULL;
13181ede 682 }
0fa2254b 683 }
13181ede 684 }
85b72fe0
DM
685
686out:
687 free(iov.iov_base);
688 return ret;
0fa2254b 689}
13181ede 690
0fa2254b
VB
691static int
692netlink_group_mask(int group)
693{
694 return group ? (1 << (group - 1)) : 0;
e12c2365
VB
695}
696
697/**
0fa2254b 698 * Subscribe to link changes.
e12c2365 699 *
960541eb 700 * @return 0 on success, -1 otherwise
e12c2365 701 */
960541eb
VB
702static int
703netlink_subscribe_changes(struct lldpd *cfg)
e12c2365 704{
0fa2254b
VB
705 unsigned int groups;
706
707 log_debug("netlink", "listening on interface changes");
708
709 groups = netlink_group_mask(RTNLGRP_LINK) |
710 netlink_group_mask(RTNLGRP_IPV4_IFADDR) |
711 netlink_group_mask(RTNLGRP_IPV6_IFADDR);
712
960541eb 713 return netlink_connect(cfg, NETLINK_ROUTE, groups);
0fa2254b
VB
714}
715
716/**
717 * Receive changes from netlink */
718static void
719netlink_change_cb(struct lldpd *cfg)
720{
721 if (cfg->g_netlink == NULL)
722 return;
960541eb 723 netlink_recv(cfg,
0fa2254b 724 cfg->g_netlink->devices,
960541eb 725 cfg->g_netlink->addresses);
0fa2254b 726}
0484f180 727
0fa2254b
VB
728/**
729 * Initialize netlink subsystem.
730 *
731 * This can be called several times but will have effect only the first time.
732 *
733 * @return 0 on success, -1 otherwise
734 */
735static int
736netlink_initialize(struct lldpd *cfg)
737{
738 if (cfg->g_netlink) return 0;
aca48e4b 739
0fa2254b
VB
740 log_debug("netlink", "initialize netlink subsystem");
741 if ((cfg->g_netlink = calloc(sizeof(struct lldpd_netlink), 1)) == NULL) {
742 log_warn("netlink", "unable to allocate memory for netlink subsystem");
743 goto end;
744 }
745
746 /* Connect to netlink (by requesting to get notified on updates) and
747 * request updated information right now */
960541eb
VB
748 if (netlink_subscribe_changes(cfg) == -1)
749 goto end;
0fa2254b
VB
750
751 struct interfaces_address_list *ifaddrs = cfg->g_netlink->addresses =
752 malloc(sizeof(struct interfaces_address_list));
13181ede
VB
753 if (ifaddrs == NULL) {
754 log_warn("netlink", "not enough memory for address list");
0fa2254b 755 goto end;
13181ede
VB
756 }
757 TAILQ_INIT(ifaddrs);
758
0fa2254b
VB
759 struct interfaces_device_list *ifs = cfg->g_netlink->devices =
760 malloc(sizeof(struct interfaces_device_list));
761 if (ifs == NULL) {
762 log_warn("netlink", "not enough memory for interface list");
763 goto end;
764 }
765 TAILQ_INIT(ifs);
766
960541eb 767 if (netlink_send(cfg->g_netlink->nl_socket, RTM_GETADDR, AF_UNSPEC, 1) == -1)
0fa2254b 768 goto end;
960541eb
VB
769 netlink_recv(cfg, NULL, ifaddrs);
770 if (netlink_send(cfg->g_netlink->nl_socket, RTM_GETLINK, AF_PACKET, 2) == -1)
0fa2254b 771 goto end;
960541eb 772 netlink_recv(cfg, ifs, NULL);
0fa2254b
VB
773
774 /* Listen to any future change */
775 cfg->g_iface_cb = netlink_change_cb;
960541eb 776 if (levent_iface_subscribe(cfg, cfg->g_netlink->nl_socket) == -1) {
0fa2254b
VB
777 goto end;
778 }
779
780 return 0;
781end:
782 netlink_cleanup(cfg);
783 return -1;
784}
785
786/**
787 * Cleanup netlink subsystem.
788 */
789void
790netlink_cleanup(struct lldpd *cfg)
791{
792 if (cfg->g_netlink == NULL) return;
793 if (cfg->g_netlink->nl_socket != -1)
794 close(cfg->g_netlink->nl_socket);
795 interfaces_free_devices(cfg->g_netlink->devices);
796 interfaces_free_addresses(cfg->g_netlink->addresses);
797
798 free(cfg->g_netlink);
799 cfg->g_netlink = NULL;
800}
801
802/**
803 * Receive the list of interfaces.
804 *
805 * @return a list of interfaces.
806 */
807struct interfaces_device_list*
808netlink_get_interfaces(struct lldpd *cfg)
809{
810 if (netlink_initialize(cfg) == -1) return NULL;
811 struct interfaces_device *ifd;
812 TAILQ_FOREACH(ifd, cfg->g_netlink->devices, next) {
813 ifd->ignore = 0;
13181ede 814 }
0fa2254b
VB
815 return cfg->g_netlink->devices;
816}
aca48e4b 817
0fa2254b
VB
818/**
819 * Receive the list of addresses.
820 *
821 * @return a list of addresses.
822 */
823struct interfaces_address_list*
824netlink_get_addresses(struct lldpd *cfg)
825{
826 if (netlink_initialize(cfg) == -1) return NULL;
827 return cfg->g_netlink->addresses;
0484f180 828}