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
;
50 * Set netlink socket buffer size.
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).
57 netlink_socket_set_buffer_size(int s
, int optname
, const char *optname_str
, int bufsize
)
59 socklen_t size
= sizeof(int);
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
);
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.
72 if (getsockopt(s
, SOL_SOCKET
, optname
, &got
, &size
) < 0) {
73 log_warn("netlink", "unable to get %s", optname_str
);
76 if (bufsize
> 0 && got
< bufsize
) {
77 log_warnx("netlink", "tried to set %s to '%d' "
78 "but got '%d'", optname_str
, bufsize
, got
);
88 * Open a Netlink socket and connect to it.
90 * @param protocol Which protocol to use (eg NETLINK_ROUTE).
91 * @param groups Which groups we want to subscribe to
92 * @return 0 on success, -1 otherwise
95 netlink_connect(struct lldpd
*cfg
, int protocol
, unsigned groups
)
98 struct sockaddr_nl local
= {
99 .nl_family
= AF_NETLINK
,
104 /* Open Netlink socket */
105 log_debug("netlink", "opening netlink socket");
106 s
= socket(AF_NETLINK
, SOCK_RAW
, protocol
);
108 log_warn("netlink", "unable to open netlink socket");
111 if (NETLINK_SEND_BUFSIZE
&&
112 netlink_socket_set_buffer_size(s
,
113 SO_SNDBUF
, "SO_SNDBUF", NETLINK_SEND_BUFSIZE
) == -1)
116 int rc
= netlink_socket_set_buffer_size(s
,
117 SO_RCVBUF
, "SO_RCVBUF", NETLINK_RECEIVE_BUFSIZE
);
120 case -2: cfg
->g_netlink
->nl_socket_recv_size
= 0; break;
121 default: cfg
->g_netlink
->nl_socket_recv_size
= rc
; break;
123 if (groups
&& bind(s
, (struct sockaddr
*)&local
, sizeof(struct sockaddr_nl
)) < 0) {
124 log_warn("netlink", "unable to bind netlink socket");
128 cfg
->g_netlink
->nl_socket
= s
;
133 * Send a netlink message.
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.
138 * @param s the netlink socket
139 * @param type the request type (eg RTM_GETLINK)
140 * @param family the rt family (eg AF_PACKET)
141 * @return 0 on success, -1 otherwise
144 netlink_send(int s
, int type
, int family
, int seq
)
146 struct netlink_req req
= {
148 .nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
)),
150 .nlmsg_flags
= NLM_F_REQUEST
| NLM_F_DUMP
,
152 .nlmsg_pid
= getpid() },
153 .ifm
= { .ifi_family
= family
}
157 .iov_len
= req
.hdr
.nlmsg_len
159 struct sockaddr_nl peer
= { .nl_family
= AF_NETLINK
};
160 struct msghdr rtnl_msg
= {
164 .msg_namelen
= sizeof(struct sockaddr_nl
)
167 if (family
== AF_BRIDGE
) {
168 unsigned int len
= RTA_LENGTH(sizeof(__u32
));
169 /* request bridge vlan attributes */
170 req
.ext_req
.rta_type
= IFLA_EXT_MASK
;
171 req
.ext_req
.rta_len
= len
;
172 req
.ext_filter_mask
= RTEXT_FILTER_BRVLAN
;
173 req
.hdr
.nlmsg_len
= NLMSG_ALIGN(req
.hdr
.nlmsg_len
) + RTA_ALIGN(len
);
174 iov
.iov_len
= req
.hdr
.nlmsg_len
;
177 /* Send netlink message. This is synchronous but we are guaranteed
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");
189 netlink_parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
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
);
199 * Parse a `linkinfo` attributes.
201 * @param iff where to put the result
202 * @param rta linkinfo attribute
203 * @param len length of attributes
206 netlink_parse_linkinfo(struct interfaces_device
*iff
, struct rtattr
*rta
, int len
)
208 struct rtattr
*link_info_attrs
[IFLA_INFO_MAX
+1] = {};
211 netlink_parse_rtattr(link_info_attrs
, IFLA_INFO_MAX
, rta
, len
);
213 if (link_info_attrs
[IFLA_INFO_KIND
]) {
214 kind
= strdup(RTA_DATA(link_info_attrs
[IFLA_INFO_KIND
]));
216 if (!strcmp(kind
, "vlan")) {
217 log_debug("netlink", "interface %s is a VLAN",
219 iff
->type
|= IFACE_VLAN_T
;
220 } else if (!strcmp(kind
, "bridge")) {
221 log_debug("netlink", "interface %s is a bridge",
223 iff
->type
|= IFACE_BRIDGE_T
;
224 } else if (!strcmp(kind
, "bond")) {
225 log_debug("netlink", "interface %s is a bond",
227 iff
->type
|= IFACE_BOND_T
;
228 } else if (!strcmp(kind
, "team")) {
229 log_debug("netlink", "interface %s is a team",
231 iff
->type
|= IFACE_BOND_T
;
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
]));
242 if (vlan_link_info_data_attrs
[IFLA_VLAN_ID
]) {
243 iff
->vlanids
[0] = *(uint16_t *)RTA_DATA(vlan_link_info_data_attrs
[IFLA_VLAN_ID
]);
244 log_debug("netlink", "VLAN ID for interface %s is %d",
245 iff
->name
, iff
->vlanids
[0]);
253 * Parse a `afspec` attributes.
255 * @param iff where to put the result
256 * @param rta afspec attribute
257 * @param len length of attributes
260 netlink_parse_afspec(struct interfaces_device
*iff
, struct rtattr
*rta
, int len
)
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)");
275 iff
->vlanids
[i
++] = vinfo
->vid
;
276 if (vinfo
->flags
& (BRIDGE_VLAN_INFO_PVID
| BRIDGE_VLAN_INFO_UNTAGGED
))
277 iff
->pvid
= vinfo
->vid
;
280 log_debug("netlink", "unknown afspec attribute type %d for iface %s",
281 rta
->rta_type
, iff
->name
? iff
->name
: "(unknown)");
284 rta
= RTA_NEXT(rta
, len
);
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;
295 * Parse a `link` netlink message.
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
302 netlink_parse_link(struct nlmsghdr
*msg
,
303 struct interfaces_device
*iff
)
305 struct ifinfomsg
*ifi
;
306 struct rtattr
*attribute
;
308 ifi
= NLMSG_DATA(msg
);
309 len
= msg
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct ifinfomsg
));
311 if (ifi
->ifi_type
!= ARPHRD_ETHER
) {
312 log_debug("netlink", "skip non Ethernet interface at index %d",
317 iff
->index
= ifi
->ifi_index
;
318 iff
->flags
= ifi
->ifi_flags
;
322 for (attribute
= IFLA_RTA(ifi
);
323 RTA_OK(attribute
, len
);
324 attribute
= RTA_NEXT(attribute
, len
)) {
325 switch(attribute
->rta_type
) {
328 iff
->name
= strdup(RTA_DATA(attribute
));
331 /* Interface alias */
332 iff
->alias
= strdup(RTA_DATA(attribute
));
335 /* Interface MAC address */
336 iff
->address
= malloc(RTA_PAYLOAD(attribute
));
338 memcpy(iff
->address
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
341 /* Index of "lower" interface */
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
);
347 log_debug("netlink", "attribute IFLA_LINK for %s: %d (ignored)",
348 iff
->name
? iff
->name
: "(unknown)", iff
->lower_idx
);
351 case IFLA_LINK_NETNSID
:
352 /* Is the lower interface into another namesapce? */
354 log_debug("netlink", "attribute IFLA_LINK_NETNSID received for %s",
355 iff
->name
? iff
->name
: "(unknown)");
358 /* Index of master interface */
359 iff
->upper_idx
= *(int*)RTA_DATA(attribute
);
362 /* Maximum Transmission Unit */
363 iff
->mtu
= *(int*)RTA_DATA(attribute
);
366 netlink_parse_linkinfo(iff
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
369 if (ifi
->ifi_family
!= AF_BRIDGE
) break;
370 netlink_parse_afspec(iff
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
373 log_debug("netlink", "unhandled link attribute type %d for iface %s",
374 attribute
->rta_type
, iff
->name
? iff
->name
: "(unknown)");
378 if (!iff
->name
|| !iff
->address
) {
379 log_info("netlink", "interface %d does not have a name or an address, skip",
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
;
389 if (iff
->lower_idx
== -2)
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
;
399 log_debug("netlink", "parsed link %d (%s, flags: %d)",
400 iff
->index
, iff
->name
, iff
->flags
);
405 * Parse a `address` netlink message.
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
412 netlink_parse_address(struct nlmsghdr
*msg
,
413 struct interfaces_address
*ifa
)
415 struct ifaddrmsg
*ifi
;
416 struct rtattr
*attribute
;
418 ifi
= NLMSG_DATA(msg
);
419 len
= msg
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
421 ifa
->index
= ifi
->ifa_index
;
422 ifa
->flags
= ifi
->ifa_flags
;
423 switch (ifi
->ifa_family
) {
425 case AF_INET6
: break;
427 log_debug("netlink", "got a non IP address on if %d (family: %d)",
428 ifa
->index
, ifi
->ifa_family
);
432 for (attribute
= IFA_RTA(ifi
);
433 RTA_OK(attribute
, len
);
434 attribute
= RTA_NEXT(attribute
, len
)) {
435 switch(attribute
->rta_type
) {
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
));
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
));
455 log_debug("netlink", "unhandled address attribute type %d for iface %d",
456 attribute
->rta_type
, ifa
->index
);
460 if (ifa
->address
.ss_family
== AF_UNSPEC
) {
461 log_debug("netlink", "no IP for interface %d",
469 * Merge an old interface with a new one.
471 * Some properties may be absent in the new interface that should be copied over
475 netlink_merge(struct interfaces_device
*old
, struct interfaces_device
*new)
477 if (new->alias
== NULL
) {
478 new->alias
= old
->alias
;
481 if (new->address
== NULL
) {
482 new->address
= old
->address
;
488 new->type
= old
->type
;
489 if (new->vlanids
[0] == 0 && new->type
== IFACE_VLAN_T
)
490 new->vlanids
[0] = old
->vlanids
[0];
492 /* It's not possible for lower link to change */
493 new->lower_idx
= old
->lower_idx
;
497 * Receive netlink answer from the kernel.
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
504 netlink_recv(struct lldpd
*cfg
,
505 struct interfaces_device_list
*ifs
,
506 struct interfaces_address_list
*ifas
)
508 int end
= 0, ret
= 0, flags
, retry
= 0;
511 int s
= cfg
->g_netlink
->nl_socket
;
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];
519 iov
.iov_len
= NETLINK_BUFFER
;
520 iov
.iov_base
= malloc(iov
.iov_len
);
522 log_warn("netlink", "not enough memory");
528 struct nlmsghdr
*msg
;
529 struct sockaddr_nl peer
= { .nl_family
= AF_NETLINK
};
530 struct msghdr rtnl_reply
= {
534 .msg_namelen
= sizeof(struct sockaddr_nl
)
536 flags
= MSG_PEEK
| MSG_TRUNC
;
538 len
= recvmsg(s
, &rtnl_reply
, flags
);
540 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
542 levent_recv_error(s
, "netlink socket");
545 log_warnx("netlink", "should have received something, but didn't");
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 */
554 if (rsize
> NETLINK_MAX_RECEIVE_BUFSIZE
) {
555 rsize
= NETLINK_MAX_RECEIVE_BUFSIZE
;
557 int rc
= netlink_socket_set_buffer_size(s
,
558 SO_RCVBUF
, "SO_RCVBUF",
561 cfg
->g_netlink
->nl_socket_recv_size
= 0;
563 cfg
->g_netlink
->nl_socket_recv_size
= rsize
;
564 if (rc
> 0 || rc
== -2) {
566 "netlink receive buffer too small, retry with larger one (%d)",
572 log_warn("netlink", "unable to receive netlink answer");
581 if (iov
.iov_len
< len
|| (rtnl_reply
.msg_flags
& MSG_TRUNC
)) {
584 /* Provided buffer is not large enough, enlarge it
585 * to size of len (which should be total length of the message)
588 tmp
= realloc(iov
.iov_base
, iov
.iov_len
);
590 log_warn("netlink", "not enough memory");
594 log_debug("netlink", "enlarge message size to %zu bytes", len
);
601 /* Buffer is big enough, do the actual reading */
606 for (msg
= (struct nlmsghdr
*)(void*)(iov
.iov_base
);
608 msg
= NLMSG_NEXT(msg
, len
)) {
609 if (!(msg
->nlmsg_flags
& NLM_F_MULTI
))
611 switch (msg
->nlmsg_type
) {
613 log_debug("netlink", "received done message");
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");
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;
631 if (msg
->nlmsg_type
== RTM_NEWLINK
) {
632 if (ifdold
== NULL
) {
633 log_debug("netlink", "interface %s is new",
635 TAILQ_INSERT_TAIL(ifs
, ifdnew
, next
);
637 log_debug("netlink", "interface %s/%s is updated",
638 ifdold
->name
, ifdnew
->name
);
639 netlink_merge(ifdold
, ifdnew
);
640 TAILQ_INSERT_AFTER(ifs
, ifdold
, ifdnew
, next
);
641 TAILQ_REMOVE(ifs
, ifdold
, next
);
642 interfaces_free_device(ifdold
);
645 if (ifdold
== NULL
) {
647 "removal request for %s, but no knowledge of it",
650 log_debug("netlink", "interface %s is to be removed",
652 TAILQ_REMOVE(ifs
, ifdold
, next
);
653 interfaces_free_device(ifdold
);
655 interfaces_free_device(ifdnew
);
659 interfaces_free_device(ifdnew
);
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");
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
,
675 sizeof(ifaold
->address
))) break;
677 if (getnameinfo((struct sockaddr
*)&ifanew
->address
,
678 sizeof(ifanew
->address
),
680 NULL
, 0, NI_NUMERICHOST
) != 0) {
681 strlcpy(addr
, "(unknown)", sizeof(addr
));
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
);
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
);
697 if (ifaold
== NULL
) {
699 "removal request for address of %s%%%d, but no knowledge of it",
700 addr
, ifanew
->index
);
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
);
707 interfaces_free_address(ifanew
);
710 interfaces_free_address(ifanew
);
715 "received unhandled message type %d (len: %d)",
716 msg
->nlmsg_type
, msg
->nlmsg_len
);
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
) {
729 "upper interface for %s is %s",
730 iface1
->name
, iface2
->name
);
731 iface1
->upper
= iface2
;
736 iface1
->upper
= NULL
;
738 iface1
->upper
= NULL
;
740 if (iface1
->lower_idx
!= -1 && iface1
->lower_idx
!= iface1
->index
) {
741 TAILQ_FOREACH(iface2
, ifs
, next
) {
742 if (iface1
->lower_idx
== iface2
->index
) {
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
751 if (iface2
->lower_idx
== iface1
->index
) {
752 iface1
->lower
= NULL
;
754 "link loop detected between %s(%d) and %s(%d)",
761 "lower interface for %s is %s",
762 iface1
->name
, iface2
->name
);
763 iface1
->lower
= iface2
;
768 iface1
->lower
= NULL
;
771 iface1
->lower
= NULL
;
782 netlink_group_mask(int group
)
784 return group
? (1 << (group
- 1)) : 0;
788 * Subscribe to link changes.
790 * @return 0 on success, -1 otherwise
793 netlink_subscribe_changes(struct lldpd
*cfg
)
797 log_debug("netlink", "listening on interface changes");
799 groups
= netlink_group_mask(RTNLGRP_LINK
) |
800 netlink_group_mask(RTNLGRP_IPV4_IFADDR
) |
801 netlink_group_mask(RTNLGRP_IPV6_IFADDR
);
803 return netlink_connect(cfg
, NETLINK_ROUTE
, groups
);
807 * Receive changes from netlink */
809 netlink_change_cb(struct lldpd
*cfg
)
811 if (cfg
->g_netlink
== NULL
)
814 cfg
->g_netlink
->devices
,
815 cfg
->g_netlink
->addresses
);
819 * Initialize netlink subsystem.
821 * This can be called several times but will have effect only the first time.
823 * @return 0 on success, -1 otherwise
826 netlink_initialize(struct lldpd
*cfg
)
829 struct interfaces_device
*iff
;
832 if (cfg
->g_netlink
) return 0;
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");
840 /* Connect to netlink (by requesting to get notified on updates) and
841 * request updated information right now */
842 if (netlink_subscribe_changes(cfg
) == -1)
845 struct interfaces_address_list
*ifaddrs
= cfg
->g_netlink
->addresses
=
846 malloc(sizeof(struct interfaces_address_list
));
847 if (ifaddrs
== NULL
) {
848 log_warn("netlink", "not enough memory for address list");
853 struct interfaces_device_list
*ifs
= cfg
->g_netlink
->devices
=
854 malloc(sizeof(struct interfaces_device_list
));
856 log_warn("netlink", "not enough memory for interface list");
861 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETADDR
, AF_UNSPEC
, 1) == -1)
863 netlink_recv(cfg
, NULL
, ifaddrs
);
864 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETLINK
, AF_PACKET
, 2) == -1)
866 netlink_recv(cfg
, ifs
, NULL
);
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)
874 netlink_recv(cfg
, ifs
, NULL
);
880 /* Listen to any future change */
881 cfg
->g_iface_cb
= netlink_change_cb
;
882 if (levent_iface_subscribe(cfg
, cfg
->g_netlink
->nl_socket
) == -1) {
888 netlink_cleanup(cfg
);
893 * Cleanup netlink subsystem.
896 netlink_cleanup(struct lldpd
*cfg
)
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
);
904 free(cfg
->g_netlink
);
905 cfg
->g_netlink
= NULL
;
909 * Receive the list of interfaces.
911 * @return a list of interfaces.
913 struct interfaces_device_list
*
914 netlink_get_interfaces(struct lldpd
*cfg
)
916 if (netlink_initialize(cfg
) == -1) return NULL
;
917 struct interfaces_device
*ifd
;
918 TAILQ_FOREACH(ifd
, cfg
->g_netlink
->devices
, next
) {
921 return cfg
->g_netlink
->devices
;
925 * Receive the list of addresses.
927 * @return a list of addresses.
929 struct interfaces_address_list
*
930 netlink_get_addresses(struct lldpd
*cfg
)
932 if (netlink_initialize(cfg
) == -1) return NULL
;
933 return cfg
->g_netlink
->addresses
;