]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/daemon/netlink.c
Fix for LLDP related netlink error messages
[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>
011056b3 28#include <linux/if_bridge.h>
0fa2254b
VB
29
30#define NETLINK_BUFFER 4096
02c91f0a 31
0fa2254b
VB
32struct netlink_req {
33 struct nlmsghdr hdr;
011056b3
VB
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;
0fa2254b 38};
13181ede
VB
39
40struct lldpd_netlink {
0fa2254b 41 int nl_socket;
960541eb 42 int nl_socket_recv_size;
0fa2254b
VB
43 /* Cache */
44 struct interfaces_device_list *devices;
45 struct interfaces_address_list *addresses;
e12c2365
VB
46};
47
c9f0ee58 48
960541eb
VB
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 */
c9f0ee58 56static int
960541eb 57netlink_socket_set_buffer_size(int s, int optname, const char *optname_str, int bufsize)
c9f0ee58 58{
e8ee1d9d 59 socklen_t size = sizeof(int);
c9f0ee58
AA
60 int got = 0;
61
960541eb
VB
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);
c9f0ee58
AA
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 */
960541eb
VB
72 if (getsockopt(s, SOL_SOCKET, optname, &got, &size) < 0) {
73 log_warn("netlink", "unable to get %s", optname_str);
0cb979c7
VB
74 return -1;
75 }
960541eb
VB
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;
0cb979c7 80 }
960541eb
VB
81
82 return got;
0cb979c7
VB
83}
84
e12c2365 85/**
0fa2254b
VB
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
960541eb 92 * @return 0 on success, -1 otherwise
e12c2365 93 */
0fa2254b 94static int
960541eb 95netlink_connect(struct lldpd *cfg, int protocol, unsigned groups)
e12c2365 96{
0fa2254b
VB
97 int s;
98 struct sockaddr_nl local = {
99 .nl_family = AF_NETLINK,
9ba21c60 100 .nl_pid = 0,
0fa2254b
VB
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;
13181ede 110 }
960541eb
VB
111 if (NETLINK_SEND_BUFSIZE &&
112 netlink_socket_set_buffer_size(s,
113 SO_SNDBUF, "SO_SNDBUF", NETLINK_SEND_BUFSIZE) == -1)
c9f0ee58 114 return -1;
960541eb
VB
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 }
0fa2254b
VB
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 }
960541eb
VB
128 cfg->g_netlink->nl_socket = s;
129 return 0;
e12c2365
VB
130}
131
132/**
0fa2254b 133 * Send a netlink message.
e12c2365 134 *
0fa2254b
VB
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.
e12c2365 137 *
0fa2254b
VB
138 * @param s the netlink socket
139 * @param type the request type (eg RTM_GETLINK)
140 * @param family the rt family (eg AF_PACKET)
e12c2365
VB
141 * @return 0 on success, -1 otherwise
142 */
143static int
0fa2254b 144netlink_send(int s, int type, int family, int seq)
e12c2365 145{
0fa2254b
VB
146 struct netlink_req req = {
147 .hdr = {
e512429c 148 .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
0fa2254b
VB
149 .nlmsg_type = type,
150 .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
151 .nlmsg_seq = seq,
152 .nlmsg_pid = getpid() },
011056b3 153 .ifm = { .ifi_family = family }
0fa2254b
VB
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
011056b3 167 if (family == AF_BRIDGE) {
e512429c 168 unsigned int len = RTA_LENGTH(sizeof(__u32));
011056b3
VB
169 /* request bridge vlan attributes */
170 req.ext_req.rta_type = IFLA_EXT_MASK;
e512429c 171 req.ext_req.rta_len = len;
011056b3 172 req.ext_filter_mask = RTEXT_FILTER_BRVLAN;
e512429c
RM
173 req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) + RTA_ALIGN(len);
174 iov.iov_len = req.hdr.nlmsg_len;
011056b3
VB
175 }
176
0fa2254b
VB
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;
16eacc5b
VB
183 }
184
0fa2254b
VB
185 return 0;
186}
16eacc5b 187
0fa2254b
VB
188static void
189netlink_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);
16eacc5b 195 }
16eacc5b
VB
196}
197
e12c2365 198/**
0fa2254b
VB
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
e12c2365 204 */
0fa2254b
VB
205static void
206netlink_parse_linkinfo(struct interfaces_device *iff, struct rtattr *rta, int len)
e12c2365 207{
0fa2254b
VB
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;
5f658dac
VB
228 } else if (!strcmp(kind, "team")) {
229 log_debug("netlink", "interface %s is a team",
230 iff->name);
231 iff->type |= IFACE_BOND_T;
0fa2254b
VB
232 }
233 }
234 }
13181ede 235
0fa2254b
VB
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]) {
011056b3 243 iff->vlanids[0] = *(uint16_t *)RTA_DATA(vlan_link_info_data_attrs[IFLA_VLAN_ID]);
0fa2254b 244 log_debug("netlink", "VLAN ID for interface %s is %d",
011056b3 245 iff->name, iff->vlanids[0]);
0fa2254b
VB
246 }
247 }
248
249 free(kind);
e12c2365
VB
250}
251
011056b3
VB
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 */
259static void
260netlink_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
e12c2365 294/**
13181ede 295 * Parse a `link` netlink message.
e12c2365 296 *
0fa2254b
VB
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
e12c2365 300 */
0fa2254b
VB
301static int
302netlink_parse_link(struct nlmsghdr *msg,
303 struct interfaces_device *iff)
e12c2365 304{
0fa2254b
VB
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;
13181ede
VB
315 }
316
0fa2254b
VB
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 */
5a85fbc9
VB
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 }
0fa2254b 350 break;
c04fafa7
VB
351 case IFLA_LINK_NETNSID:
352 /* Is the lower interface into another namesapce? */
5a85fbc9 353 iff->lower_idx = -2;
d2e6f750
VB
354 log_debug("netlink", "attribute IFLA_LINK_NETNSID received for %s",
355 iff->name ? iff->name : "(unknown)");
c04fafa7 356 break;
0fa2254b
VB
357 case IFLA_MASTER:
358 /* Index of master interface */
359 iff->upper_idx = *(int*)RTA_DATA(attribute);
360 break;
0fa2254b
VB
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;
011056b3
VB
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;
0fa2254b
VB
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 }
13181ede 377 }
0fa2254b
VB
378 if (!iff->name || !iff->address) {
379 log_info("netlink", "interface %d does not have a name or an address, skip",
13181ede 380 iff->index);
0fa2254b 381 return -1;
13181ede 382 }
92c6dcfe
VB
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 }
5a85fbc9
VB
389 if (iff->lower_idx == -2)
390 iff->lower_idx = -1;
13181ede 391
2b9ecd2a
VB
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;
2b9ecd2a
VB
397 }
398
0fa2254b
VB
399 log_debug("netlink", "parsed link %d (%s, flags: %d)",
400 iff->index, iff->name, iff->flags);
401 return 0;
e12c2365
VB
402}
403
404/**
13181ede 405 * Parse a `address` netlink message.
e12c2365 406 *
0fa2254b
VB
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
e12c2365 410 */
0fa2254b
VB
411static int
412netlink_parse_address(struct nlmsghdr *msg,
413 struct interfaces_address *ifa)
e12c2365 414{
0fa2254b
VB
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) {
13181ede
VB
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)",
0fa2254b
VB
428 ifa->index, ifi->ifa_family);
429 return -1;
13181ede
VB
430 }
431
0fa2254b
VB
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 }
13181ede 459 }
0fa2254b 460 if (ifa->address.ss_family == AF_UNSPEC) {
13181ede
VB
461 log_debug("netlink", "no IP for interface %d",
462 ifa->index);
0fa2254b 463 return -1;
13181ede 464 }
0fa2254b 465 return 0;
e12c2365
VB
466}
467
58e30b5a
VB
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 */
474void
475netlink_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;
011056b3
VB
489 if (new->vlanids[0] == 0 && new->type == IFACE_VLAN_T)
490 new->vlanids[0] = old->vlanids[0];
d2e6f750
VB
491
492 /* It's not possible for lower link to change */
493 new->lower_idx = old->lower_idx;
58e30b5a
VB
494}
495
e12c2365 496/**
0fa2254b 497 * Receive netlink answer from the kernel.
e12c2365 498 *
0fa2254b
VB
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
e12c2365 502 */
0fa2254b 503static int
960541eb 504netlink_recv(struct lldpd *cfg,
0fa2254b 505 struct interfaces_device_list *ifs,
960541eb 506 struct interfaces_address_list *ifas)
e12c2365 507{
6c3697f2 508 int end = 0, ret = 0, flags, retry = 0;
85b72fe0 509 struct iovec iov;
0fa2254b 510 int link_update = 0;
960541eb 511 int s = cfg->g_netlink->nl_socket;
0fa2254b
VB
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
85b72fe0
DM
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
0fa2254b
VB
526 while (!end) {
527 ssize_t len;
528 struct nlmsghdr *msg;
0fa2254b
VB
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 };
6c3697f2 536 flags = MSG_PEEK | MSG_TRUNC;
85b72fe0 537retry:
66a551ed 538 len = recvmsg(s, &rtnl_reply, flags);
0fa2254b
VB
539 if (len == -1) {
540 if (errno == EAGAIN || errno == EWOULDBLOCK) {
6c3697f2
VB
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");
85b72fe0
DM
546 ret = 0;
547 goto out;
0fa2254b 548 }
960541eb
VB
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);
0cb979c7
VB
568 flags = 0;
569 goto retry;
0cb979c7
VB
570 }
571 }
644cd42d 572 log_warn("netlink", "unable to receive netlink answer");
85b72fe0
DM
573 ret = -1;
574 goto out;
0fa2254b 575 }
85b72fe0
DM
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);
0fa2254b
VB
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 }
703f6a0d 630
0fa2254b
VB
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);
58e30b5a 639 netlink_merge(ifdold, ifdnew);
0fa2254b
VB
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",
703f6a0d 648 ifdnew->name);
0fa2254b
VB
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,
878441b2 675 sizeof(ifaold->address))) break;
0fa2254b
VB
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 }
13181ede 683
0fa2254b
VB
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) {
8027d907 698 log_info("netlink",
0fa2254b
VB
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 }
13181ede 719 }
0fa2254b
VB
720end:
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) {
c04fafa7
VB
728 log_debug("netlink",
729 "upper interface for %s is %s",
730 iface1->name, iface2->name);
0fa2254b
VB
731 iface1->upper = iface2;
732 break;
733 }
13181ede 734 }
100266c1
VB
735 if (iface2 == NULL)
736 iface1->upper = NULL;
0fa2254b
VB
737 } else {
738 iface1->upper = NULL;
13181ede 739 }
0fa2254b
VB
740 if (iface1->lower_idx != -1 && iface1->lower_idx != iface1->index) {
741 TAILQ_FOREACH(iface2, ifs, next) {
742 if (iface1->lower_idx == iface2->index) {
100266c1
VB
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. */
0fa2254b 751 if (iface2->lower_idx == iface1->index) {
100266c1 752 iface1->lower = NULL;
c04fafa7 753 log_debug("netlink",
5a85fbc9
VB
754 "link loop detected between %s(%d) and %s(%d)",
755 iface1->name,
756 iface1->index,
757 iface2->name,
758 iface2->index);
c04fafa7
VB
759 } else {
760 log_debug("netlink",
761 "lower interface for %s is %s",
762 iface1->name, iface2->name);
763 iface1->lower = iface2;
764 }
0fa2254b 765 break;
7d0a4975 766 }
100266c1
VB
767 if (iface2 == NULL)
768 iface1->lower = NULL;
13181ede 769 }
0fa2254b
VB
770 } else {
771 iface1->lower = NULL;
13181ede 772 }
0fa2254b 773 }
13181ede 774 }
85b72fe0
DM
775
776out:
777 free(iov.iov_base);
778 return ret;
0fa2254b 779}
13181ede 780
0fa2254b
VB
781static int
782netlink_group_mask(int group)
783{
784 return group ? (1 << (group - 1)) : 0;
e12c2365
VB
785}
786
787/**
0fa2254b 788 * Subscribe to link changes.
e12c2365 789 *
960541eb 790 * @return 0 on success, -1 otherwise
e12c2365 791 */
960541eb
VB
792static int
793netlink_subscribe_changes(struct lldpd *cfg)
e12c2365 794{
0fa2254b
VB
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
960541eb 803 return netlink_connect(cfg, NETLINK_ROUTE, groups);
0fa2254b
VB
804}
805
806/**
807 * Receive changes from netlink */
808static void
809netlink_change_cb(struct lldpd *cfg)
810{
811 if (cfg->g_netlink == NULL)
812 return;
960541eb 813 netlink_recv(cfg,
0fa2254b 814 cfg->g_netlink->devices,
960541eb 815 cfg->g_netlink->addresses);
0fa2254b 816}
0484f180 817
0fa2254b
VB
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 */
825static int
826netlink_initialize(struct lldpd *cfg)
827{
011056b3
VB
828#ifdef ENABLE_DOT1
829 struct interfaces_device *iff;
830#endif
831
0fa2254b 832 if (cfg->g_netlink) return 0;
aca48e4b 833
0fa2254b
VB
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 */
960541eb
VB
842 if (netlink_subscribe_changes(cfg) == -1)
843 goto end;
0fa2254b
VB
844
845 struct interfaces_address_list *ifaddrs = cfg->g_netlink->addresses =
846 malloc(sizeof(struct interfaces_address_list));
13181ede
VB
847 if (ifaddrs == NULL) {
848 log_warn("netlink", "not enough memory for address list");
0fa2254b 849 goto end;
13181ede
VB
850 }
851 TAILQ_INIT(ifaddrs);
852
0fa2254b
VB
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
960541eb 861 if (netlink_send(cfg->g_netlink->nl_socket, RTM_GETADDR, AF_UNSPEC, 1) == -1)
0fa2254b 862 goto end;
960541eb
VB
863 netlink_recv(cfg, NULL, ifaddrs);
864 if (netlink_send(cfg->g_netlink->nl_socket, RTM_GETLINK, AF_PACKET, 2) == -1)
0fa2254b 865 goto end;
960541eb 866 netlink_recv(cfg, ifs, NULL);
011056b3
VB
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
0fa2254b
VB
879
880 /* Listen to any future change */
881 cfg->g_iface_cb = netlink_change_cb;
960541eb 882 if (levent_iface_subscribe(cfg, cfg->g_netlink->nl_socket) == -1) {
0fa2254b
VB
883 goto end;
884 }
885
886 return 0;
887end:
888 netlink_cleanup(cfg);
889 return -1;
890}
891
892/**
893 * Cleanup netlink subsystem.
894 */
895void
896netlink_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 */
913struct interfaces_device_list*
914netlink_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;
13181ede 920 }
0fa2254b
VB
921 return cfg->g_netlink->devices;
922}
aca48e4b 923
0fa2254b
VB
924/**
925 * Receive the list of addresses.
926 *
927 * @return a list of addresses.
928 */
929struct interfaces_address_list*
930netlink_get_addresses(struct lldpd *cfg)
931{
932 if (netlink_initialize(cfg) == -1) return NULL;
933 return cfg->g_netlink->addresses;
0484f180 934}