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
= sizeof(struct netlink_req
),
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 /* request bridge vlan attributes */
169 req
.ext_req
.rta_type
= IFLA_EXT_MASK
;
170 req
.ext_req
.rta_len
= RTA_LENGTH(sizeof(__u32
));
171 req
.ext_filter_mask
= RTEXT_FILTER_BRVLAN
;
174 /* Send netlink message. This is synchronous but we are guaranteed
176 log_debug("netlink", "sending netlink message");
177 if (sendmsg(s
, (struct msghdr
*)&rtnl_msg
, 0) == -1) {
178 log_warn("netlink", "unable to send netlink message");
186 netlink_parse_rtattr(struct rtattr
*tb
[], int max
, struct rtattr
*rta
, int len
)
188 while (RTA_OK(rta
, len
)) {
189 if ((rta
->rta_type
<= max
) && (!tb
[rta
->rta_type
]))
190 tb
[rta
->rta_type
] = rta
;
191 rta
= RTA_NEXT(rta
,len
);
196 * Parse a `linkinfo` attributes.
198 * @param iff where to put the result
199 * @param rta linkinfo attribute
200 * @param len length of attributes
203 netlink_parse_linkinfo(struct interfaces_device
*iff
, struct rtattr
*rta
, int len
)
205 struct rtattr
*link_info_attrs
[IFLA_INFO_MAX
+1] = {};
208 netlink_parse_rtattr(link_info_attrs
, IFLA_INFO_MAX
, rta
, len
);
210 if (link_info_attrs
[IFLA_INFO_KIND
]) {
211 kind
= strdup(RTA_DATA(link_info_attrs
[IFLA_INFO_KIND
]));
213 if (!strcmp(kind
, "vlan")) {
214 log_debug("netlink", "interface %s is a VLAN",
216 iff
->type
|= IFACE_VLAN_T
;
217 } else if (!strcmp(kind
, "bridge")) {
218 log_debug("netlink", "interface %s is a bridge",
220 iff
->type
|= IFACE_BRIDGE_T
;
221 } else if (!strcmp(kind
, "bond")) {
222 log_debug("netlink", "interface %s is a bond",
224 iff
->type
|= IFACE_BOND_T
;
225 } else if (!strcmp(kind
, "team")) {
226 log_debug("netlink", "interface %s is a team",
228 iff
->type
|= IFACE_BOND_T
;
233 if (kind
&& !strcmp(kind
, "vlan") && link_info_attrs
[IFLA_INFO_DATA
]) {
234 struct rtattr
*vlan_link_info_data_attrs
[IFLA_VLAN_MAX
+1] = {};
235 netlink_parse_rtattr(vlan_link_info_data_attrs
, IFLA_VLAN_MAX
,
236 RTA_DATA(link_info_attrs
[IFLA_INFO_DATA
]),
237 RTA_PAYLOAD(link_info_attrs
[IFLA_INFO_DATA
]));
239 if (vlan_link_info_data_attrs
[IFLA_VLAN_ID
]) {
240 iff
->vlanids
[0] = *(uint16_t *)RTA_DATA(vlan_link_info_data_attrs
[IFLA_VLAN_ID
]);
241 log_debug("netlink", "VLAN ID for interface %s is %d",
242 iff
->name
, iff
->vlanids
[0]);
250 * Parse a `afspec` attributes.
252 * @param iff where to put the result
253 * @param rta afspec attribute
254 * @param len length of attributes
257 netlink_parse_afspec(struct interfaces_device
*iff
, struct rtattr
*rta
, int len
)
260 while (RTA_OK(rta
, len
)) {
261 struct bridge_vlan_info
*vinfo
;
262 switch (rta
->rta_type
) {
263 case IFLA_BRIDGE_VLAN_INFO
:
264 vinfo
= RTA_DATA(rta
);
265 log_debug("netlink", "found VLAN %d on interface %s",
266 vinfo
->vid
, iff
->name
? iff
->name
: "(unknown)");
267 if (i
>= sizeof(iff
->vlanids
)/sizeof(iff
->vlanids
[0])) {
268 log_info("netlink", "too many VLANs on interface %s",
269 iff
->name
? iff
->name
: "(unknown)");
272 iff
->vlanids
[i
++] = vinfo
->vid
;
273 if (vinfo
->flags
& (BRIDGE_VLAN_INFO_PVID
| BRIDGE_VLAN_INFO_UNTAGGED
))
274 iff
->pvid
= vinfo
->vid
;
277 log_debug("netlink", "unknown afspec attribute type %d for iface %s",
278 rta
->rta_type
, iff
->name
? iff
->name
: "(unknown)");
281 rta
= RTA_NEXT(rta
, len
);
283 /* All enbridged interfaces will have VLAN 1 by default, ignore it */
284 if (iff
->vlanids
[0] == 1 && iff
->vlanids
[1] == 0 && iff
->pvid
== 1) {
285 log_debug("netlink", "found only default VLAN 1 on interface %s, removing",
286 iff
->name
? iff
->name
: "(unknown)");
287 iff
->vlanids
[0] = iff
->pvid
= 0;
292 * Parse a `link` netlink message.
294 * @param msg message to be parsed
295 * @param iff where to put the result
296 * return 0 if the interface is worth it, -1 otherwise
299 netlink_parse_link(struct nlmsghdr
*msg
,
300 struct interfaces_device
*iff
)
302 struct ifinfomsg
*ifi
;
303 struct rtattr
*attribute
;
305 ifi
= NLMSG_DATA(msg
);
306 len
= msg
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct ifinfomsg
));
308 if (ifi
->ifi_type
!= ARPHRD_ETHER
) {
309 log_debug("netlink", "skip non Ethernet interface at index %d",
314 iff
->index
= ifi
->ifi_index
;
315 iff
->flags
= ifi
->ifi_flags
;
319 for (attribute
= IFLA_RTA(ifi
);
320 RTA_OK(attribute
, len
);
321 attribute
= RTA_NEXT(attribute
, len
)) {
322 switch(attribute
->rta_type
) {
325 iff
->name
= strdup(RTA_DATA(attribute
));
328 /* Interface alias */
329 iff
->alias
= strdup(RTA_DATA(attribute
));
332 /* Interface MAC address */
333 iff
->address
= malloc(RTA_PAYLOAD(attribute
));
335 memcpy(iff
->address
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
338 /* Index of "lower" interface */
339 if (iff
->lower_idx
== -1) {
340 iff
->lower_idx
= *(int*)RTA_DATA(attribute
);
341 log_debug("netlink", "attribute IFLA_LINK for %s: %d",
342 iff
->name
? iff
->name
: "(unknown)", iff
->lower_idx
);
344 log_debug("netlink", "attribute IFLA_LINK for %s: %d (ignored)",
345 iff
->name
? iff
->name
: "(unknown)", iff
->lower_idx
);
348 case IFLA_LINK_NETNSID
:
349 /* Is the lower interface into another namesapce? */
351 log_debug("netlink", "attribute IFLA_LINK_NETNSID received for %s",
352 iff
->name
? iff
->name
: "(unknown)");
355 /* Index of master interface */
356 iff
->upper_idx
= *(int*)RTA_DATA(attribute
);
359 /* Maximum Transmission Unit */
360 iff
->mtu
= *(int*)RTA_DATA(attribute
);
363 netlink_parse_linkinfo(iff
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
366 if (ifi
->ifi_family
!= AF_BRIDGE
) break;
367 netlink_parse_afspec(iff
, RTA_DATA(attribute
), RTA_PAYLOAD(attribute
));
370 log_debug("netlink", "unhandled link attribute type %d for iface %s",
371 attribute
->rta_type
, iff
->name
? iff
->name
: "(unknown)");
375 if (!iff
->name
|| !iff
->address
) {
376 log_info("netlink", "interface %d does not have a name or an address, skip",
380 if (iff
->upper_idx
== -1) {
381 /* No upper interface, we cannot be enslaved. We need to clear
382 * the flag because the appropriate information may come later
383 * and we don't want to miss it. */
384 iff
->flags
&= ~IFF_SLAVE
;
386 if (iff
->lower_idx
== -2)
389 if (ifi
->ifi_family
== AF_BRIDGE
&& msg
->nlmsg_type
== RTM_DELLINK
&& iff
->upper_idx
!= -1) {
390 log_debug("netlink", "removal of %s from bridge %d",
391 iff
->name
, iff
->upper_idx
);
392 msg
->nlmsg_type
= RTM_NEWLINK
;
396 log_debug("netlink", "parsed link %d (%s, flags: %d)",
397 iff
->index
, iff
->name
, iff
->flags
);
402 * Parse a `address` netlink message.
404 * @param msg message to be parsed
405 * @param ifa where to put the result
406 * return 0 if the address is worth it, -1 otherwise
409 netlink_parse_address(struct nlmsghdr
*msg
,
410 struct interfaces_address
*ifa
)
412 struct ifaddrmsg
*ifi
;
413 struct rtattr
*attribute
;
415 ifi
= NLMSG_DATA(msg
);
416 len
= msg
->nlmsg_len
- NLMSG_LENGTH(sizeof(struct ifaddrmsg
));
418 ifa
->index
= ifi
->ifa_index
;
419 ifa
->flags
= ifi
->ifa_flags
;
420 switch (ifi
->ifa_family
) {
422 case AF_INET6
: break;
424 log_debug("netlink", "got a non IP address on if %d (family: %d)",
425 ifa
->index
, ifi
->ifa_family
);
429 for (attribute
= IFA_RTA(ifi
);
430 RTA_OK(attribute
, len
);
431 attribute
= RTA_NEXT(attribute
, len
)) {
432 switch(attribute
->rta_type
) {
435 if (ifi
->ifa_family
== AF_INET
) {
436 struct sockaddr_in ip
;
437 memset(&ip
, 0, sizeof(struct sockaddr_in
));
438 ip
.sin_family
= AF_INET
;
439 memcpy(&ip
.sin_addr
, RTA_DATA(attribute
),
440 sizeof(struct in_addr
));
441 memcpy(&ifa
->address
, &ip
, sizeof(struct sockaddr_in
));
443 struct sockaddr_in6 ip6
;
444 memset(&ip6
, 0, sizeof(struct sockaddr_in6
));
445 ip6
.sin6_family
= AF_INET6
;
446 memcpy(&ip6
.sin6_addr
, RTA_DATA(attribute
),
447 sizeof(struct in6_addr
));
448 memcpy(&ifa
->address
, &ip6
, sizeof(struct sockaddr_in6
));
452 log_debug("netlink", "unhandled address attribute type %d for iface %d",
453 attribute
->rta_type
, ifa
->index
);
457 if (ifa
->address
.ss_family
== AF_UNSPEC
) {
458 log_debug("netlink", "no IP for interface %d",
466 * Merge an old interface with a new one.
468 * Some properties may be absent in the new interface that should be copied over
472 netlink_merge(struct interfaces_device
*old
, struct interfaces_device
*new)
474 if (new->alias
== NULL
) {
475 new->alias
= old
->alias
;
478 if (new->address
== NULL
) {
479 new->address
= old
->address
;
485 new->type
= old
->type
;
486 if (new->vlanids
[0] == 0 && new->type
== IFACE_VLAN_T
)
487 new->vlanids
[0] = old
->vlanids
[0];
489 /* It's not possible for lower link to change */
490 new->lower_idx
= old
->lower_idx
;
494 * Receive netlink answer from the kernel.
496 * @param ifs list to store interface list or NULL if we don't
497 * @param ifas list to store address list or NULL if we don't
498 * @return 0 on success, -1 on error
501 netlink_recv(struct lldpd
*cfg
,
502 struct interfaces_device_list
*ifs
,
503 struct interfaces_address_list
*ifas
)
505 int end
= 0, ret
= 0, flags
, retry
= 0;
508 int s
= cfg
->g_netlink
->nl_socket
;
510 struct interfaces_device
*ifdold
;
511 struct interfaces_device
*ifdnew
;
512 struct interfaces_address
*ifaold
;
513 struct interfaces_address
*ifanew
;
514 char addr
[INET6_ADDRSTRLEN
+ 1];
516 iov
.iov_len
= NETLINK_BUFFER
;
517 iov
.iov_base
= malloc(iov
.iov_len
);
519 log_warn("netlink", "not enough memory");
525 struct nlmsghdr
*msg
;
526 struct sockaddr_nl peer
= { .nl_family
= AF_NETLINK
};
527 struct msghdr rtnl_reply
= {
531 .msg_namelen
= sizeof(struct sockaddr_nl
)
533 flags
= MSG_PEEK
| MSG_TRUNC
;
535 len
= recvmsg(s
, &rtnl_reply
, flags
);
537 if (errno
== EAGAIN
|| errno
== EWOULDBLOCK
) {
539 levent_recv_error(s
, "netlink socket");
542 log_warnx("netlink", "should have received something, but didn't");
546 int rsize
= cfg
->g_netlink
->nl_socket_recv_size
;
547 if (errno
== ENOBUFS
&&
548 rsize
> 0 && rsize
< NETLINK_MAX_RECEIVE_BUFSIZE
) {
549 /* Try to increase buffer size */
551 if (rsize
> NETLINK_MAX_RECEIVE_BUFSIZE
) {
552 rsize
= NETLINK_MAX_RECEIVE_BUFSIZE
;
554 int rc
= netlink_socket_set_buffer_size(s
,
555 SO_RCVBUF
, "SO_RCVBUF",
558 cfg
->g_netlink
->nl_socket_recv_size
= 0;
560 cfg
->g_netlink
->nl_socket_recv_size
= rsize
;
561 if (rc
> 0 || rc
== -2) {
563 "netlink receive buffer too small, retry with larger one (%d)",
569 log_warn("netlink", "unable to receive netlink answer");
578 if (iov
.iov_len
< len
|| (rtnl_reply
.msg_flags
& MSG_TRUNC
)) {
581 /* Provided buffer is not large enough, enlarge it
582 * to size of len (which should be total length of the message)
585 tmp
= realloc(iov
.iov_base
, iov
.iov_len
);
587 log_warn("netlink", "not enough memory");
591 log_debug("netlink", "enlarge message size to %zu bytes", len
);
598 /* Buffer is big enough, do the actual reading */
603 for (msg
= (struct nlmsghdr
*)(void*)(iov
.iov_base
);
605 msg
= NLMSG_NEXT(msg
, len
)) {
606 if (!(msg
->nlmsg_flags
& NLM_F_MULTI
))
608 switch (msg
->nlmsg_type
) {
610 log_debug("netlink", "received done message");
616 log_debug("netlink", "received link information");
617 ifdnew
= calloc(1, sizeof(struct interfaces_device
));
618 if (ifdnew
== NULL
) {
619 log_warn("netlink", "not enough memory for another interface, give up what we have");
622 if (netlink_parse_link(msg
, ifdnew
) == 0) {
623 /* We need to find if we already have this interface */
624 TAILQ_FOREACH(ifdold
, ifs
, next
) {
625 if (ifdold
->index
== ifdnew
->index
) break;
628 if (msg
->nlmsg_type
== RTM_NEWLINK
) {
629 if (ifdold
== NULL
) {
630 log_debug("netlink", "interface %s is new",
632 TAILQ_INSERT_TAIL(ifs
, ifdnew
, next
);
634 log_debug("netlink", "interface %s/%s is updated",
635 ifdold
->name
, ifdnew
->name
);
636 netlink_merge(ifdold
, ifdnew
);
637 TAILQ_INSERT_AFTER(ifs
, ifdold
, ifdnew
, next
);
638 TAILQ_REMOVE(ifs
, ifdold
, next
);
639 interfaces_free_device(ifdold
);
642 if (ifdold
== NULL
) {
644 "removal request for %s, but no knowledge of it",
647 log_debug("netlink", "interface %s is to be removed",
649 TAILQ_REMOVE(ifs
, ifdold
, next
);
650 interfaces_free_device(ifdold
);
652 interfaces_free_device(ifdnew
);
656 interfaces_free_device(ifdnew
);
662 log_debug("netlink", "received address information");
663 ifanew
= calloc(1, sizeof(struct interfaces_address
));
664 if (ifanew
== NULL
) {
665 log_warn("netlink", "not enough memory for another address, give what we have");
668 if (netlink_parse_address(msg
, ifanew
) == 0) {
669 TAILQ_FOREACH(ifaold
, ifas
, next
) {
670 if ((ifaold
->index
== ifanew
->index
) &&
671 !memcmp(&ifaold
->address
, &ifanew
->address
,
672 sizeof(ifaold
->address
))) break;
674 if (getnameinfo((struct sockaddr
*)&ifanew
->address
,
675 sizeof(ifanew
->address
),
677 NULL
, 0, NI_NUMERICHOST
) != 0) {
678 strlcpy(addr
, "(unknown)", sizeof(addr
));
681 if (msg
->nlmsg_type
== RTM_NEWADDR
) {
682 if (ifaold
== NULL
) {
683 log_debug("netlink", "new address %s%%%d",
684 addr
, ifanew
->index
);
685 TAILQ_INSERT_TAIL(ifas
, ifanew
, next
);
687 log_debug("netlink", "updated address %s%%%d",
688 addr
, ifaold
->index
);
689 TAILQ_INSERT_AFTER(ifas
, ifaold
, ifanew
, next
);
690 TAILQ_REMOVE(ifas
, ifaold
, next
);
691 interfaces_free_address(ifaold
);
694 if (ifaold
== NULL
) {
696 "removal request for address of %s%%%d, but no knowledge of it",
697 addr
, ifanew
->index
);
699 log_debug("netlink", "address %s%%%d is to be removed",
700 addr
, ifaold
->index
);
701 TAILQ_REMOVE(ifas
, ifaold
, next
);
702 interfaces_free_address(ifaold
);
704 interfaces_free_address(ifanew
);
707 interfaces_free_address(ifanew
);
712 "received unhandled message type %d (len: %d)",
713 msg
->nlmsg_type
, msg
->nlmsg_len
);
719 /* Fill out lower/upper */
720 struct interfaces_device
*iface1
, *iface2
;
721 TAILQ_FOREACH(iface1
, ifs
, next
) {
722 if (iface1
->upper_idx
!= -1 && iface1
->upper_idx
!= iface1
->index
) {
723 TAILQ_FOREACH(iface2
, ifs
, next
) {
724 if (iface1
->upper_idx
== iface2
->index
) {
726 "upper interface for %s is %s",
727 iface1
->name
, iface2
->name
);
728 iface1
->upper
= iface2
;
733 iface1
->upper
= NULL
;
735 iface1
->upper
= NULL
;
737 if (iface1
->lower_idx
!= -1 && iface1
->lower_idx
!= iface1
->index
) {
738 TAILQ_FOREACH(iface2
, ifs
, next
) {
739 if (iface1
->lower_idx
== iface2
->index
) {
740 /* Workaround a bug introduced
741 * in Linux 4.1: a pair of veth
742 * will be lower interface of
743 * each other. Do not modify
744 * index as if one of them is
745 * updated, we will loose the
746 * information about the
748 if (iface2
->lower_idx
== iface1
->index
) {
749 iface1
->lower
= NULL
;
751 "link loop detected between %s(%d) and %s(%d)",
758 "lower interface for %s is %s",
759 iface1
->name
, iface2
->name
);
760 iface1
->lower
= iface2
;
765 iface1
->lower
= NULL
;
768 iface1
->lower
= NULL
;
779 netlink_group_mask(int group
)
781 return group
? (1 << (group
- 1)) : 0;
785 * Subscribe to link changes.
787 * @return 0 on success, -1 otherwise
790 netlink_subscribe_changes(struct lldpd
*cfg
)
794 log_debug("netlink", "listening on interface changes");
796 groups
= netlink_group_mask(RTNLGRP_LINK
) |
797 netlink_group_mask(RTNLGRP_IPV4_IFADDR
) |
798 netlink_group_mask(RTNLGRP_IPV6_IFADDR
);
800 return netlink_connect(cfg
, NETLINK_ROUTE
, groups
);
804 * Receive changes from netlink */
806 netlink_change_cb(struct lldpd
*cfg
)
808 if (cfg
->g_netlink
== NULL
)
811 cfg
->g_netlink
->devices
,
812 cfg
->g_netlink
->addresses
);
816 * Initialize netlink subsystem.
818 * This can be called several times but will have effect only the first time.
820 * @return 0 on success, -1 otherwise
823 netlink_initialize(struct lldpd
*cfg
)
826 struct interfaces_device
*iff
;
829 if (cfg
->g_netlink
) return 0;
831 log_debug("netlink", "initialize netlink subsystem");
832 if ((cfg
->g_netlink
= calloc(sizeof(struct lldpd_netlink
), 1)) == NULL
) {
833 log_warn("netlink", "unable to allocate memory for netlink subsystem");
837 /* Connect to netlink (by requesting to get notified on updates) and
838 * request updated information right now */
839 if (netlink_subscribe_changes(cfg
) == -1)
842 struct interfaces_address_list
*ifaddrs
= cfg
->g_netlink
->addresses
=
843 malloc(sizeof(struct interfaces_address_list
));
844 if (ifaddrs
== NULL
) {
845 log_warn("netlink", "not enough memory for address list");
850 struct interfaces_device_list
*ifs
= cfg
->g_netlink
->devices
=
851 malloc(sizeof(struct interfaces_device_list
));
853 log_warn("netlink", "not enough memory for interface list");
858 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETADDR
, AF_UNSPEC
, 1) == -1)
860 netlink_recv(cfg
, NULL
, ifaddrs
);
861 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETLINK
, AF_PACKET
, 2) == -1)
863 netlink_recv(cfg
, ifs
, NULL
);
865 /* If we have a bridge, search for VLAN-aware bridges */
866 TAILQ_FOREACH(iff
, ifs
, next
) {
867 if (iff
->type
& IFACE_BRIDGE_T
) {
868 log_debug("netlink", "interface %s is a bridge, check for VLANs", iff
->name
);
869 if (netlink_send(cfg
->g_netlink
->nl_socket
, RTM_GETLINK
, AF_BRIDGE
, 3) == -1)
871 netlink_recv(cfg
, ifs
, NULL
);
877 /* Listen to any future change */
878 cfg
->g_iface_cb
= netlink_change_cb
;
879 if (levent_iface_subscribe(cfg
, cfg
->g_netlink
->nl_socket
) == -1) {
885 netlink_cleanup(cfg
);
890 * Cleanup netlink subsystem.
893 netlink_cleanup(struct lldpd
*cfg
)
895 if (cfg
->g_netlink
== NULL
) return;
896 if (cfg
->g_netlink
->nl_socket
!= -1)
897 close(cfg
->g_netlink
->nl_socket
);
898 interfaces_free_devices(cfg
->g_netlink
->devices
);
899 interfaces_free_addresses(cfg
->g_netlink
->addresses
);
901 free(cfg
->g_netlink
);
902 cfg
->g_netlink
= NULL
;
906 * Receive the list of interfaces.
908 * @return a list of interfaces.
910 struct interfaces_device_list
*
911 netlink_get_interfaces(struct lldpd
*cfg
)
913 if (netlink_initialize(cfg
) == -1) return NULL
;
914 struct interfaces_device
*ifd
;
915 TAILQ_FOREACH(ifd
, cfg
->g_netlink
->devices
, next
) {
918 return cfg
->g_netlink
->devices
;
922 * Receive the list of addresses.
924 * @return a list of addresses.
926 struct interfaces_address_list
*
927 netlink_get_addresses(struct lldpd
*cfg
)
929 if (netlink_initialize(cfg
) == -1) return NULL
;
930 return cfg
->g_netlink
->addresses
;