1 /* -*- mode: c; c-file-style: "openbsd" -*- */
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
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.
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.
18 /* Grabbing interfaces information with netlink only. */
23 #include <sys/socket.h>
25 #include <net/if_arp.h>
26 #include <linux/netlink.h>
27 #include <linux/rtnetlink.h>
28 #include <linux/if_bridge.h>
30 #define NETLINK_BUFFER 4096
35 /* attribute has to be NLMSG aligned */
36 struct rtattr ext_req
__attribute__ ((aligned(NLMSG_ALIGNTO
)));
37 __u32 ext_filter_mask
;
40 struct lldpd_netlink
{
42 int nl_socket_recv_size
;
44 struct interfaces_device_list
*devices
;
45 struct interfaces_address_list
*addresses
;
49 * Set vlan id in the bitmap
52 bitmap_set(uint32_t *bmap
, uint16_t vlan_id
)
54 if (vlan_id
< MAX_VLAN
)
55 bmap
[vlan_id
/ 32] |= (((uint32_t) 1) << (vlan_id
% 32));
59 * Checks if the bitmap is empty
62 is_bitmap_empty(uint32_t *bmap
)
66 for (i
= 0; i
< VLAN_BITMAP_LEN
; i
++) {
75 * Calculate the number of bits set in the bitmap to get total
79 num_bits_set(uint32_t *bmap
)
84 for (i
= 0; (i
< VLAN_BITMAP_LEN
); i
++) {
87 for (bit
= 0; bit
< 32; bit
++) {
88 if (bmap
[i
] & (1 << bit
))
97 * Set netlink socket buffer size.
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).
104 netlink_socket_set_buffer_size(int s
, int optname
, const char *optname_str
, int bufsize
)
106 socklen_t size
= sizeof(int);
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
);
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.
119 if (getsockopt(s
, SOL_SOCKET
, optname
, &got
, &size
) < 0) {
120 log_warn("netlink", "unable to get %s", optname_str
);
123 if (bufsize
> 0 && got
< bufsize
) {
124 log_warnx("netlink", "tried to set %s to '%d' "
125 "but got '%d'", optname_str
, bufsize
, got
);
133 * Connect to netlink.
135 * Open a Netlink socket and connect to it.
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
142 netlink_connect(struct lldpd
*cfg
, int protocol
, unsigned groups
)
145 struct sockaddr_nl local
= {
146 .nl_family
= AF_NETLINK
,
151 /* Open Netlink socket */
152 log_debug("netlink", "opening netlink socket");
153 s
= socket(AF_NETLINK
, SOCK_RAW
, protocol
);
155 log_warn("netlink", "unable to open netlink socket");
158 if (NETLINK_SEND_BUFSIZE
&&
159 netlink_socket_set_buffer_size(s
,
160 SO_SNDBUF
, "SO_SNDBUF", NETLINK_SEND_BUFSIZE
) == -1)
163 int rc
= netlink_socket_set_buffer_size(s
,
164 SO_RCVBUF
, "SO_RCVBUF", NETLINK_RECEIVE_BUFSIZE
);
167 case -2: cfg
->g_netlink
->nl_socket_recv_size
= 0; break;
168 default: cfg
->g_netlink
->nl_socket_recv_size
= rc
; break;
170 if (groups
&& bind(s
, (struct sockaddr
*)&local
, sizeof(struct sockaddr_nl
)) < 0) {
171 log_warn("netlink", "unable to bind netlink socket");
175 cfg
->g_netlink
->nl_socket
= s
;
180 * Send a netlink message.
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.
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
191 netlink_send(int s
, int type
, int family
, int seq
)
193 struct netlink_req req
= {
195 .nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
197 .nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
,
199 .nlmsg_pid
= getpid() },
200 .ifm
= { .ifi_family
= family
}
204 .iov_len
= req
.hdr
.nlmsg_len
206 struct sockaddr_nl peer
= { .nl_family
= AF_NETLINK
};
207 struct msghdr rtnl_msg
= {
211 .msg_namelen
= sizeof(struct sockaddr_nl
)
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
;
224 /* Send netlink message. This is synchronous but we are guaranteed
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");
236 netlink_parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
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
);
246 * Parse a `linkinfo` attributes.
248 * @param iff where to put the result
249 * @param rta linkinfo attribute
250 * @param len length of attributes
253 netlink_parse_linkinfo(struct interfaces_device
*iff
, struct rtattr
*rta
, int len
)
255 struct rtattr
*link_info_attrs
[IFLA_INFO_MAX
+1] = {};
259 netlink_parse_rtattr(link_info_attrs
, IFLA_INFO_MAX
, rta
, len
);
261 if (link_info_attrs
[IFLA_INFO_KIND
]) {
262 kind
= strdup(RTA_DATA(link_info_attrs
[IFLA_INFO_KIND
]));
264 if (!strcmp(kind
, "vlan")) {
265 log_debug("netlink", "interface %s is a VLAN",
267 iff
->type
|= IFACE_VLAN_T
;
268 } else if (!strcmp(kind
, "bridge")) {
269 log_debug("netlink", "interface %s is a bridge",
271 iff
->type
|= IFACE_BRIDGE_T
;
272 } else if (!strcmp(kind
, "bond")) {
273 log_debug("netlink", "interface %s is a bond",
275 iff
->type
|= IFACE_BOND_T
;
276 } else if (!strcmp(kind
, "team")) {
277 log_debug("netlink", "interface %s is a team",
279 iff
->type
|= IFACE_BOND_T
;
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
]));
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",
302 * Parse a `afspec` attributes.
304 * @param iff where to put the result
305 * @param rta afspec attribute
306 * @param len length of attributes
309 netlink_parse_afspec(struct interfaces_device
*iff
, struct rtattr
*rta
, int len
)
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)");
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
;
324 log_debug("netlink", "unknown afspec attribute type %d for iface %s",
325 rta
->rta_type
, iff
->name
? iff
->name
: "(unknown)");
328 rta
= RTA_NEXT(rta
, len
);
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)
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;
340 * Parse a `link` netlink message.
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
347 netlink_parse_link(struct nlmsghdr
*msg
,
348 struct interfaces_device
*iff
)
350 struct ifinfomsg
*ifi
;
351 struct rtattr
*attribute
;
353 ifi
= NLMSG_DATA(msg
);
354 len
= msg
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct ifinfomsg
));
356 if (ifi
->ifi_type
!= ARPHRD_ETHER
) {
357 log_debug("netlink", "skip non Ethernet interface at index %d",
362 iff
->index
= ifi
->ifi_index
;
363 iff
->flags
= ifi
->ifi_flags
;
367 for (attribute
= IFLA_RTA(ifi
);
368 RTA_OK(attribute
, len
);
369 attribute
= RTA_NEXT(attribute
, len
)) {
370 switch(attribute
->rta_type
) {
373 iff
->name
= strdup(RTA_DATA(attribute
));
376 /* Interface alias */
377 iff
->alias
= strdup(RTA_DATA(attribute
));
380 /* Interface MAC address */
381 iff
->address
= malloc(RTA_PAYLOAD(attribute
));
383 memcpy(iff
->address
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
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
);
392 log_debug("netlink", "attribute IFLA_LINK for %s: %d (ignored)",
393 iff
->name
? iff
->name
: "(unknown)", iff
->lower_idx
);
396 case IFLA_LINK_NETNSID
:
397 /* Is the lower interface into another namesapce? */
399 log_debug("netlink", "attribute IFLA_LINK_NETNSID received for %s",
400 iff
->name
? iff
->name
: "(unknown)");
403 /* Index of master interface */
404 iff
->upper_idx
= *(int*)RTA_DATA(attribute
);
407 /* Maximum Transmission Unit */
408 iff
->mtu
= *(int*)RTA_DATA(attribute
);
411 netlink_parse_linkinfo(iff
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
414 if (ifi
->ifi_family
!= AF_BRIDGE
) break;
415 netlink_parse_afspec(iff
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
418 log_debug("netlink", "unhandled link attribute type %d for iface %s",
419 attribute
->rta_type
, iff
->name
? iff
->name
: "(unknown)");
423 if (!iff
->name
|| !iff
->address
) {
424 log_info("netlink", "interface %d does not have a name or an address, skip",
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
;
434 if (iff
->lower_idx
== -2)
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
;
444 log_debug("netlink", "parsed link %d (%s, flags: %d)",
445 iff
->index
, iff
->name
, iff
->flags
);
450 * Parse a `address` netlink message.
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
457 netlink_parse_address(struct nlmsghdr
*msg
,
458 struct interfaces_address
*ifa
)
460 struct ifaddrmsg
*ifi
;
461 struct rtattr
*attribute
;
463 ifi
= NLMSG_DATA(msg
);
464 len
= msg
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
466 ifa
->index
= ifi
->ifa_index
;
467 ifa
->flags
= ifi
->ifa_flags
;
468 switch (ifi
->ifa_family
) {
470 case AF_INET6
: break;
472 log_debug("netlink", "got a non IP address on if %d (family: %d)",
473 ifa
->index
, ifi
->ifa_family
);
477 for (attribute
= IFA_RTA(ifi
);
478 RTA_OK(attribute
, len
);
479 attribute
= RTA_NEXT(attribute
, len
)) {
480 switch(attribute
->rta_type
) {
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
));
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
));
500 log_debug("netlink", "unhandled address attribute type %d for iface %d",
501 attribute
->rta_type
, ifa
->index
);
505 if (ifa
->address
.ss_family
== AF_UNSPEC
) {
506 log_debug("netlink", "no IP for interface %d",
514 * Merge an old interface with a new one.
516 * Some properties may be absent in the new interface that should be copied over
520 netlink_merge(struct interfaces_device
*old
, struct interfaces_device
*new)
522 if (new->alias
== NULL
) {
523 new->alias
= old
->alias
;
526 if (new->address
== NULL
) {
527 new->address
= old
->address
;
533 new->type
= old
->type
;
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
);
539 /* It's not possible for lower link to change */
540 new->lower_idx
= old
->lower_idx
;
544 * Receive netlink answer from the kernel.
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
551 netlink_recv(struct lldpd
*cfg
,
552 struct interfaces_device_list
*ifs
,
553 struct interfaces_address_list
*ifas
)
555 int end
= 0, ret
= 0, flags
, retry
= 0;
558 int s
= cfg
->g_netlink
->nl_socket
;
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];
566 iov
.iov_len
= NETLINK_BUFFER
;
567 iov
.iov_base
= malloc(iov
.iov_len
);
569 log_warn("netlink", "not enough memory");
575 struct nlmsghdr
*msg
;
576 struct sockaddr_nl peer
= { .nl_family
= AF_NETLINK
};
577 struct msghdr rtnl_reply
= {
581 .msg_namelen
= sizeof(struct sockaddr_nl
)
583 flags
= MSG_PEEK
| MSG_TRUNC
;
585 len
= recvmsg(s
, &rtnl_reply
, flags
);
587 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
589 levent_recv_error(s
, "netlink socket");
592 log_warnx("netlink", "should have received something, but didn't");
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 */
601 if (rsize
> NETLINK_MAX_RECEIVE_BUFSIZE
) {
602 rsize
= NETLINK_MAX_RECEIVE_BUFSIZE
;
604 int rc
= netlink_socket_set_buffer_size(s
,
605 SO_RCVBUF
, "SO_RCVBUF",
608 cfg
->g_netlink
->nl_socket_recv_size
= 0;
610 cfg
->g_netlink
->nl_socket_recv_size
= rsize
;
611 if (rc
> 0 || rc
== -2) {
613 "netlink receive buffer too small, retry with larger one (%d)",
619 log_warn("netlink", "unable to receive netlink answer");
628 if (iov
.iov_len
< len
|| (rtnl_reply
.msg_flags
& MSG_TRUNC
)) {
631 /* Provided buffer is not large enough, enlarge it
632 * to size of len (which should be total length of the message)
635 tmp
= realloc(iov
.iov_base
, iov
.iov_len
);
637 log_warn("netlink", "not enough memory");
641 log_debug("netlink", "enlarge message size to %zu bytes", len
);
648 /* Buffer is big enough, do the actual reading */
653 for (msg
= (struct nlmsghdr
*)(void*)(iov
.iov_base
);
655 msg
= NLMSG_NEXT(msg
, len
)) {
656 if (!(msg
->nlmsg_flags
& NLM_F_MULTI
))
658 switch (msg
->nlmsg_type
) {
660 log_debug("netlink", "received done message");
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");
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;
678 if (msg
->nlmsg_type
== RTM_NEWLINK
) {
679 if (ifdold
== NULL
) {
680 log_debug("netlink", "interface %s is new",
682 TAILQ_INSERT_TAIL(ifs
, ifdnew
, next
);
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
);
692 if (ifdold
== NULL
) {
694 "removal request for %s, but no knowledge of it",
697 log_debug("netlink", "interface %s is to be removed",
699 TAILQ_REMOVE(ifs
, ifdold
, next
);
700 interfaces_free_device(ifdold
);
702 interfaces_free_device(ifdnew
);
706 interfaces_free_device(ifdnew
);
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");
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;
724 if (getnameinfo((struct sockaddr
*)&ifanew
->address
,
725 sizeof(ifanew
->address
),
727 NULL
, 0, NI_NUMERICHOST
) != 0) {
728 strlcpy(addr
, "(unknown)", sizeof(addr
));
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
);
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
);
744 if (ifaold
== NULL
) {
746 "removal request for address of %s%%%d, but no knowledge of it",
747 addr
, ifanew
->index
);
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
);
754 interfaces_free_address(ifanew
);
757 interfaces_free_address(ifanew
);
762 "received unhandled message type %d (len: %d)",
763 msg
->nlmsg_type
, msg
->nlmsg_len
);
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
) {
776 "upper interface for %s is %s",
777 iface1
->name
, iface2
->name
);
778 iface1
->upper
= iface2
;
783 iface1
->upper
= NULL
;
785 iface1
->upper
= NULL
;
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
798 if (iface2
->lower_idx
== iface1
->index
) {
799 iface1
->lower
= NULL
;
801 "link loop detected between %s(%d) and %s(%d)",
808 "lower interface for %s is %s",
809 iface1
->name
, iface2
->name
);
810 iface1
->lower
= iface2
;
815 iface1
->lower
= NULL
;
818 iface1
->lower
= NULL
;
829 netlink_group_mask(int group
)
831 return group
? (1 << (group
- 1)) : 0;
835 * Subscribe to link changes.
837 * @return 0 on success, -1 otherwise
840 netlink_subscribe_changes(struct lldpd
*cfg
)
844 log_debug("netlink", "listening on interface changes");
846 groups
= netlink_group_mask(RTNLGRP_LINK
) |
847 netlink_group_mask(RTNLGRP_IPV4_IFADDR
) |
848 netlink_group_mask(RTNLGRP_IPV6_IFADDR
);
850 return netlink_connect(cfg
, NETLINK_ROUTE
, groups
);
854 * Receive changes from netlink */
856 netlink_change_cb(struct lldpd
*cfg
)
858 if (cfg
->g_netlink
== NULL
)
861 cfg
->g_netlink
->devices
,
862 cfg
->g_netlink
->addresses
);
866 * Initialize netlink subsystem.
868 * This can be called several times but will have effect only the first time.
870 * @return 0 on success, -1 otherwise
873 netlink_initialize(struct lldpd
*cfg
)
876 struct interfaces_device
*iff
;
879 if (cfg
->g_netlink
) return 0;
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");
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)
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");
900 struct interfaces_device_list
*ifs
= cfg
->g_netlink
->devices
=
901 malloc(sizeof(struct interfaces_device_list
));
903 log_warn("netlink", "not enough memory for interface list");
908 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETADDR
, AF_UNSPEC
, 1) == -1)
910 netlink_recv(cfg
, NULL
, ifaddrs
);
911 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETLINK
, AF_PACKET
, 2) == -1)
913 netlink_recv(cfg
, ifs
, NULL
);
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)
921 netlink_recv(cfg
, ifs
, NULL
);
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) {
935 netlink_cleanup(cfg
);
940 * Cleanup netlink subsystem.
943 netlink_cleanup(struct lldpd
*cfg
)
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
);
951 free(cfg
->g_netlink
);
952 cfg
->g_netlink
= NULL
;
956 * Receive the list of interfaces.
958 * @return a list of interfaces.
960 struct interfaces_device_list
*
961 netlink_get_interfaces(struct lldpd
*cfg
)
963 if (netlink_initialize(cfg
) == -1) return NULL
;
964 struct interfaces_device
*ifd
;
965 TAILQ_FOREACH(ifd
, cfg
->g_netlink
->devices
, next
) {
968 return cfg
->g_netlink
->devices
;
972 * Receive the list of addresses.
974 * @return a list of addresses.
976 struct interfaces_address_list
*
977 netlink_get_addresses(struct lldpd
*cfg
)
979 if (netlink_initialize(cfg
) == -1) return NULL
;
980 return cfg
->g_netlink
->addresses
;