ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+Files: libnl/*
+Copyright: Copyright (c) Thomas Graf <tgraf@suug.ch>
+ Baruch Even <baruch@ev-en.org>
+ Petr Gotthard <petr.gotthard@siemens.com>
+ Siemens AG Oesterreich
+ Philip Craig <philipc@snapgear.com>
+ Patrick McHardy <kaber@trash.net>
+ Secure Computing Corporation
+License: LGPL-2.1
+ This library is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published
+ by the Free Software Foundation version 2.1 of the License.
+ .
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+ .
+ On Debian GNU/Linux systems, the complete text of the GNU Lesser General
+ Public License can be found in /usr/share/common-licenses/LGPL-2.1
+Comment:
+ The content of this directory is shipped with lldpd but not used for
+ compilation. The system libnl3 is used in place of this embedded
+ copy.
+
+Files: libnl/src/idiag-socket-details.c
+ libnl/src/lib/utils.c
+ libnl/src/nl-addr-add.c
+ libnl/src/nl-addr-delete.c
+ libnl/src/nl-addr-list.c
+ libnl/src/nl-cls-add.c
+ libnl/src/nl-addr-add.c
+Copyright: (c) 2013 Sassano Systems LLC <joe@sassanosystems.com>
+ (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
+License: GPL-2
+Comment:
+ Those files are userland tools part of libnl-3. They are never
+ compiled.
+
+Files: libnl/include/linux-private/linux/*
+Copyright: 1991-2012 Linus Torvalds and many others
+License: GPL-2
+Comment:
+ It is believed that header files are an interface for user space and
+ therefore cannot be covered by copyright.
+
+License: GPL-2
+ This package is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+ .
+ This package is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this package; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ .
+ On Debian systems, the complete text of the GNU General Public
+ License version 2 can be found in `/usr/share/common-licenses/GPL-2'.
+
+Files: libnl/include/netlink/xfrm/selector.h
+ libnl/include/netlink/xfrm/sa.h
+ libnl/include/netlink/xfrm/ae.h
+ libnl/include/netlink/xfrm/sp.h
+ libnl/include/netlink/xfrm/template.h
+ libnl/include/netlink/xfrm/lifetime.h
+ libnl/lib/xfrm/sa.c
+ libnl/lib/xfrm/template.c
+ libnl/lib/xfrm/ae.c
+ libnl/lib/xfrm/sp.c
+ libnl/lib/xfrm/selector.c
+ libnl/lib/xfrm/lifetime.c
+Copyright: Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
+License: BSD-3-clause
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ .
+ Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ .
+ Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the
+ distribution.
+ .
+ Neither the name of Texas Instruments Incorporated nor the names of
+ its contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
Files: libevent/*
Copyright: Copyright 2000-2007 Niels Provos <provos@citi.umich.edu>
Copyright 2007-2012 Niels Provos and Nick Mathewson
#include "lldpd.h"
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
+#include <asm/types.h>
#include <sys/socket.h>
-#include <net/if_arp.h>
#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-#define NETLINK_BUFFER 4096
-
-struct netlink_req {
- struct nlmsghdr hdr;
- struct rtgenmsg gen;
+#include <net/if_arp.h>
+#include <netlink/socket.h>
+#include <netlink/route/addr.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vlan.h>
+
+struct lldpd_netlink {
+ struct nl_cache_mngr *mngr;
+ struct nl_cache *addr;
+ struct nl_cache *link;
};
/**
- * Connect to netlink.
- *
- * Open a Netlink socket and connect to it.
- *
- * @param protocol Which protocol to use (eg NETLINK_ROUTE).
- * @param groups Which groups we want to subscribe to
- * @return The opened socket or -1 on error.
+ * Callback when we get netlink updates.
*/
-static int
-netlink_connect(int protocol, unsigned groups)
+static void
+netlink_change_cb(struct lldpd *cfg)
{
- int s;
- struct sockaddr_nl local = {
- .nl_family = AF_NETLINK,
- .nl_pid = getpid(),
- .nl_groups = groups
- };
-
- /* Open Netlink socket */
- log_debug("netlink", "opening netlink socket");
- s = socket(AF_NETLINK, SOCK_RAW, protocol);
- if (s == -1) {
- log_warn("netlink", "unable to open netlink socket");
- return -1;
- }
- if (groups && bind(s, (struct sockaddr *)&local, sizeof(struct sockaddr_nl)) < 0) {
- log_warn("netlink", "unable to bind netlink socket");
- close(s);
- return -1;
- }
- return s;
+ int err;
+ log_debug("netlink", "netlink update received");
+ if ((err = nl_cache_mngr_data_ready(cfg->g_netlink->mngr)) < 0) {
+ log_warn("netlink", "unable to parse incoming netlink messages: %s",
+ nl_geterror(err));
+ }
}
/**
- * Send a netlink message.
+ * Initialize netlink subsystem.
*
- * The type of the message can be chosen as well the route family. The
- * mesage will always be NLM_F_REQUEST | NLM_F_DUMP.
+ * This can be called several times but will have effect only the first time.
*
- * @param s the netlink socket
- * @param type the request type (eg RTM_GETLINK)
- * @param family the rt family (eg AF_PACKET)
* @return 0 on success, -1 otherwise
*/
static int
-netlink_send(int s, int type, int family)
+netlink_initialize(struct lldpd *cfg)
{
- struct netlink_req req = {
- .hdr = {
- .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
- .nlmsg_type = type,
- .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
- .nlmsg_seq = 1,
- .nlmsg_pid = getpid() },
- .gen = { .rtgen_family = family }
- };
- struct iovec iov = {
- .iov_base = &req,
- .iov_len = req.hdr.nlmsg_len
- };
- struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
- struct msghdr rtnl_msg = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_name = &peer,
- .msg_namelen = sizeof(struct sockaddr_nl)
- };
-
- /* Send netlink message. This is synchronous but we are guaranteed
- * to not block. */
- log_debug("netlink", "sending netlink message");
- if (sendmsg(s, (struct msghdr *)&rtnl_msg, 0) == -1) {
- log_warn("netlink", "unable to send netlink message");
- return -1;
- }
-
- return 0;
-}
+ int err;
+ if (cfg->g_netlink) return 0;
-static void
-netlink_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
-{
- while (RTA_OK(rta, len)) {
- if ((rta->rta_type <= max) && (!tb[rta->rta_type]))
- tb[rta->rta_type] = rta;
- rta = RTA_NEXT(rta,len);
+ log_debug("netlink", "initialize netlink subsystem");
+ if ((cfg->g_netlink = calloc(sizeof(struct lldpd_netlink), 1)) == NULL) {
+ log_warn("netlink", "unable to allocate memory for netlink subsystem");
+ goto end;
}
-}
-/**
- * Parse a `linkinfo` attributes.
- *
- * @param iff where to put the result
- * @param rta linkinfo attribute
- * @param len length of attributes
- */
-static void
-netlink_parse_linkinfo(struct interfaces_device *iff, struct rtattr *rta, int len)
-{
- struct rtattr *link_info_attrs[IFLA_INFO_MAX+1] = {};
- char *kind = NULL;
-
- netlink_parse_rtattr(link_info_attrs, IFLA_INFO_MAX, rta, len);
-
- if (link_info_attrs[IFLA_INFO_KIND]) {
- kind = strdup(RTA_DATA(link_info_attrs[IFLA_INFO_KIND]));
- if (kind) {
- if (!strcmp(kind, "vlan")) {
- log_debug("netlink", "interface %s is a VLAN",
- iff->name);
- iff->type |= IFACE_VLAN_T;
- } else if (!strcmp(kind, "bridge")) {
- log_debug("netlink", "interface %s is a bridge",
- iff->name);
- iff->type |= IFACE_BRIDGE_T;
- } else if (!strcmp(kind, "bond")) {
- log_debug("netlink", "interface %s is a bond",
- iff->name);
- iff->type |= IFACE_BOND_T;
- }
- }
+ if ((err = nl_cache_mngr_alloc(NULL, NETLINK_ROUTE, NL_AUTO_PROVIDE,
+ &cfg->g_netlink->mngr)) < 0) {
+ log_warn("netlink", "unable to allocate cache manager: %s",
+ nl_geterror(err));
+ goto end;
}
- if (kind && !strcmp(kind, "vlan") && link_info_attrs[IFLA_INFO_DATA]) {
- struct rtattr *vlan_link_info_data_attrs[IFLA_VLAN_MAX+1] = {};
- netlink_parse_rtattr(vlan_link_info_data_attrs, IFLA_VLAN_MAX,
- RTA_DATA(link_info_attrs[IFLA_INFO_DATA]),
- RTA_PAYLOAD(link_info_attrs[IFLA_INFO_DATA]));
+ if ((err = nl_cache_mngr_add(cfg->g_netlink->mngr,
+ "route/link", NULL, NULL, &cfg->g_netlink->link)) < 0) {
+ log_warn("netlink", "unable to allocate route/link cache");
+ goto end;
+ }
+ if ((err = nl_cache_mngr_add(cfg->g_netlink->mngr,
+ "route/addr", NULL, NULL, &cfg->g_netlink->addr)) < 0) {
+ log_warn("netlink", "unable to allocate route/addr cache");
+ goto end;
+ }
- if (vlan_link_info_data_attrs[IFLA_VLAN_ID]) {
- iff->vlanid = *(uint16_t *)RTA_DATA(vlan_link_info_data_attrs[IFLA_VLAN_ID]);
- log_debug("netlink", "VLAN ID for interface %s is %d",
- iff->name, iff->vlanid);
- }
+ cfg->g_iface_cb = netlink_change_cb;
+ if (levent_iface_subscribe(cfg, nl_cache_mngr_get_fd(cfg->g_netlink->mngr)) == -1) {
+ goto end;
}
- free(kind);
+ return 0;
+end:
+ netlink_cleanup(cfg);
+ return -1;
}
/**
- * Parse a `link` netlink message.
- *
- * @param msg message to be parsed
- * @param iff where to put the result
- * return 0 if the interface is worth it, -1 otherwise
+ * Cleanup netlink subsystem.
*/
-static int
-netlink_parse_link(struct nlmsghdr *msg,
- struct interfaces_device *iff)
+void
+netlink_cleanup(struct lldpd *cfg)
{
- struct ifinfomsg *ifi;
- struct rtattr *attribute;
- int len;
- ifi = NLMSG_DATA(msg);
- len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
-
- if (!((ifi->ifi_flags & IFF_UP) && (ifi->ifi_flags & IFF_RUNNING))) {
- log_debug("netlink", "skip down interface at index %d",
- ifi->ifi_index);
- return -1;
- }
- if (ifi->ifi_type != ARPHRD_ETHER) {
- log_debug("netlink", "skip non Ethernet interface at index %d",
- ifi->ifi_index);
- return -1;
- }
-
- iff->index = ifi->ifi_index;
- iff->flags = ifi->ifi_flags;
- iff->lower_idx = -1;
- iff->upper_idx = -1;
-
- for (attribute = IFLA_RTA(ifi);
- RTA_OK(attribute, len);
- attribute = RTA_NEXT(attribute, len)) {
- switch(attribute->rta_type) {
- case IFLA_IFNAME:
- /* Interface name */
- iff->name = strdup(RTA_DATA(attribute));
- break;
- case IFLA_IFALIAS:
- /* Interface alias */
- iff->alias = strdup(RTA_DATA(attribute));
- break;
- case IFLA_ADDRESS:
- /* Interface MAC address */
- iff->address = malloc(RTA_PAYLOAD(attribute));
- if (iff->address)
- memcpy(iff->address, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
- break;
- case IFLA_LINK:
- /* Index of "lower" interface */
- iff->lower_idx = *(int*)RTA_DATA(attribute);
- break;
- case IFLA_MASTER:
- /* Index of master interface */
- iff->upper_idx = *(int*)RTA_DATA(attribute);
- break;
- case IFLA_TXQLEN:
- /* Transmit queue length */
- iff->txqueue = *(int*)RTA_DATA(attribute);
- break;
- case IFLA_MTU:
- /* Maximum Transmission Unit */
- iff->mtu = *(int*)RTA_DATA(attribute);
- break;
- case IFLA_LINKINFO:
- netlink_parse_linkinfo(iff, RTA_DATA(attribute), RTA_PAYLOAD(attribute));
- break;
- default:
- log_debug("netlink", "unhandled link attribute type %d for iface %s",
- attribute->rta_type, iff->name ? iff->name : "(unknown)");
- break;
- }
- }
- if (!iff->name || !iff->address) {
- log_info("netlink", "interface %d does not have a name or an address, skip",
- iff->index);
- return -1;
- }
- return 0;
+ if (cfg->g_netlink == NULL) return;
+ if (cfg->g_netlink->mngr != NULL) nl_cache_mngr_free(cfg->g_netlink->mngr);
+
+ free(cfg->g_netlink);
+ cfg->g_netlink = NULL;
}
/**
- * Parse a `address` netlink message.
+ * Parse a `link` netlink message.
*
- * @param msg message to be parsed
- * @param ifa where to put the result
- * return 0 if the address is worth it, -1 otherwise
+ * @param link link object from cache
+ * @return parsed interface
*/
-static int
-netlink_parse_address(struct nlmsghdr *msg,
- struct interfaces_address *ifa)
+static struct interfaces_device *
+netlink_parse_link(struct rtnl_link *link)
{
- struct ifaddrmsg *ifi;
- struct rtattr *attribute;
- int len;
- ifi = NLMSG_DATA(msg);
- len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg));
-
- ifa->index = ifi->ifa_index;
- ifa->flags = ifi->ifa_flags;
- switch (ifi->ifa_family) {
- case AF_INET:
- case AF_INET6: break;
- default:
- log_debug("netlink", "got a non IP address on if %d (family: %d)",
- ifa->index, ifi->ifa_family);
- return -1;
- }
-
- for (attribute = IFA_RTA(ifi);
- RTA_OK(attribute, len);
- attribute = RTA_NEXT(attribute, len)) {
- switch(attribute->rta_type) {
- case IFA_ADDRESS:
- /* Address */
- if (ifi->ifa_family == AF_INET) {
- struct sockaddr_in ip = { .sin_family = AF_INET };
- memcpy(&ip.sin_addr, RTA_DATA(attribute),
- sizeof(struct in_addr));
- memcpy(&ifa->address, &ip, sizeof(struct sockaddr_in));
- } else {
- struct sockaddr_in6 ip6 = { .sin6_family = AF_INET6 };
- memcpy(&ip6.sin6_addr, RTA_DATA(attribute),
- sizeof(struct in6_addr));
- memcpy(&ifa->address, &ip6, sizeof(struct sockaddr_in6));
- }
- break;
- default:
- log_debug("netlink", "unhandled address attribute type %d for iface %d",
- attribute->rta_type, ifa->index);
- break;
- }
- }
- if (ifa->address.ss_family == AF_UNSPEC) {
- log_debug("netlink", "no IP for interface %d",
- ifa->index);
- return -1;
- }
- return 0;
+ const char *name = rtnl_link_get_name(link);
+ if (name == NULL) {
+ log_debug("netlink", "skip unnamed interface");
+ return NULL;
+ }
+
+ unsigned int flags = rtnl_link_get_flags(link);
+ if (!((flags & IFF_UP) && (flags & IFF_RUNNING))) {
+ log_debug("netlink", "skip down interface %s", name);
+ return NULL;
+ }
+ if (rtnl_link_get_arptype(link) != ARPHRD_ETHER) {
+ log_debug("netlink", "skip non Ethernet interface %s", name);
+ return NULL;
+ }
+
+ struct interfaces_device *iff = calloc(1, sizeof(struct interfaces_device));
+ if (iff == NULL) {
+ log_warn("netlink", "no memory for a new interface");
+ return NULL;
+ }
+ iff->index = rtnl_link_get_ifindex(link);;
+ iff->flags = flags;
+ iff->lower_idx = rtnl_link_get_link(link);
+ iff->upper_idx = rtnl_link_get_master(link);
+ iff->name = strdup(name);
+ if (rtnl_link_get_ifalias(link) != NULL)
+ iff->alias = strdup(rtnl_link_get_ifalias(link));
+
+ struct nl_addr *mac = rtnl_link_get_addr(link);
+ if (mac) {
+ iff->address = malloc(nl_addr_get_len(mac));
+ if (iff->address)
+ memcpy(iff->address,
+ nl_addr_get_binary_addr(mac),
+ nl_addr_get_len(mac));
+ }
+ if (!iff->address) {
+ log_info("netlink", "interface %d does not have a name or an address, skip",
+ iff->index);
+ interfaces_free_device(iff);
+ return NULL;
+ }
+ iff->txqueue = rtnl_link_get_txqlen(link);
+ iff->mtu = rtnl_link_get_mtu(link);
+
+ const char *kind = rtnl_link_get_type(link);
+ if (kind) {
+ if (!strcmp(kind, "vlan")) {
+ iff->type |= IFACE_VLAN_T;
+ iff->vlanid = rtnl_link_vlan_get_id(link);
+ log_debug("netlink", "interface %s is a VLAN (id=%d)",
+ name, iff->vlanid);
+ } else if (!strcmp(kind, "bridge")) {
+ iff->type |= IFACE_BRIDGE_T;
+ log_debug("netlink", "interface %s is a bridge",
+ name);
+ } else if (!strcmp(kind, "bond")) {
+ iff->type |= IFACE_BOND_T;
+ log_debug("netlink", "interface %s is a bond",
+ name);
+ }
+ }
+
+ return iff;
}
/**
- * Receive netlink answer from the kernel.
+ * Parse a `address` netlink message.
*
- * @param s the netlink socket
- * @param ifs list to store interface list or NULL if we don't
- * @param ifas list to store address list or NULL if we don't
- * @return 0 on success, -1 on error
+ * @param addr address object from cache
+ * @return parsed address
*/
-static int
-netlink_recv(int s,
- struct interfaces_device_list *ifs,
- struct interfaces_address_list *ifas)
+static struct interfaces_address *
+netlink_parse_address(struct rtnl_addr *addr)
{
- char reply[NETLINK_BUFFER] __attribute__ ((aligned));
- int end = 0;
-
- struct interfaces_device *iff;
- struct interfaces_address *ifa;
-
- while (!end) {
- int len;
- struct nlmsghdr *msg;
- struct iovec iov = {
- .iov_base = reply,
- .iov_len = NETLINK_BUFFER
- };
- struct sockaddr_nl peer = { .nl_family = AF_NETLINK };
- struct msghdr rtnl_reply = {
- .msg_iov = &iov,
- .msg_iovlen = 1,
- .msg_name = &peer,
- .msg_namelen = sizeof(struct sockaddr_nl)
- };
-
- len = recvmsg(s, &rtnl_reply, 0);
- if (len == -1) {
- log_warnx("netlink", "unable to receive netlink answer");
- return -1;
- }
- if (!len) return 0;
- for (msg = (struct nlmsghdr*)(void*)reply;
- NLMSG_OK(msg, len);
- msg = NLMSG_NEXT(msg, len)) {
- switch (msg->nlmsg_type) {
- case NLMSG_DONE:
- log_debug("netlink", "received end of dump message");
- end = 1;
- break;
- case RTM_NEWLINK:
- if (!ifs) break;
- log_debug("netlink", "received link information");
- iff = calloc(1, sizeof(struct interfaces_device));
- if (iff == NULL) {
- log_warn("netlink", "not enough memory for another interface, give what we have");
- return 0;
- }
- if (netlink_parse_link(msg, iff) == 0)
- TAILQ_INSERT_TAIL(ifs, iff, next);
- else
- interfaces_free_device(iff);
- break;
- case RTM_NEWADDR:
- if (!ifas) break;
- log_debug("netlink", "received address information");
- ifa = calloc(1, sizeof(struct interfaces_address));
- if (ifa == NULL) {
- log_warn("netlink", "not enough memory for another address, give what we have");
- return 0;
- }
- if (netlink_parse_address(msg, ifa) == 0)
- TAILQ_INSERT_TAIL(ifas, ifa, next);
- else
- interfaces_free_address(ifa);
- break;
- default:
- log_debug("netlink",
- "received unhandled message type %d (len: %d)",
- msg->nlmsg_type, msg->nlmsg_len);
- }
- }
- }
- return 0;
+ int family = rtnl_addr_get_family(addr);
+ switch (family) {
+ case AF_INET:
+ case AF_INET6: break;
+ default:
+ log_debug("netlink", "got a non IP address on if %d (family: %d)",
+ rtnl_addr_get_ifindex(addr), family);
+ return NULL;
+ }
+
+ struct interfaces_address *ifa = calloc(1, sizeof(struct interfaces_address));
+ if (ifa == NULL) {
+ log_warn("netlink", "no memory for a new address");
+ return NULL;
+ }
+ ifa->index = rtnl_addr_get_ifindex(addr);
+ ifa->flags = rtnl_addr_get_flags(addr);
+
+ socklen_t len = sizeof(ifa->address);
+ int err = nl_addr_fill_sockaddr(rtnl_addr_get_local(addr),
+ (struct sockaddr *)&ifa->address, &len);
+ if (err < 0 || ifa->address.ss_family == AF_UNSPEC) {
+ log_debug("netlink", "no IP for interface %d",
+ ifa->index);
+ interfaces_free_address(ifa);
+ return NULL;
+ }
+ return ifa;
}
/**
* @return a list of interfaces.
*/
struct interfaces_device_list*
-netlink_get_interfaces()
+netlink_get_interfaces(struct lldpd *cfg)
{
- int s;
- struct interfaces_device_list *ifs;
- struct interfaces_device *iface1, *iface2;
-
- if ((s = netlink_connect(NETLINK_ROUTE, 0)) == -1)
- return NULL;
- if (netlink_send(s, RTM_GETLINK, AF_PACKET) == -1) {
- close(s);
- return NULL;
- }
-
- log_debug("netlink", "get the list of available interfaces");
- ifs = malloc(sizeof(struct interfaces_device_list));
- if (ifs == NULL) {
- log_warn("netlink", "not enough memory for interface list");
- close(s);
- return NULL;
- }
- TAILQ_INIT(ifs);
- netlink_recv(s, ifs, NULL);
-
- /* Fill out lower/upper */
- TAILQ_FOREACH(iface1, ifs, next) {
- if (iface1->upper_idx != -1 && iface1->upper_idx != iface1->index)
- TAILQ_FOREACH(iface2, ifs, next) {
- if (iface1->upper_idx == iface2->index) {
- iface1->upper = iface2;
- break;
- }
- }
- if (iface1->lower_idx != -1 && iface1->lower_idx != iface1->index)
- TAILQ_FOREACH(iface2, ifs, next) {
- if (iface1->lower_idx == iface2->index) {
- iface1->lower = iface2;
- break;
- }
- }
- }
-
- close(s);
- return ifs;
+ if (netlink_initialize(cfg) == -1) return NULL;
+
+ struct interfaces_device_list *ifs;
+
+ log_debug("netlink", "get the list of available interfaces");
+ ifs = malloc(sizeof(struct interfaces_device_list));
+ if (ifs == NULL) {
+ log_warn("netlink", "not enough memory for interface list");
+ return NULL;
+ }
+ TAILQ_INIT(ifs);
+
+ for (struct nl_object *link = nl_cache_get_first(cfg->g_netlink->link);
+ link != NULL;
+ link = nl_cache_get_next(link)) {
+ nl_object_get(link);
+ struct interfaces_device *iff = netlink_parse_link((struct rtnl_link *)link);
+ if (iff) TAILQ_INSERT_TAIL(ifs, iff, next);
+ nl_object_put(link);
+ }
+
+ struct interfaces_device *iface1, *iface2;
+ TAILQ_FOREACH(iface1, ifs, next) {
+ if (iface1->upper_idx != 0 && iface1->upper_idx != iface1->index)
+ TAILQ_FOREACH(iface2, ifs, next) {
+ if (iface1->upper_idx == iface2->index) {
+ log_debug("netlink", "%s is upper iface for %s",
+ iface2->name, iface1->name);
+ iface1->upper = iface2;
+ break;
+ }
+ }
+ if (iface1->lower_idx != 0 && iface1->lower_idx != iface1->index)
+ TAILQ_FOREACH(iface2, ifs, next) {
+ if (iface1->lower_idx == iface2->index) {
+ log_debug("netlink", "%s is lower iface for %s",
+ iface2->name, iface1->name);
+ iface1->lower = iface2;
+ break;
+ }
+ }
+ }
+
+ return ifs;
}
/**
* @return a list of addresses.
*/
struct interfaces_address_list*
-netlink_get_addresses()
+netlink_get_addresses(struct lldpd *cfg)
{
- int s;
- struct interfaces_address_list *ifaddrs;
-
- if ((s = netlink_connect(NETLINK_ROUTE, 0)) == -1)
- return NULL;
- if (netlink_send(s, RTM_GETADDR, AF_UNSPEC) == -1) {
- close(s);
- return NULL;
- }
-
- log_debug("netlink", "get the list of available addresses");
- ifaddrs = malloc(sizeof(struct interfaces_address_list));
- if (ifaddrs == NULL) {
- log_warn("netlink", "not enough memory for address list");
- close(s);
- return NULL;
- }
- TAILQ_INIT(ifaddrs);
- netlink_recv(s, NULL, ifaddrs);
-
- close(s);
- return ifaddrs;
-}
+ if (netlink_initialize(cfg) == -1) return NULL;
-static int
-netlink_group_mask(int group)
-{
- return group ? (1 << (group - 1)) : 0;
-}
+ struct interfaces_address_list *ifaddrs;
-/**
- * Subscribe to link changes.
- *
- * @return The socket we should listen to for changes.
- */
-int
-netlink_subscribe_changes()
-{
- unsigned int groups;
-
- log_debug("netlink", "listening on interface changes");
-
- groups = netlink_group_mask(RTNLGRP_LINK) |
- netlink_group_mask(RTNLGRP_IPV4_IFADDR) |
- netlink_group_mask(RTNLGRP_IPV6_IFADDR);
+ log_debug("netlink", "get the list of available addresses");
+ ifaddrs = malloc(sizeof(struct interfaces_address_list));
+ if (ifaddrs == NULL) {
+ log_warn("netlink", "not enough memory for address list");
+ return NULL;
+ }
+ TAILQ_INIT(ifaddrs);
+
+ for (struct nl_object *addr = nl_cache_get_first(cfg->g_netlink->addr);
+ addr != NULL;
+ addr = nl_cache_get_next(addr)) {
+ nl_object_get(addr);
+ struct interfaces_address *ifa = netlink_parse_address((struct rtnl_addr *)addr);
+ if (ifa) TAILQ_INSERT_TAIL(ifaddrs, ifa, next);
+ nl_object_put(addr);
+ }
- return netlink_connect(NETLINK_ROUTE, groups);
+ return ifaddrs;
}