first enabled protocol will be used when no neighbor is detected.
+ Allow to filter debug logs using tokens. Add more debug logs.
+ lldpctl can now output JSON.
+ + Use netlink to gather interface information.
lldpd (0.6.1)
* Features:
1. If your system does not use standard Linux interface, you can
support additional interfaces by implementing the appropriate
- `struct lldpd_ops`. You can look at `src/daemon/interfaces.c` for
- examples. You also need to implement an interface handler which is
- a function that will take care of some interface (including the
- regular ones if they need special treatment). This handler will be
- responsible to instantiate the appropriate `struct lldpd_hardware`
- structure and associate it to the appropriate `struct
- lldpd_ops`. Again, there are examples in
- `src/daemon/interfaces.c`. The handler should be added to the list
- of handlers in `src/daemon/lldpd.c` in
- `lldpd_update_localports()`.
+ `struct lldpd_ops`. You can look at
+ `src/daemon/interfaces-linux.c` for examples. Also, have a look at
+ `interfaces_update()` which is responsible for discovering and
+ registering interfaces.
2. `lldpctl` provides a convenient way to query `lldpd`. It also
comes with various outputs, including XML which allows one to
AX_LDFLAGS_OPTION([-Wl,-z,relro])
AX_LDFLAGS_OPTION([-Wl,-z,now])
+# OS
+lldp_CHECK_OS
+
AC_CACHE_SAVE
# Checks for header files.
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_REPLACE_FUNCS([strlcpy])
-AC_REPLACE_FUNCS([getifaddrs])
AC_CACHE_SAVE
## Unit tests wich check
--- /dev/null
+#
+# lldp_CHECK_OS
+#
+# List of supported OS.
+#
+AC_DEFUN([lldp_DEFINE_OS], [dnl
+ case $host_os in
+ $1)
+ os="$2"
+ AC_DEFINE_UNQUOTED(HOST_OS_$3, 1, [Host operating system is $2])
+ ;;
+ esac
+ AM_CONDITIONAL(HOST_OS_$3, test x$os = x$2)dnl
+])
+
+AC_DEFUN([lldp_CHECK_OS], [
+ AC_CANONICAL_HOST
+ AC_MSG_CHECKING([if host OS is supported])
+
+ lldp_DEFINE_OS(linux*, Linux, LINUX)
+
+ if test x$os = x; then
+ AC_MSG_RESULT(no)
+ AC_MSG_ERROR([*** unsupported OS $host_os])
+ fi
+ AC_MSG_RESULT([yes ($os)])
+])
#define GET_VLAN_VID_CMD (GET_VLAN_REALDEV_NAME_CMD + 1)
#endif
-#if !HAVE_GETIFADDRS
-struct ifaddrs {
- struct ifaddrs *ifa_next; /* Next item in list */
- char *ifa_name; /* Name of interface */
- unsigned int ifa_flags; /* Flags from SIOCGIFFLAGS */
- struct sockaddr *ifa_addr; /* Address of interface */
- struct sockaddr *ifa_netmask; /* Netmask of interface */
- /* At most one of the following two is valid. If the IFF_BROADCAST
- bit is set in `ifa_flags', then `ifa_broadaddr' is valid. If the
- IFF_POINTOPOINT bit is set, then `ifa_dstaddr' is valid.
- It is never the case that both these bits are set at once. */
- union {
- struct sockaddr *ifu_broadaddr;
- /* Broadcast address of interface */
- struct sockaddr *ifu_dstaddr;
- /* Point-to-point destination address */
- } ifa_ifu;
-# ifndef ifa_broadaddr
-# define ifa_broadaddr ifa_ifu.ifu_broadaddr
-# endif
-# ifndef ifa_dstaddr
-# define ifa_dstaddr ifa_ifu.ifu_dstaddr
-# endif
- void *ifa_data; /* Address-specific data */
-};
-
-int getifaddrs(struct ifaddrs **ifap);
-void freeifaddrs(struct ifaddrs *ifa);
-#endif
-
#if !HAVE_STRLCPY
size_t strlcpy(char *, const char *, size_t);
#endif
+++ /dev/null
-/* -*- mode: c; c-file-style: "openbsd" -*- */
-/* Stolen from:
- http://www.linux-ipv6.org/cvsweb/usagi/usagi/libinet6/ifaddrs.c?rev=1.17.4.2;content-type=text%2Fplain
-*/
-
-/* $USAGI: ifaddrs.c,v 1.17.4.2 2002-12-08 08:22:22 yoshfuji Exp $ */
-
-/**************************************************************************
- * ifaddrs.c
- * Copyright (C)2000 Hideaki YOSHIFUJI, All Rights Reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. 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.
- * 3. Neither the name of the author 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 AUTHOR 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 AUTHOR 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.
- */
-
-#include "compat.h"
-
-/* For compatibility */
-#undef IFA_NETMASK
-#undef HAVE_IFADDRS_IFA_ANYCAST
-#undef HAVE_SOCKADDR_SA_LEN
-#define __set_errno(X) errno = (X)
-#define __close(X) close(X)
-
-#include <string.h>
-#include <time.h>
-#include <malloc.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <sys/socket.h>
-#include <asm/types.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netpacket/packet.h>
-#include <net/ethernet.h> /* the L2 protocols */
-#include <sys/uio.h>
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <netinet/in.h>
-
-/* ====================================================================== */
-struct nlmsg_list{
- struct nlmsg_list *nlm_next;
- struct nlmsghdr *nlh;
- int size;
- time_t seq;
-};
-
-struct rtmaddr_ifamap {
- void *address;
- void *local;
-#ifdef IFA_NETMASK
- void *netmask;
-#endif
- void *broadcast;
-#ifdef HAVE_IFADDRS_IFA_ANYCAST
- void *anycast;
-#endif
- int address_len;
- int local_len;
-#ifdef IFA_NETMASK
- int netmask_len;
-#endif
- int broadcast_len;
-#ifdef HAVE_IFADDRS_IFA_ANYCAST
- int anycast_len;
-#endif
-};
-
-/* ====================================================================== */
-static size_t
-ifa_sa_len(sa_family_t family, int len)
-{
- size_t size;
- switch(family){
- case AF_INET:
- size = sizeof(struct sockaddr_in);
- break;
- case AF_INET6:
- size = sizeof(struct sockaddr_in6);
- break;
- case AF_PACKET:
- size = (size_t)(((struct sockaddr_ll *)NULL)->sll_addr) + len;
- if (size < sizeof(struct sockaddr_ll))
- size = sizeof(struct sockaddr_ll);
- break;
- default:
- size = (size_t)(((struct sockaddr *)NULL)->sa_data) + len;
- if (size < sizeof(struct sockaddr))
- size = sizeof(struct sockaddr);
- }
- return size;
-}
-
-static void
-ifa_make_sockaddr(sa_family_t family,
- struct sockaddr *sa,
- void *p, size_t len,
- uint32_t scope, uint32_t scopeid)
-{
- if (sa == NULL) return;
- switch(family){
- case AF_INET:
- memcpy(&((struct sockaddr_in*)sa)->sin_addr, (char *)p, len);
- break;
- case AF_INET6:
- memcpy(&((struct sockaddr_in6*)sa)->sin6_addr, (char *)p, len);
- if (IN6_IS_ADDR_LINKLOCAL(p) ||
- IN6_IS_ADDR_MC_LINKLOCAL(p)){
- ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
- }
- break;
- case AF_PACKET:
- memcpy(((struct sockaddr_ll*)sa)->sll_addr, (char *)p, len);
- ((struct sockaddr_ll*)sa)->sll_halen = len;
- break;
- default:
- memcpy(sa->sa_data, p, len); /*XXX*/
- break;
- }
- sa->sa_family = family;
-#ifdef HAVE_SOCKADDR_SA_LEN
- sa->sa_len = ifa_sa_len(family, len);
-#endif
-}
-
-static struct sockaddr *
-ifa_make_sockaddr_mask(sa_family_t family,
- struct sockaddr *sa,
- uint32_t prefixlen)
-{
- int i;
- char *p = NULL, c;
- uint32_t max_prefixlen = 0;
-
- if (sa == NULL) return NULL;
- switch(family){
- case AF_INET:
- memset(&((struct sockaddr_in*)sa)->sin_addr, 0, sizeof(((struct sockaddr_in*)sa)->sin_addr));
- p = (char *)&((struct sockaddr_in*)sa)->sin_addr;
- max_prefixlen = 32;
- break;
- case AF_INET6:
- memset(&((struct sockaddr_in6*)sa)->sin6_addr, 0, sizeof(((struct sockaddr_in6*)sa)->sin6_addr));
- p = (char *)&((struct sockaddr_in6*)sa)->sin6_addr;
-#if 0 /* XXX: fill scope-id? */
- if (IN6_IS_ADDR_LINKLOCAL(p) ||
- IN6_IS_ADDR_MC_LINKLOCAL(p)){
- ((struct sockaddr_in6*)sa)->sin6_scope_id = scopeid;
- }
-#endif
- max_prefixlen = 128;
- break;
- default:
- return NULL;
- }
- sa->sa_family = family;
-#ifdef HAVE_SOCKADDR_SA_LEN
- sa->sa_len = ifa_sa_len(family, len);
-#endif
- if (p){
- if (prefixlen > max_prefixlen)
- prefixlen = max_prefixlen;
- for (i=0; i<(prefixlen / 8); i++)
- *p++ = 0xff;
- c = 0xff;
- c <<= (8 - (prefixlen % 8));
- *p = c;
- }
- return sa;
-}
-
-/* ====================================================================== */
-static int
-nl_sendreq(int sd, int request, int flags, int *seq)
-{
- char reqbuf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
- NLMSG_ALIGN(sizeof(struct rtgenmsg))];
- struct sockaddr_nl nladdr;
- struct nlmsghdr *req_hdr;
- struct rtgenmsg *req_msg;
- time_t t = time(NULL);
-
- if (seq) *seq = t;
- memset(&reqbuf, 0, sizeof(reqbuf));
- req_hdr = (struct nlmsghdr *)reqbuf;
- req_msg = (struct rtgenmsg *)NLMSG_DATA(req_hdr);
- req_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*req_msg));
- req_hdr->nlmsg_type = request;
- req_hdr->nlmsg_flags = flags | NLM_F_REQUEST;
- req_hdr->nlmsg_pid = 0;
- req_hdr->nlmsg_seq = t;
- req_msg->rtgen_family = AF_UNSPEC;
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
- return (sendto(sd, (void *)req_hdr, req_hdr->nlmsg_len, 0,
- (struct sockaddr *)&nladdr, sizeof(nladdr)));
-}
-
-static int
-nl_recvmsg(int sd, int request, int seq,
- void *buf, size_t buflen,
- int *flags)
-{
- struct msghdr msg;
- struct iovec iov = { buf, buflen };
- struct sockaddr_nl nladdr;
- int read_len;
-
- for (;;){
- msg.msg_name = (void *)&nladdr;
- msg.msg_namelen = sizeof(nladdr);
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- msg.msg_flags = 0;
- read_len = recvmsg(sd, &msg, 0);
- if ((read_len < 0 && errno == EINTR) || (msg.msg_flags & MSG_TRUNC))
- continue;
- if (flags) *flags = msg.msg_flags;
- break;
- }
- return read_len;
-}
-
-static int
-nl_getmsg(int sd, int request, int seq,
- struct nlmsghdr **nlhp,
- int *done)
-{
- struct nlmsghdr *nh;
- size_t bufsize = 65536, lastbufsize = 0;
- void *buff = NULL;
- int result = 0, read_size;
- int msg_flags;
- pid_t pid = getpid();
- for (;;){
- void *newbuff = realloc(buff, bufsize);
- if (newbuff == NULL || bufsize < lastbufsize) {
- result = -1;
- break;
- }
- buff = newbuff;
- result = read_size = nl_recvmsg(sd, request, seq, buff, bufsize, &msg_flags);
- if (read_size < 0 || (msg_flags & MSG_TRUNC)){
- lastbufsize = bufsize;
- bufsize *= 2;
- continue;
- }
- if (read_size == 0) break;
- nh = (struct nlmsghdr *)buff;
- for (nh = (struct nlmsghdr *)buff;
- NLMSG_OK(nh, read_size);
- nh = (struct nlmsghdr *)NLMSG_NEXT(nh, read_size)){
- if (nh->nlmsg_pid != pid ||
- nh->nlmsg_seq != seq)
- continue;
- if (nh->nlmsg_type == NLMSG_DONE){
- (*done)++;
- break; /* ok */
- }
- if (nh->nlmsg_type == NLMSG_ERROR){
- struct nlmsgerr *nlerr = (struct nlmsgerr *)NLMSG_DATA(nh);
- result = -1;
- if (nh->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
- __set_errno(EIO);
- else
- __set_errno(-nlerr->error);
- break;
- }
- }
- break;
- }
- if (result < 0)
- if (buff){
- int saved_errno = errno;
- free(buff);
- __set_errno(saved_errno);
- }
- *nlhp = (struct nlmsghdr *)buff;
- return result;
-}
-
-static int
-nl_getlist(int sd, int seq,
- int request,
- struct nlmsg_list **nlm_list,
- struct nlmsg_list **nlm_end)
-{
- struct nlmsghdr *nlh = NULL;
- int status;
- int done = 0;
-
- status = nl_sendreq(sd, request, NLM_F_ROOT|NLM_F_MATCH, &seq);
- if (status < 0)
- return status;
- if (seq == 0)
- seq = (int)time(NULL);
- while(!done){
- status = nl_getmsg(sd, request, seq, &nlh, &done);
- if (status < 0)
- return status;
- if (nlh){
- struct nlmsg_list *nlm_next = (struct nlmsg_list *)malloc(sizeof(struct nlmsg_list));
- if (nlm_next == NULL){
- int saved_errno = errno;
- free(nlh);
- __set_errno(saved_errno);
- status = -1;
- } else {
- nlm_next->nlm_next = NULL;
- nlm_next->nlh = (struct nlmsghdr *)nlh;
- nlm_next->size = status;
- nlm_next->seq = seq;
- if (*nlm_list == NULL){
- *nlm_list = nlm_next;
- *nlm_end = nlm_next;
- } else {
- (*nlm_end)->nlm_next = nlm_next;
- *nlm_end = nlm_next;
- }
- }
- }
- }
- return status >= 0 ? seq : status;
-}
-
-/* ---------------------------------------------------------------------- */
-static void
-free_nlmsglist(struct nlmsg_list *nlm0)
-{
- struct nlmsg_list *nlm, *nlm_next;
- int saved_errno;
- if (!nlm0)
- return;
- saved_errno = errno;
- nlm = nlm0;
- while (nlm)
- {
- if (nlm->nlh)
- free(nlm->nlh);
- nlm_next = nlm->nlm_next;
- free(nlm);
- nlm = nlm_next;
- }
- __set_errno(saved_errno);
-}
-
-static void
-free_data(void *data, void *ifdata)
-{
- int saved_errno = errno;
- if (data != NULL) free(data);
- if (ifdata != NULL) free(ifdata);
- __set_errno(saved_errno);
-}
-
-/* ---------------------------------------------------------------------- */
-static void
-nl_close(int sd)
-{
- int saved_errno = errno;
- if (sd >= 0) __close(sd);
- __set_errno(saved_errno);
-}
-
-/* ---------------------------------------------------------------------- */
-static int
-nl_open(void)
-{
- struct sockaddr_nl nladdr;
- int sd;
-
- sd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (sd < 0) return -1;
- memset(&nladdr, 0, sizeof(nladdr));
- nladdr.nl_family = AF_NETLINK;
- if (bind(sd, (struct sockaddr*)&nladdr, sizeof(nladdr)) < 0){
- nl_close(sd);
- return -1;
- }
- return sd;
-}
-
-/* ====================================================================== */
-int getifaddrs(struct ifaddrs **ifap)
-{
- int sd;
- struct nlmsg_list *nlmsg_list, *nlmsg_end, *nlm;
- /* - - - - - - - - - - - - - - - */
- int icnt;
- size_t dlen, xlen, nlen;
- uint32_t max_ifindex = 0;
-
- pid_t pid = getpid();
- int seq;
- int build ; /* 0 or 1 */
-
-/* ---------------------------------- */
- /* initialize */
- icnt = dlen = xlen = nlen = 0;
- nlmsg_list = nlmsg_end = NULL;
-
- if (ifap)
- *ifap = NULL;
-
-/* ---------------------------------- */
- /* open socket and bind */
- sd = nl_open();
- if (sd < 0)
- return -1;
-
-/* ---------------------------------- */
- /* gather info */
- if ((seq = nl_getlist(sd, 0, RTM_GETLINK,
- &nlmsg_list, &nlmsg_end)) < 0){
- free_nlmsglist(nlmsg_list);
- nl_close(sd);
- return -1;
- }
- if ((seq = nl_getlist(sd, seq+1, RTM_GETADDR,
- &nlmsg_list, &nlmsg_end)) < 0){
- free_nlmsglist(nlmsg_list);
- nl_close(sd);
- return -1;
- }
-
-/* ---------------------------------- */
- /* Estimate size of result buffer and fill it */
- for (build=0; build<=1; build++){
- struct ifaddrs *ifl = NULL, *ifa = NULL;
- struct nlmsghdr *nlh, *nlh0;
- void *data = NULL, *xdata = NULL, *ifdata = NULL;
- char *ifname = NULL, **iflist = NULL;
- uint16_t *ifflist = NULL;
- struct rtmaddr_ifamap ifamap;
-
- if (build){
- ifa = data = calloc(1,
- NLMSG_ALIGN(sizeof(struct ifaddrs[icnt]))
- + dlen + xlen + nlen);
- ifdata = calloc(1,
- NLMSG_ALIGN(sizeof(char *[max_ifindex+1]))
- + NLMSG_ALIGN(sizeof(uint16_t [max_ifindex+1])));
- if (ifap != NULL)
- *ifap = (ifdata != NULL) ? ifa : NULL;
- else{
- free_data(data, ifdata);
- break;
- }
- if (data == NULL || ifdata == NULL){
- free_data(data, ifdata);
- break;
- }
- ifl = NULL;
- data += NLMSG_ALIGN(sizeof(struct ifaddrs)) * icnt;
- xdata = data + dlen;
- ifname = xdata + xlen;
- iflist = ifdata;
- ifflist = ((void *)iflist) + NLMSG_ALIGN(sizeof(char *[max_ifindex+1]));
- }
-
- for (nlm=nlmsg_list; nlm; nlm=nlm->nlm_next){
- int nlmlen = nlm->size;
- if (!(nlh0 = nlm->nlh))
- continue;
- for (nlh = nlh0;
- NLMSG_OK(nlh, nlmlen);
- nlh=NLMSG_NEXT(nlh,nlmlen)){
- struct ifinfomsg *ifim = NULL;
- struct ifaddrmsg *ifam = NULL;
- struct rtattr *rta;
-
- size_t nlm_struct_size = 0;
- sa_family_t nlm_family = 0;
- uint32_t nlm_scope = 0, nlm_index = 0;
-#ifndef IFA_NETMASK
- size_t sockaddr_size = 0;
- uint32_t nlm_prefixlen = 0;
-#endif
- size_t rtasize;
-
- memset(&ifamap, 0, sizeof(ifamap));
-
- /* check if the message is what we want */
- if (nlh->nlmsg_pid != pid ||
- nlh->nlmsg_seq != nlm->seq)
- continue;
- if (nlh->nlmsg_type == NLMSG_DONE){
- break; /* ok */
- }
- switch (nlh->nlmsg_type){
- case RTM_NEWLINK:
- ifim = (struct ifinfomsg *)NLMSG_DATA(nlh);
- nlm_struct_size = sizeof(*ifim);
- nlm_family = ifim->ifi_family;
- nlm_scope = 0;
- nlm_index = ifim->ifi_index;
- nlm_prefixlen = 0;
- if (build)
- ifflist[nlm_index] = ifa->ifa_flags = ifim->ifi_flags;
- break;
- case RTM_NEWADDR:
- ifam = (struct ifaddrmsg *)NLMSG_DATA(nlh);
- nlm_struct_size = sizeof(*ifam);
- nlm_family = ifam->ifa_family;
- nlm_scope = ifam->ifa_scope;
- nlm_index = ifam->ifa_index;
- nlm_prefixlen = ifam->ifa_prefixlen;
- if (build)
- ifa->ifa_flags = ifflist[nlm_index];
- break;
- default:
- continue;
- }
-
- if (!build){
- if (max_ifindex < nlm_index)
- max_ifindex = nlm_index;
- } else {
- if (ifl != NULL)
- ifl->ifa_next = ifa;
- }
-
- rtasize = NLMSG_PAYLOAD(nlh, nlmlen) - NLMSG_ALIGN(nlm_struct_size);
- for (rta = (struct rtattr *)(((char *)NLMSG_DATA(nlh)) + NLMSG_ALIGN(nlm_struct_size));
- RTA_OK(rta, rtasize);
- rta = RTA_NEXT(rta, rtasize)){
- struct sockaddr **sap = NULL;
- void *rtadata = RTA_DATA(rta);
- size_t rtapayload = RTA_PAYLOAD(rta);
- socklen_t sa_len;
-
- switch(nlh->nlmsg_type){
- case RTM_NEWLINK:
- switch(rta->rta_type){
- case IFLA_ADDRESS:
- case IFLA_BROADCAST:
- if (build){
- sap = (rta->rta_type == IFLA_ADDRESS) ? &ifa->ifa_addr : &ifa->ifa_broadaddr;
- *sap = (struct sockaddr *)data;
- }
- sa_len = ifa_sa_len(AF_PACKET, rtapayload);
- if (rta->rta_type == IFLA_ADDRESS)
- sockaddr_size = NLMSG_ALIGN(sa_len);
- if (!build){
- dlen += NLMSG_ALIGN(sa_len);
- } else {
- memset(*sap, 0, sa_len);
- ifa_make_sockaddr(AF_PACKET, *sap, rtadata,rtapayload, 0,0);
- ((struct sockaddr_ll *)*sap)->sll_ifindex = nlm_index;
- ((struct sockaddr_ll *)*sap)->sll_hatype = ifim->ifi_type;
- data += NLMSG_ALIGN(sa_len);
- }
- break;
- case IFLA_IFNAME:/* Name of Interface */
- if (!build)
- nlen += NLMSG_ALIGN(rtapayload + 1);
- else{
- ifa->ifa_name = ifname;
- if (iflist[nlm_index] == NULL)
- iflist[nlm_index] = ifa->ifa_name;
- strncpy(ifa->ifa_name, rtadata, rtapayload);
- ifa->ifa_name[rtapayload] = '\0';
- ifname += NLMSG_ALIGN(rtapayload + 1);
- }
- break;
- case IFLA_STATS:/* Statistics of Interface */
- if (!build)
- xlen += NLMSG_ALIGN(rtapayload);
- else{
- ifa->ifa_data = xdata;
- memcpy(ifa->ifa_data, rtadata, rtapayload);
- xdata += NLMSG_ALIGN(rtapayload);
- }
- break;
- case IFLA_UNSPEC:
- break;
- case IFLA_MTU:
- break;
- case IFLA_LINK:
- break;
- case IFLA_QDISC:
- break;
- }
- break;
- case RTM_NEWADDR:
- if (nlm_family == AF_PACKET) break;
- switch(rta->rta_type){
- case IFA_ADDRESS:
- ifamap.address = rtadata;
- ifamap.address_len = rtapayload;
- break;
- case IFA_LOCAL:
- ifamap.local = rtadata;
- ifamap.local_len = rtapayload;
- break;
- case IFA_BROADCAST:
- ifamap.broadcast = rtadata;
- ifamap.broadcast_len = rtapayload;
- break;
-#ifdef HAVE_IFADDRS_IFA_ANYCAST
- case IFA_ANYCAST:
- ifamap.anycast = rtadata;
- ifamap.anycast_len = rtapayload;
- break;
-#endif
- case IFA_LABEL:
- if (!build)
- nlen += NLMSG_ALIGN(rtapayload + 1);
- else{
- ifa->ifa_name = ifname;
- if (iflist[nlm_index] == NULL)
- iflist[nlm_index] = ifname;
- strncpy(ifa->ifa_name, rtadata, rtapayload);
- ifa->ifa_name[rtapayload] = '\0';
- ifname += NLMSG_ALIGN(rtapayload + 1);
- }
- break;
- case IFA_UNSPEC:
- break;
- case IFA_CACHEINFO:
- break;
- }
- }
- }
- if (nlh->nlmsg_type == RTM_NEWADDR &&
- nlm_family != AF_PACKET) {
- if (!ifamap.local) {
- ifamap.local = ifamap.address;
- ifamap.local_len = ifamap.address_len;
- }
- if (!ifamap.address) {
- ifamap.address = ifamap.local;
- ifamap.address_len = ifamap.local_len;
- }
- if (ifamap.address_len != ifamap.local_len ||
- (ifamap.address != NULL &&
- memcmp(ifamap.address, ifamap.local, ifamap.address_len))) {
- /* p2p; address is peer and local is ours */
- ifamap.broadcast = ifamap.address;
- ifamap.broadcast_len = ifamap.address_len;
- ifamap.address = ifamap.local;
- ifamap.address_len = ifamap.local_len;
- }
- if (ifamap.address) {
-#ifndef IFA_NETMASK
- sockaddr_size = NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
-#endif
- if (!build)
- dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.address_len));
- else {
- ifa->ifa_addr = (struct sockaddr *)data;
- ifa_make_sockaddr(nlm_family, ifa->ifa_addr, ifamap.address, ifamap.address_len,
- nlm_scope, nlm_index);
- data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.address_len));
- }
- }
-#ifdef IFA_NETMASK
- if (ifamap.netmask) {
- if (!build)
- dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.netmask_len));
- else {
- ifa->ifa_netmask = (struct sockaddr *)data;
- ifa_make_sockaddr(nlm_family, ifa->ifa_netmask, ifamap.netmask, ifamap.netmask_len,
- nlm_scope, nlm_index);
- data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.netmask_len));
- }
- }
-#endif
- if (ifamap.broadcast) {
- if (!build)
- dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.broadcast_len));
- else {
- ifa->ifa_broadaddr = (struct sockaddr *)data;
- ifa_make_sockaddr(nlm_family, ifa->ifa_broadaddr, ifamap.broadcast, ifamap.broadcast_len,
- nlm_scope, nlm_index);
- data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.broadcast_len));
- }
- }
-#ifdef HAVE_IFADDRS_IFA_ANYCAST
- if (ifamap.anycast) {
- if (!build)
- dlen += NLMSG_ALIGN(ifa_sa_len(nlm_family,ifamap.anycast_len));
- else {
- ifa->ifa_anycast = (struct sockaddr *)data;
- ifa_make_sockaddr(nlm_family, ifa->ifa_anyaddr, ifamap.anycast, ifamap.anycast_len,
- nlm_scope, nlm_index);
- data += NLMSG_ALIGN(ifa_sa_len(nlm_family, ifamap.anycast_len));
- }
- }
-#endif
- }
- if (!build){
-#ifndef IFA_NETMASK
- dlen += sockaddr_size;
-#endif
- icnt++;
- } else {
- if (ifa->ifa_name == NULL)
- ifa->ifa_name = iflist[nlm_index];
-#ifndef IFA_NETMASK
- if (ifa->ifa_addr &&
- ifa->ifa_addr->sa_family != AF_UNSPEC &&
- ifa->ifa_addr->sa_family != AF_PACKET){
- ifa->ifa_netmask = (struct sockaddr *)data;
- ifa_make_sockaddr_mask(ifa->ifa_addr->sa_family, ifa->ifa_netmask, nlm_prefixlen);
- }
- data += sockaddr_size;
-#endif
- ifl = ifa++;
- }
- }
- }
- if (!build){
- if (icnt == 0 && (dlen + nlen + xlen == 0)){
- if (ifap != NULL)
- *ifap = NULL;
- break; /* cannot found any addresses */
- }
- }
- else
- free_data(NULL, ifdata);
- }
-
-/* ---------------------------------- */
- /* Finalize */
- free_nlmsglist(nlmsg_list);
- nl_close(sd);
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-void
-freeifaddrs(struct ifaddrs *ifa)
-{
- free(ifa);
-}
cdp.c cdp.h \
sonmp.c sonmp.h \
edp.c edp.h \
- interfaces.c client.c priv.c privsep_fdpass.c dmi.c \
+ client.c \
+ priv.c privsep_fdpass.c \
+ dmi.c \
event.c lldpd.c
liblldpd_la_CFLAGS = @LIBEVENT_CFLAGS@
liblldpd_la_LIBADD = \
$(top_builddir)/src/libcommon-daemon-client.la \
$(top_builddir)/src/libcommon-daemon-lib.la @LIBEVENT_LIBS@
+if HOST_OS_LINUX
+liblldpd_la_SOURCES += \
+ interfaces-linux.c \
+ netlink.c
+endif
+
# Add SNMP support if needed
if USE_SNMP
liblldpd_la_SOURCES += agent.c agent_priv.c agent.h
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define INCLUDE_LINUX_IF_H
#include "lldpd.h"
#include <unistd.h>
- asset: /sys/class/dmi/id/chassis_asset_tag
*/
-#if __i386__ || __amd64__
+#ifdef HOST_OS_LINUX
char*
dmi_get(char *file)
{
return strdup(buffer);
return NULL;
}
+#else
+char *
+dmi_get(char *file)
+{
+ return NULL;
+}
+#endif
+
char*
dmi_hw()
return dmi_get(SYSFS_CLASS_DMI "chassis_asset_tag");
}
#endif
-#endif
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#define INCLUDE_LINUX_IF_H
#include "lldpd.h"
#include <stdio.h>
#include <linux/sockios.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
+#include <linux/ethtool.h>
#define SYSFS_PATH_MAX 256
#define MAX_PORTS 1024
static struct sock_filter lldpd_filter_f[] = { LLDPD_FILTER_F };
-/* net/if.h */
-extern unsigned int if_nametoindex (__const char *__ifname) __THROW;
-extern char *if_indextoname (unsigned int __ifindex, char *__ifname) __THROW;
-
struct lldpd_ops eth_ops;
struct lldpd_ops bond_ops;
}
static int
-old_iface_is_bridge(struct lldpd *cfg, const char *name)
+iface_nametoindex(struct netlink_interface_list *interfaces,
+ const char *device)
+{
+ struct netlink_interface *iface;
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (!strcmp(iface->name, device))
+ return iface->index;
+ }
+ log_debug("interfaces", "cannot get interface index for %s",
+ device);
+ return 0;
+}
+
+static int
+iface_indextoname(struct netlink_interface_list *interfaces,
+ int index, char *name)
+{
+ struct netlink_interface *iface;
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface->index == index) {
+ strncpy(name, iface->name, IFNAMSIZ);
+ return 0;
+ }
+ }
+ log_debug("interfaces", "cannot get interface name for index %d",
+ index);
+ return -1;
+}
+
+static int
+old_iface_is_bridge(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *name)
{
int ifindices[MAX_BRIDGES];
char ifname[IFNAMSIZ];
to fill logs. */
return 0;
for (i = 0; i < num; i++) {
- if (if_indextoname(ifindices[i], ifname) == NULL)
+ if (iface_indextoname(interfaces, ifindices[i], ifname) == -1)
log_info("interfaces", "unable to get name of interface %d",
ifindices[i]);
else if (strncmp(name, ifname, IFNAMSIZ) == 0)
}
static int
-iface_is_bridge(struct lldpd *cfg, const char *name)
+iface_is_bridge(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *name)
{
#ifdef SYSFS_BRIDGE_FDB
char path[SYSFS_PATH_MAX];
SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_FDB, name)) >= SYSFS_PATH_MAX)
log_warnx("interfaces", "path truncated");
if ((f = priv_open(path)) < 0) {
- return old_iface_is_bridge(cfg, name);
+ return old_iface_is_bridge(cfg, interfaces, name);
}
close(f);
return 1;
#else
- return old_iface_is_bridge(cfg, name);
+ return old_iface_is_bridge(cfg, interfaces, name);
#endif
}
#ifdef ENABLE_DOT1
static int
-old_iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
+old_iface_is_bridged_to(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *slave, const char *master)
{
- int j, index = if_nametoindex(slave);
+ int j, index = iface_nametoindex(interfaces, slave);
int ifptindices[MAX_PORTS];
unsigned long args2[4] = { BRCTL_GET_PORT_LIST,
(unsigned long)ifptindices, MAX_PORTS, 0 };
struct ifreq ifr;
+ if (index == 0) return 0;
strncpy(ifr.ifr_name, master, IFNAMSIZ);
memset(ifptindices, 0, sizeof(ifptindices));
}
static int
-iface_is_bridged_to(struct lldpd *cfg, const char *slave, const char *master)
+iface_is_bridged_to(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *slave, const char *master)
{
#ifdef SYSFS_BRIDGE_PORT_SUBDIR
char path[SYSFS_PATH_MAX];
int f;
/* Master should be a bridge, first */
- if (!iface_is_bridge(cfg, master)) return 0;
+ if (!iface_is_bridge(cfg, interfaces, master)) return 0;
if (snprintf(path, SYSFS_PATH_MAX,
SYSFS_CLASS_NET "%s/" SYSFS_BRIDGE_PORT_SUBDIR "/%s/port_no",
master, slave) >= SYSFS_PATH_MAX)
log_warnx("interfaces", "path truncated");
if ((f = priv_open(path)) < 0) {
- return old_iface_is_bridged_to(cfg, slave, master);
+ return old_iface_is_bridged_to(cfg, interfaces, slave, master);
}
close(f);
return 1;
#else
- return old_iface_is_bridged_to(cfg, slave, master);
+ return old_iface_is_bridged_to(cfg, interfaces, slave, master);
#endif
}
#endif
}
static int
-iface_is_enslaved(struct lldpd *cfg, const char *name)
+iface_is_enslaved(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ const char *name)
{
- struct ifaddrs *ifap, *ifa;
+ struct netlink_interface *iface;
int master;
- if (getifaddrs(&ifap) != 0) {
- log_warn("interfaces", "unable to get interface list");
- return -1;
- }
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (iface_is_bond_slave(cfg, name, ifa->ifa_name, NULL)) {
- master = if_nametoindex(ifa->ifa_name);
- freeifaddrs(ifap);
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface_is_bond_slave(cfg, name, iface->name, NULL)) {
+ master = iface->index;
return master;
}
}
- freeifaddrs(ifap);
return -1;
}
static void
-iface_get_permanent_mac(struct lldpd *cfg, struct lldpd_hardware *hardware)
+iface_get_permanent_mac(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ struct lldpd_hardware *hardware)
{
int master, f, state = 0;
FILE *netbond;
log_debug("interfaces", "get MAC address for %s",
hardware->h_ifname);
- if ((master = iface_is_enslaved(cfg, hardware->h_ifname)) == -1)
+ if ((master = iface_is_enslaved(cfg, interfaces,
+ hardware->h_ifname)) == -1)
return;
/* We have a bond, we need to query it to get real MAC addresses */
- if ((if_indextoname(master, bond)) == NULL) {
+ if ((iface_indextoname(interfaces, master, bond)) == -1) {
log_warnx("interfaces", "unable to get bond name");
return;
}
/* Generic minimal checks to handle a given interface. */
static int
-iface_minimal_checks(struct lldpd *cfg, struct ifaddrs *ifa)
+iface_minimal_checks(struct lldpd *cfg,
+ struct netlink_interface_list *interfaces,
+ struct netlink_interface *iface)
{
- struct sockaddr_ll sdl;
struct ifreq ifr;
struct ethtool_drvinfo ethc;
const char * const *rif;
NULL
};
- int is_bridge = iface_is_bridge(cfg, ifa->ifa_name);
+ int is_bridge = iface_is_bridge(cfg, interfaces, iface->name);
- log_debug("interfaces", "minimal checks for %s", ifa->ifa_name);
+ log_debug("interfaces", "minimal checks for %s", iface->name);
if (!(LOCAL_CHASSIS(cfg)->c_cap_enabled & LLDP_CAP_BRIDGE) &&
is_bridge) {
log_debug("interfaces", "skip %s: is a bridge",
- ifa->ifa_name);
+ iface->name);
LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_BRIDGE;
return 0;
}
if (!(LOCAL_CHASSIS(cfg)->c_cap_enabled & LLDP_CAP_WLAN) &&
- iface_is_wireless(cfg, ifa->ifa_name))
+ iface_is_wireless(cfg, iface->name))
LOCAL_CHASSIS(cfg)->c_cap_enabled |= LLDP_CAP_WLAN;
/* First, check if this interface has already been handled */
- if (!ifa->ifa_flags) {
+ if (!iface->flags) {
log_debug("interfaces", "skip %s: already been handled",
- ifa->ifa_name);
+ iface->name);
return 0;
}
- if (ifa->ifa_addr == NULL) {
- if (ifa->ifa_addr->sa_family != PF_PACKET) {
- log_debug("interfaces", "skip %s: address family is %d and not PF_PACKET",
- ifa->ifa_name, ifa->ifa_addr->sa_family);
- return 0;
- }
- log_debug("interfaces", "skip %s: no address",
- ifa->ifa_name);
- }
-
- memcpy(&sdl, ifa->ifa_addr, sizeof(struct sockaddr_ll));
- if (sdl.sll_hatype != ARPHRD_ETHER || !sdl.sll_halen) {
+ if (iface->type != ARPHRD_ETHER) {
log_debug("interfaces", "skip %s: not an Ethernet device",
- ifa->ifa_name);
+ iface->name);
return 0;
}
/* We request that the interface is able to do either multicast
* or broadcast to be able to send discovery frames. */
- if (!(ifa->ifa_flags & (IFF_MULTICAST|IFF_BROADCAST))) {
+ if (!(iface->flags & (IFF_MULTICAST|IFF_BROADCAST))) {
log_debug("interfaces", "skip %s: not able to do multicast nor broadcast",
- ifa->ifa_name);
+ iface->name);
+ return 0;
+ }
+
+ /* If the interface is linked to another one, skip it too. */
+ if (iface->link != -1 && iface->index != iface->link) {
+ log_debug("interfaces", "skip %s: there is a lower interface (%d)",
+ iface->name, iface->link);
return 0;
}
/* Check if the driver is whitelisted */
memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, ifa->ifa_name);
+ strcpy(ifr.ifr_name, iface->name);
memset(ðc, 0, sizeof(ethc));
ifr.ifr_data = (caddr_t) ðc;
ethc.cmd = ETHTOOL_GDRVINFO;
if (strcmp(ethc.driver, *rif) == 0) {
/* White listed! */
log_debug("interfaces", "accept %s: whitelisted",
- ifa->ifa_name);
+ iface->name);
return 1;
}
}
}
- log_debug("interfaces", "keep %s: not whitelisted",
- ifa->ifa_name);
+ log_debug("interfaces", "keep checking %s: not whitelisted",
+ iface->name);
/* Check queue len. If no queue, this usually means that this
is not a "real" interface. */
- memset(&ifr, 0, sizeof(ifr));
- strcpy(ifr.ifr_name, ifa->ifa_name);
- if ((ioctl(cfg->g_sock, SIOCGIFTXQLEN, &ifr) < 0) || !ifr.ifr_qlen) {
+ if (iface->txqueue == 0) {
log_debug("interfaces", "skip %s: no queue",
- ifa->ifa_name);
+ iface->name);
return 0;
}
/* Don't handle bond and VLAN, nor bridge */
- if (iface_is_vlan(cfg, ifa->ifa_name)) {
+ if (iface_is_vlan(cfg, iface->name)) {
log_debug("interfaces", "skip %s: is a VLAN",
- ifa->ifa_name);
+ iface->name);
return 0;
}
- if (iface_is_bond(cfg, ifa->ifa_name)) {
+ if (iface_is_bond(cfg, iface->name)) {
log_debug("interfaces", "skip %s: is a bond",
- ifa->ifa_name);
+ iface->name);
return 0;
}
if (is_bridge) {
log_debug("interfaces", "skip %s: is a bridge",
- ifa->ifa_name);
+ iface->name);
return 0;
}
log_debug("interfaces", "%s passes the minimal checks",
- ifa->ifa_name);
+ iface->name);
return 1;
}
/* Fill up port name and description */
static void
-iface_port_name_desc(struct lldpd_hardware *hardware)
+iface_port_name_desc(struct lldpd_hardware *hardware, struct netlink_interface *iface)
{
struct lldpd_port *port = &hardware->h_lport;
- char buffer[256]; /* 256 = IFALIASZ */
- char path[SYSFS_PATH_MAX];
- int f;
/* There are two cases:
port name in description.
*/
- if ((snprintf(path, SYSFS_PATH_MAX,
- SYSFS_CLASS_NET "%s/ifalias", hardware->h_ifname)) >= SYSFS_PATH_MAX)
- log_warnx("interfaces", "path truncated");
- memset(buffer, 0, sizeof(buffer));
- if (((f = priv_open(path)) < 0) || (read(f, buffer, sizeof(buffer)-1) < 1)) {
+ if (iface->alias == NULL || strlen(iface->alias) == 0) {
/* Case 2: MAC address and port name */
- close(f);
log_debug("interfaces", "use ifname and MAC address for %s",
hardware->h_ifname);
port->p_id_subtype = LLDP_PORTID_SUBTYPE_LLADDR;
return;
}
/* Case 1: port name and port description */
- close(f);
log_debug("interfaces", "use ifname and ifalias for %s",
hardware->h_ifname);
port->p_id_subtype = LLDP_PORTID_SUBTYPE_IFNAME;
calloc(1, port->p_id_len)) == NULL)
fatal("interfaces", NULL);
memcpy(port->p_id, hardware->h_ifname, port->p_id_len);
- if (buffer[strlen(buffer) - 1] == '\n')
- buffer[strlen(buffer) - 1] = '\0';
- port->p_descr = strdup(buffer);
+ port->p_descr = strdup(iface->alias);
}
/* Fill up MAC/PHY for a given hardware port */
log_debug("interfaces", "ask ethtool for the appropriate MAC/PHY for %s",
hardware->h_ifname);
- if (priv_ethtool(hardware->h_ifname, ðc) == 0) {
+ if (priv_ethtool(hardware->h_ifname, ðc, sizeof(struct ethtool_cmd)) == 0) {
port->p_macphy.autoneg_support = (ethc.supported & SUPPORTED_Autoneg) ? 1 : 0;
port->p_macphy.autoneg_enabled = (ethc.autoneg == AUTONEG_DISABLE) ? 0 : 1;
for (j=0; advertised_ethtool_to_rfc3636[j][0]; j++) {
#endif
}
-static void
-iface_mtu(struct lldpd *cfg, struct lldpd_hardware *hardware)
-{
- struct ifreq ifr;
-
- /* get MTU */
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, hardware->h_ifname, sizeof(ifr.ifr_name));
- if (ioctl(cfg->g_sock, SIOCGIFMTU, (char*)&ifr) == -1) {
- log_warn("interfaces", "unable to get MTU of %s, using 1500", hardware->h_ifname);
- hardware->h_mtu = 1500;
- } else
- hardware->h_mtu = ifr.ifr_mtu;
-}
-
static void
iface_multicast(struct lldpd *cfg, const char *name, int remove)
{
log_debug("interfaces", "initialize ethernet device %s",
hardware->h_ifname);
- if ((fd = priv_iface_init(hardware->h_ifname)) == -1)
+ if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
return -1;
hardware->h_sendfd = fd; /* Send */
iface_eth_send(struct lldpd *cfg, struct lldpd_hardware *hardware,
char *buffer, size_t size)
{
- log_debug("interfaces", "send PDU to ethernet device %s",
- hardware->h_ifname);
+ log_debug("interfaces", "send PDU to ethernet device %s (fd=%d)",
+ hardware->h_ifname, hardware->h_sendfd);
return write(hardware->h_sendfd,
buffer, size);
}
return 0;
}
-void
-lldpd_ifh_eth(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_eth(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
struct lldpd_hardware *hardware;
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (!iface_minimal_checks(cfg, ifa))
+ TAILQ_FOREACH(iface, interfaces, next) {
+ log_debug("interfaces", "check if %s is a real ethernet device",
+ iface->name);
+ if (!iface_minimal_checks(cfg, interfaces, iface))
continue;
log_debug("interfaces", "%s is an acceptable ethernet device",
- ifa->ifa_name);
+ iface->name);
if ((hardware = lldpd_get_hardware(cfg,
- ifa->ifa_name,
- if_nametoindex(ifa->ifa_name),
+ iface->name,
+ iface->index,
ð_ops)) == NULL) {
if ((hardware = lldpd_alloc_hardware(cfg,
- ifa->ifa_name)) == NULL) {
+ iface->name,
+ iface->index)) == NULL) {
log_warnx("interfaces", "Unable to allocate space for %s",
- ifa->ifa_name);
+ iface->name);
continue;
}
if (iface_eth_init(cfg, hardware) != 0) {
continue;
}
hardware->h_ops = ð_ops;
- hardware->h_ifindex = if_nametoindex(ifa->ifa_name);
TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
} else {
if (hardware->h_flags) continue; /* Already seen this time */
lldpd_port_cleanup(&hardware->h_lport, 0);
}
- hardware->h_flags = ifa->ifa_flags; /* Should be non-zero */
- ifa->ifa_flags = 0; /* Future handlers
+ hardware->h_flags = iface->flags; /* Should be non-zero */
+ iface->flags = 0; /* Future handlers
don't have to
care about this
interface. */
/* Get local address */
- memcpy(&hardware->h_lladdr,
- (u_int8_t*)((u_int8_t*)ifa->ifa_addr +
- offsetof(struct sockaddr_ll, sll_addr)),
- sizeof(hardware->h_lladdr));
+ memcpy(&hardware->h_lladdr, iface->address, ETHER_ADDR_LEN);
/* Fill information about port */
- iface_port_name_desc(hardware);
+ iface_port_name_desc(hardware, iface);
/* Fill additional info */
iface_macphy(hardware);
- iface_mtu(cfg, hardware);
+ hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
}
}
-void
-lldpd_ifh_whitelist(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_whitelist(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
if (!cfg->g_config.c_iface_pattern)
return;
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_flags == 0) continue; /* Already handled by someone else */
- if (!pattern_match(ifa->ifa_name, cfg->g_config.c_iface_pattern, 0)) {
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface->flags == 0) continue; /* Already handled by someone else */
+ if (!pattern_match(iface->name, cfg->g_config.c_iface_pattern, 0)) {
/* This interface was not found. We flag it. */
- log_debug("interfaces", "blacklist %s", ifa->ifa_name);
- ifa->ifa_flags = 0;
+ log_debug("interfaces", "blacklist %s", iface->name);
+ iface->flags = 0;
}
}
}
+struct bond_master {
+ char name[IFNAMSIZ];
+ int index;
+};
+
static int
iface_bond_init(struct lldpd *cfg, struct lldpd_hardware *hardware)
{
- char *mastername = (char *)hardware->h_data; /* Master name */
+ struct bond_master *master = hardware->h_data;
int fd, status;
int un = 1;
- if (!mastername) return -1;
+ if (!master) return -1;
log_debug("interfaces", "initialize bonded device %s",
hardware->h_ifname);
/* First, we get a socket to the raw physical interface */
- if ((fd = priv_iface_init(hardware->h_ifname)) == -1)
+ if ((fd = priv_iface_init(hardware->h_ifindex)) == -1)
return -1;
hardware->h_sendfd = fd;
if ((status = iface_set_filter(hardware->h_ifname, fd)) != 0) {
iface_multicast(cfg, hardware->h_ifname, 0);
/* Then, we open a raw interface for the master */
- if ((fd = priv_iface_init(mastername)) == -1) {
+ if ((fd = priv_iface_init(master->index)) == -1) {
close(hardware->h_sendfd);
return -1;
}
- if ((status = iface_set_filter(mastername, fd)) != 0) {
+ if ((status = iface_set_filter(master->name, fd)) != 0) {
close(hardware->h_sendfd);
close(fd);
return status;
* physical device instead of bond device (works with >=
* 2.6.24). */
if (setsockopt(fd, SOL_PACKET,
- PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
- log_debug("interfaces", "unable to setsockopt for master bonding device of %s. "
- "You will get inaccurate results",
- hardware->h_ifname);
+ PACKET_ORIGDEV, &un, sizeof(un)) == -1) {
+ log_info("interfaces", "unable to setsockopt for master bonding device of %s. "
+ "You will get inaccurate results",
+ hardware->h_ifname);
}
- iface_multicast(cfg, mastername, 0);
+ iface_multicast(cfg, master->name, 0);
levent_hardware_add_fd(hardware, hardware->h_sendfd);
levent_hardware_add_fd(hardware, fd);
log_debug("interfaces", "interface %s initialized (fd=%d,master=%s[%d])",
hardware->h_ifname,
hardware->h_sendfd,
- mastername, fd);
+ master->name, fd);
return 0;
}
/* With bonds, we have duplicate MAC address on different physical
* interfaces. We need to alter the source MAC address when we send on
* an inactive slave. */
- char *master = (char*)hardware->h_data;
+ struct bond_master *master = hardware->h_data;
int active;
log_debug("interfaces", "send PDU to bonded device %s",
hardware->h_ifname);
- if (!iface_is_bond_slave(cfg, hardware->h_ifname, master, &active)) {
+ if (!iface_is_bond_slave(cfg, hardware->h_ifname, master->name, &active)) {
log_warnx("interfaces", "%s seems to not be enslaved anymore?",
hardware->h_ifname);
return 0;
int n;
struct sockaddr_ll from;
socklen_t fromlen;
+ struct bond_master *master = hardware->h_data;
log_debug("interfaces", "receive PDU from bonded device %s",
hardware->h_ifname);
if (from.sll_ifindex == hardware->h_ifindex)
/* This is for us */
return n;
- if (from.sll_ifindex == if_nametoindex((char*)hardware->h_data))
+ if (from.sll_ifindex == master->index)
/* We don't know from which physical interface it comes (kernel
* < 2.6.24). In doubt, this is for us. */
return n;
static int
iface_bond_close(struct lldpd *cfg, struct lldpd_hardware *hardware)
{
+ struct bond_master *master = hardware->h_data;
log_debug("interfaces", "closing bonded device %s",
hardware->h_ifname);
iface_multicast(cfg, hardware->h_ifname, 1);
- iface_multicast(cfg, (char*)hardware->h_data, 1);
+ iface_multicast(cfg, master->name, 1);
free(hardware->h_data);
return 0;
}
-void
-lldpd_ifh_bond(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_bond(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
struct lldpd_hardware *hardware;
- int master;
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (!iface_minimal_checks(cfg, ifa))
+ struct bond_master *master;
+ int idx;
+ TAILQ_FOREACH(iface, interfaces, next) {
+ log_debug("interfaces", "check if %s is part of a bond",
+ iface->name);
+ if (!iface_minimal_checks(cfg, interfaces, iface))
continue;
- if ((master = iface_is_enslaved(cfg, ifa->ifa_name)) == -1)
+ if ((idx = iface_is_enslaved(cfg, interfaces,
+ iface->name)) == -1)
continue;
log_debug("interfaces", "%s is an acceptable bonded device (master=%d)",
- ifa->ifa_name, master);
+ iface->name, idx);
if ((hardware = lldpd_get_hardware(cfg,
- ifa->ifa_name,
- if_nametoindex(ifa->ifa_name),
+ iface->name,
+ iface->index,
&bond_ops)) == NULL) {
if ((hardware = lldpd_alloc_hardware(cfg,
- ifa->ifa_name)) == NULL) {
+ iface->name,
+ iface->index)) == NULL) {
log_warnx("interfaces", "Unable to allocate space for %s",
- ifa->ifa_name);
+ iface->name);
+ continue;
+ }
+ hardware->h_data = master = calloc(1, sizeof(struct bond_master));
+ if (!hardware->h_data) {
+ log_warn("interfaces", "not enough memory");
+ lldpd_hardware_cleanup(cfg, hardware);
+ continue;
+ }
+ master->index = idx;
+ if (iface_indextoname(interfaces, master->index, master->name) == -1) {
+ lldpd_hardware_cleanup(cfg, hardware);
continue;
}
- hardware->h_data = (char *)calloc(1, IFNAMSIZ);
- if_indextoname(master, hardware->h_data);
if (iface_bond_init(cfg, hardware) != 0) {
log_warn("interfaces", "unable to initialize %s",
hardware->h_ifname);
continue;
}
hardware->h_ops = &bond_ops;
- hardware->h_ifindex = if_nametoindex(ifa->ifa_name);
TAILQ_INSERT_TAIL(&cfg->g_hardware, hardware, h_entries);
} else {
if (hardware->h_flags) continue; /* Already seen this time */
- memset(hardware->h_data, 0, IFNAMSIZ);
- if_indextoname(master, hardware->h_data);
+ master = hardware->h_data;
+ memset(hardware->h_data, 0, sizeof(struct bond_master));
+ master->index = idx;
+ iface_indextoname(interfaces, master->index, master->name);
lldpd_port_cleanup(&hardware->h_lport, 0);
}
-
- hardware->h_flags = ifa->ifa_flags;
- ifa->ifa_flags = 0;
+
+ hardware->h_flags = iface->flags;
+ iface->flags = 0;
/* Get local address */
- iface_get_permanent_mac(cfg, hardware);
-
+ iface_get_permanent_mac(cfg, interfaces, hardware);
+
/* Fill information about port */
- iface_port_name_desc(hardware);
-
+ iface_port_name_desc(hardware, iface);
+
/* Fill additional info */
#ifdef ENABLE_DOT3
- hardware->h_lport.p_aggregid = master;
+ hardware->h_lport.p_aggregid = master->index;
#endif
iface_macphy(hardware);
- iface_mtu(cfg, hardware);
+ hardware->h_mtu = iface->mtu ? iface->mtu : 1500;
}
}
#ifdef ENABLE_DOT1
static void
iface_append_vlan(struct lldpd *cfg,
- struct lldpd_hardware *hardware, struct ifaddrs *ifa)
+ struct lldpd_hardware *hardware, struct netlink_interface *iface)
{
struct lldpd_port *port = &hardware->h_lport;
struct lldpd_vlan *vlan;
/* Check if the VLAN is already here. */
TAILQ_FOREACH(vlan, &port->p_vlans, v_entries)
- if (strncmp(ifa->ifa_name, vlan->v_name, IFNAMSIZ) == 0)
+ if (strncmp(iface->name, vlan->v_name, IFNAMSIZ) == 0)
return;
if ((vlan = (struct lldpd_vlan *)
calloc(1, sizeof(struct lldpd_vlan))) == NULL)
return;
- if ((vlan->v_name = strdup(ifa->ifa_name)) == NULL) {
+ if ((vlan->v_name = strdup(iface->name)) == NULL) {
free(vlan);
return;
}
memset(&ifv, 0, sizeof(ifv));
ifv.cmd = GET_VLAN_VID_CMD;
- strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
+ strlcpy(ifv.device1, iface->name, sizeof(ifv.device1));
if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) < 0) {
/* Dunno what happened */
free(vlan->v_name);
TAILQ_INSERT_TAIL(&port->p_vlans, vlan, v_entries);
}
-void
-lldpd_ifh_vlan(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_vlan(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
struct vlan_ioctl_args ifv;
struct lldpd_hardware *hardware;
-
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (!ifa->ifa_flags)
+
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (!iface->flags)
continue;
- if (!iface_is_vlan(cfg, ifa->ifa_name))
+ if (!iface_is_vlan(cfg, iface->name))
continue;
/* We need to find the physical interfaces of this
vlan, through bonds and bridges. */
+ /* TODO: use iflink instead? Possible since 2.6.17 only. */
log_debug("interfaces", "search physical interface for VLAN interface %s",
- ifa->ifa_name);
+ iface->name);
memset(&ifv, 0, sizeof(ifv));
ifv.cmd = GET_VLAN_REALDEV_NAME_CMD;
- strlcpy(ifv.device1, ifa->ifa_name, sizeof(ifv.device1));
+ strlcpy(ifv.device1, iface->name, sizeof(ifv.device1));
if (ioctl(cfg->g_sock, SIOCGIFVLAN, &ifv) >= 0) {
/* Three cases:
1. we get a real device
2. we get a bond
3. we get a bridge
*/
+ int idx = iface_nametoindex(interfaces, ifv.u.device2);
+ if (idx == 0) continue;
if ((hardware = lldpd_get_hardware(cfg,
ifv.u.device2,
- if_nametoindex(ifv.u.device2),
+ idx,
NULL)) == NULL) {
if (iface_is_bond(cfg, ifv.u.device2)) {
TAILQ_FOREACH(hardware, &cfg->g_hardware,
hardware->h_ifname,
ifv.u.device2);
iface_append_vlan(cfg,
- hardware, ifa);
+ hardware, iface);
}
- } else if (iface_is_bridge(cfg, ifv.u.device2)) {
+ } else if (iface_is_bridge(cfg, interfaces, ifv.u.device2)) {
TAILQ_FOREACH(hardware, &cfg->g_hardware,
h_entries)
if (iface_is_bridged_to(cfg,
+ interfaces,
hardware->h_ifname,
ifv.u.device2)) {
log_debug("interfaces",
hardware->h_ifname,
ifv.u.device2);
iface_append_vlan(cfg,
- hardware, ifa);
+ hardware, iface);
}
}
} else iface_append_vlan(cfg,
- hardware, ifa);
+ hardware, iface);
}
}
}
#define IN_IS_ADDR_GLOBAL(a) (!IN_IS_ADDR_LOOPBACK(a))
#endif
#ifndef IN6_IS_ADDR_GLOBAL
-#define IN6_IS_ADDR_GLOBAL(a) (!IN6_IS_ADDR_LOOPBACK(a) && \
- !IN6_IS_ADDR_LINKLOCAL(a))
+#define IN6_IS_ADDR_GLOBAL(a) \
+ (!IN6_IS_ADDR_LOOPBACK(a) && !IN6_IS_ADDR_LINKLOCAL(a))
#endif
/* Find a management address in all available interfaces, even those that were
already handled. This is a special interface handler because it does not
really handle interface related information (management address is attached
to the local chassis). */
-void
-lldpd_ifh_mgmt(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_mgmt(struct lldpd *cfg, struct netlink_address_list *addrs)
{
- struct ifaddrs *ifa;
+ struct netlink_address *addr;
char addrstrbuf[INET6_ADDRSTRLEN];
struct lldpd_mgmt *mgmt;
void *sin_addr_ptr;
example !*:*,!10.* will only blacklist
addresses. We will pick the first IPv4 address not
matching 10.*. */
- for (ifa = ifap;
- ifa != NULL;
- ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL)
- continue;
- if (ifa->ifa_addr->sa_family != lldpd_af(af))
+ TAILQ_FOREACH(addr, addrs, next) {
+ if (addr->address.ss_family != lldpd_af(af))
continue;
switch (af) {
case LLDPD_AF_IPV4:
- sin_addr_ptr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
+ sin_addr_ptr = &((struct sockaddr_in *)&addr->address)->sin_addr;
sin_addr_size = sizeof(struct in_addr);
if (!IN_IS_ADDR_GLOBAL((struct in_addr *)sin_addr_ptr))
continue;
break;
case LLDPD_AF_IPV6:
- sin_addr_ptr = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
+ sin_addr_ptr = &((struct sockaddr_in6 *)&addr->address)->sin6_addr;
sin_addr_size = sizeof(struct in6_addr);
if (!IN6_IS_ADDR_GLOBAL((struct in6_addr *)sin_addr_ptr))
continue;
continue;
}
if (inet_ntop(lldpd_af(af), sin_addr_ptr,
- addrstrbuf, sizeof(addrstrbuf)) == NULL) {
+ addrstrbuf, sizeof(addrstrbuf)) == NULL) {
log_warn("interfaces", "unable to convert IP address to a string");
continue;
}
if (cfg->g_config.c_mgmt_pattern == NULL ||
pattern_match(addrstrbuf, cfg->g_config.c_mgmt_pattern, allnegative)) {
mgmt = lldpd_alloc_mgmt(af, sin_addr_ptr, sin_addr_size,
- if_nametoindex(ifa->ifa_name));
+ addr->index);
if (mgmt == NULL) {
assert(errno == ENOMEM); /* anything else is a bug */
log_warn("interfaces", "out of memory error");
/* Fill out chassis ID if not already done. This handler is special
because we will only handle interfaces that are already handled. */
-void
-lldpd_ifh_chassis(struct lldpd *cfg, struct ifaddrs *ifap)
+static void
+lldpd_ifh_chassis(struct lldpd *cfg, struct netlink_interface_list *interfaces)
{
- struct ifaddrs *ifa;
+ struct netlink_interface *iface;
struct lldpd_hardware *hardware;
char *name = NULL;
LOCAL_CHASSIS(cfg)->c_id_subtype == LLDP_CHASSISID_SUBTYPE_LLADDR)
return; /* We already have one */
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (ifa->ifa_flags) continue;
+ TAILQ_FOREACH(iface, interfaces, next) {
+ if (iface->flags) continue;
if (cfg->g_config.c_cid_pattern &&
- !pattern_match(ifa->ifa_name, cfg->g_config.c_cid_pattern, 0)) continue;
+ !pattern_match(iface->name, cfg->g_config.c_cid_pattern, 0)) continue;
if ((hardware = lldpd_get_hardware(cfg,
- ifa->ifa_name,
- if_nametoindex(ifa->ifa_name),
+ iface->name,
+ iface->index,
NULL)) == NULL)
/* That's odd. Let's skip. */
continue;
.recv = iface_bond_recv,
.cleanup = iface_bond_close,
};
+
+void
+interfaces_update(struct lldpd *cfg)
+{
+ struct netlink_interface_list *interfaces = NULL;
+ struct netlink_address_list *addresses = NULL;
+ interfaces = netlink_get_interfaces();
+ addresses = netlink_get_addresses();
+ if (interfaces == NULL || addresses == NULL) {
+ log_warnx("interfaces", "cannot update the list of local interfaces");
+ goto end;
+ }
+
+ lldpd_ifh_whitelist(cfg, interfaces);
+ lldpd_ifh_bond(cfg, interfaces);
+ lldpd_ifh_eth(cfg, interfaces);
+#ifdef ENABLE_DOT1
+ lldpd_ifh_vlan(cfg, interfaces);
+#endif
+ lldpd_ifh_mgmt(cfg, addresses);
+ lldpd_ifh_chassis(cfg, interfaces);
+
+end:
+ netlink_free_interfaces(interfaces);
+ netlink_free_addresses(addresses);
+ return;
+
+}
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netpacket/packet.h>
-#include <linux/sockios.h>
inline static int
lldpd_af_to_lldp_proto(int af)
Main loop.
.It Sy smartfilter
Smart filtering of different protocols on the same port.
+.It Sy netlink
+Netlink subsystem.
.El
.It Fl k
Disable advertising of kernel release, version and machine. Kernel name
#include <sys/time.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
-#include <net/if_arp.h>
#include <pwd.h>
#include <grp.h>
}
struct lldpd_hardware *
-lldpd_alloc_hardware(struct lldpd *cfg, char *name)
+lldpd_alloc_hardware(struct lldpd *cfg, char *name, int index)
{
struct lldpd_hardware *hardware;
hardware->h_cfg = cfg;
strlcpy(hardware->h_ifname, name, sizeof(hardware->h_ifname));
+ hardware->h_ifindex = index;
hardware->h_lport.p_chassis = LOCAL_CHASSIS(cfg);
hardware->h_lport.p_chassis->c_refcount++;
TAILQ_INIT(&hardware->h_rports);
static void
lldpd_med(struct lldpd_chassis *chassis)
{
-#if __i386__ || __amd64__
static short int once = 0;
if (!once) {
chassis->c_med_hw = dmi_hw();
chassis->c_med_asset = dmi_asset();
once = 1;
}
-#endif
}
#endif
static void
lldpd_update_localports(struct lldpd *cfg)
{
- struct ifaddrs *ifap;
struct lldpd_hardware *hardware;
- lldpd_ifhandlers ifhs[] = {
- lldpd_ifh_whitelist, /* Is the interface whitelisted? */
- lldpd_ifh_bond, /* Handle bond */
- lldpd_ifh_eth, /* Handle classic ethernet interfaces */
-#ifdef ENABLE_DOT1
- lldpd_ifh_vlan, /* Handle VLAN */
-#endif
- lldpd_ifh_mgmt, /* Handle management address (if not already handled) */
- lldpd_ifh_chassis, /* Handle chassis ID (if not already handled) */
- NULL
- };
- lldpd_ifhandlers *ifh;
log_debug("localchassis", "update information for local ports");
TAILQ_FOREACH(hardware, &cfg->g_hardware, h_entries)
hardware->h_flags = 0;
- if (getifaddrs(&ifap) != 0)
- fatal("localchassis", "failed to get interface list");
-
- /* We will run the list of interfaces through a list of interface
- * handlers. Each handler will create or update some hardware port (and
- * will set h_flags to a non zero value. The handler can use the list of
- * interfaces but this is not mandatory. If the interface handler
- * handles an interface from the list, it should set ifa_flags to 0 to
- * let know the other handlers that it took care of this interface. This
- * means that more specific handlers should be before less specific
- * ones. */
- for (ifh = ifhs; *ifh != NULL; ifh++)
- (*ifh)(cfg, ifap);
- freeifaddrs(ifap);
+ interfaces_update(cfg);
}
void
#include <stddef.h>
#include <string.h>
#include <sys/queue.h>
-#ifdef HAVE_SYS_TYPES_H
-# include <sys/types.h>
-#endif
-#ifndef INCLUDE_LINUX_IF_H
-# include <net/if.h>
-#else
-# include <arpa/inet.h>
-# include <linux/if.h>
-#endif
-#if HAVE_GETIFADDRS
-# include <ifaddrs.h>
-#endif
+#include <sys/types.h>
#include <net/ethernet.h>
#include <netinet/in.h>
-#include <linux/ethtool.h>
#include <sys/un.h>
#include "lldp-tlv.h"
TAILQ_HEAD(, lldpd_hardware) g_hardware;
};
-typedef void(*lldpd_ifhandlers)(struct lldpd *, struct ifaddrs *);
-
/* lldpd.c */
struct lldpd_hardware *lldpd_get_hardware(struct lldpd *,
char *, int, struct lldpd_ops *);
-struct lldpd_hardware *lldpd_alloc_hardware(struct lldpd *, char *);
+struct lldpd_hardware *lldpd_alloc_hardware(struct lldpd *, char *, int);
void lldpd_hardware_cleanup(struct lldpd*, struct lldpd_hardware *);
struct lldpd_mgmt *lldpd_alloc_mgmt(int family, void *addr, size_t addrsize, u_int32_t iface);
void lldpd_recv(struct lldpd *, struct lldpd_hardware *, int);
int edp_decode(PROTO_DECODE_SIG);
#endif
-/* interfaces.c */
-void lldpd_ifh_whitelist(struct lldpd *, struct ifaddrs *);
-void lldpd_ifh_bond(struct lldpd *, struct ifaddrs *);
-void lldpd_ifh_eth(struct lldpd *, struct ifaddrs *);
-#ifdef ENABLE_DOT1
-void lldpd_ifh_vlan(struct lldpd *, struct ifaddrs *);
-#endif
-void lldpd_ifh_mgmt(struct lldpd *, struct ifaddrs *);
-void lldpd_ifh_chassis(struct lldpd *, struct ifaddrs *);
-
/* dmi.c */
#ifdef ENABLE_LLDPMED
-#if __i386__ || __amd64__
char *dmi_hw(void);
char *dmi_fw(void);
char *dmi_sn(void);
char *dmi_model(void);
char *dmi_asset(void);
#endif
-#endif
#ifdef USE_SNMP
/* agent.c */
void priv_ctl_cleanup(void);
char *priv_gethostbyname(void);
int priv_open(char*);
-int priv_ethtool(char*, struct ethtool_cmd*);
-int priv_iface_init(const char *);
+#ifdef HOST_OS_LINUX
+int priv_ethtool(char*, void*, size_t);
+#endif
+int priv_iface_init(int);
int priv_iface_multicast(const char *, u_int8_t *, int);
int priv_snmp_socket(struct sockaddr_un *);
int receive_fd(int);
void send_fd(int, int);
+/* interfaces-*.c */
+void interfaces_update(struct lldpd *);
+
+#ifdef HOST_OS_LINUX
+/* netlink stuff */
+struct netlink_interface {
+ TAILQ_ENTRY(netlink_interface) next;
+ int index; /* Index */
+ char *name; /* Name */
+ char *alias; /* Alias */
+ int flags; /* Flags */
+ int mtu; /* MTU */
+ char *address; /* MAC address */
+ int type; /* Type (ARPHDR_*) */
+ int link; /* Support interface */
+ int master; /* Master interface */
+ int txqueue; /* TX queue len */
+};
+struct netlink_address {
+ TAILQ_ENTRY(netlink_address) next;
+ int index; /* Index */
+ int flags; /* Flags */
+ struct sockaddr_storage address; /* Address */
+};
+TAILQ_HEAD(netlink_interface_list, netlink_interface);
+TAILQ_HEAD(netlink_address_list, netlink_address);
+struct netlink_interface_list *netlink_get_interfaces(void);
+struct netlink_address_list *netlink_get_addresses(void);
+void netlink_free_interfaces(struct netlink_interface_list *);
+void netlink_free_addresses(struct netlink_address_list *);
+#endif
+
#endif /* _LLDPD_H */
--- /dev/null
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "lldpd.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#define NETLINK_BUFFER 4096
+
+struct netlink_req {
+ struct nlmsghdr hdr;
+ struct rtgenmsg gen;
+};
+
+/**
+ * Connect to netlink.
+ *
+ * Open a Netlink socket and connect to it.
+ *
+ * @param protocol Which protocol to use (eg NETLINK_ROUTE).
+ * @return The opened socket or -1 on error.
+ */
+static int
+netlink_connect(int protocol)
+{
+ int s = 0;
+ struct sockaddr_nl local = {
+ .nl_family = AF_NETLINK,
+ .nl_pid = getpid(),
+ .nl_groups = 0
+ };
+
+ /* 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 (bind(s, (struct sockaddr *)&local, sizeof(struct sockaddr_nl)) < 0) {
+ log_warn("netlink", "unable to bind netlink socket");
+ close(s);
+ return -1;
+ }
+ return s;
+}
+
+/**
+ * Send a netlink message.
+ *
+ * The type of the message can be chosen as well the route family. The
+ * mesage will always be NLM_F_REQUEST | NLM_F_DUMP.
+ *
+ * @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)
+{
+ struct netlink_req req = {
+ .hdr = {
+ .nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
+ .nlmsg_type = RTM_GETLINK,
+ .nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP,
+ .nlmsg_seq = 1,
+ .nlmsg_pid = getpid() },
+ .gen = { .rtgen_family = AF_PACKET }
+ };
+ 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;
+}
+
+/**
+ * Free an interface.
+ *
+ * @param iff interface to be freed
+ */
+static void
+netlink_free_interface(struct netlink_interface *iff)
+{
+ if (!iff) return;
+ free(iff->name);
+ free(iff->alias);
+ free(iff->address);
+ free(iff);
+}
+
+/**
+ * Free a list of interfaces.
+ *
+ * @param ifs list of interfaces to be freed
+ */
+void
+netlink_free_interfaces(struct netlink_interface_list *ifs)
+{
+ struct netlink_interface *iff, *iff_next;
+ if (!ifs) return;
+ for (iff = TAILQ_FIRST(ifs);
+ iff != NULL;
+ iff = iff_next) {
+ iff_next = TAILQ_NEXT(iff, next);
+ netlink_free_interface(iff);
+ }
+ free(ifs);
+}
+
+/**
+ * Free a list of addresses.
+ *
+ * @param ifaddrs list of addresses
+ */
+void
+netlink_free_addresses(struct netlink_address_list *ifaddrs)
+{
+ struct netlink_address *ifa, *ifa_next;
+ if (!ifaddrs) return;
+ for (ifa = TAILQ_FIRST(ifaddrs);
+ ifa != NULL;
+ ifa = ifa_next) {
+ ifa_next = TAILQ_NEXT(ifa, next);
+ free(ifa);
+ }
+ free(ifaddrs);
+}
+
+/**
+ * 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
+ */
+static int
+netlink_parse_link(struct nlmsghdr *msg,
+ struct netlink_interface *iff)
+{
+ struct ifinfomsg *iface;
+ struct rtattr *attribute;
+ int len;
+ iface = NLMSG_DATA(msg);
+ len = msg->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+ iff->index = iface->ifi_index;
+ iff->type = iface->ifi_type;
+ iff->flags = iface->ifi_flags;
+ iff->link = -1;
+
+ for (attribute = IFLA_RTA(iface);
+ 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 "inferior" interface */
+ iff->link = *(int*)RTA_DATA(attribute);
+ break;
+ case IFLA_MASTER:
+ /* Index of master interface */
+ iff->master = *(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;
+ default:
+ log_debug("netlink", "unhandled 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;
+}
+
+/**
+ * Parse a `address` 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
+ */
+static int
+netlink_parse_address(struct nlmsghdr *msg,
+ struct netlink_address *ifa)
+{
+ 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 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;
+}
+
+/**
+ * Receive netlink answer from the kernel.
+ *
+ * @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
+ */
+static int
+netlink_recv(int s,
+ struct netlink_interface_list *ifs,
+ struct netlink_address_list *ifas)
+{
+ char reply[NETLINK_BUFFER];
+ int end = 0;
+
+ struct netlink_interface *iff;
+ struct netlink_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*)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 netlink_interface));
+ 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
+ netlink_free_interface(iff);
+ break;
+ case RTM_NEWADDR:
+ if (!ifas) break;
+ log_debug("netlink", "received address information");
+ ifa = calloc(1, sizeof(struct netlink_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
+ free(ifa);
+ break;
+ default:
+ log_debug("netlink",
+ "received unhandled message type %d (len: %d)",
+ msg->nlmsg_type, msg->nlmsg_len);
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Receive the list of interfaces.
+ *
+ * @return a list of interfaces.
+ */
+struct netlink_interface_list*
+netlink_get_interfaces()
+{
+ int s;
+ struct netlink_interface_list *ifs;
+
+ if ((s = netlink_connect(NETLINK_ROUTE)) == -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 netlink_interface_list));
+ if (ifs == NULL) {
+ log_warn("netlink", "not enough memory for interface list");
+ return NULL;
+ }
+ TAILQ_INIT(ifs);
+ netlink_recv(s, ifs, NULL);
+
+ close(s);
+ return ifs;
+}
+
+/**
+ * Receive the list of addresses.
+ *
+ * @return a list of addresses.
+ */
+struct netlink_address_list*
+netlink_get_addresses()
+{
+ int s;
+ struct netlink_address_list *ifaddrs;
+
+ if ((s = netlink_connect(NETLINK_ROUTE)) == -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 netlink_address_list));
+ if (ifaddrs == NULL) {
+ log_warn("netlink", "not enough memory for address list");
+ return NULL;
+ }
+ TAILQ_INIT(ifaddrs);
+ netlink_recv(s, NULL, ifaddrs);
+
+ close(s);
+ return ifaddrs;
+}
#include <sys/utsname.h>
#include <sys/ioctl.h>
#include <netdb.h>
-#include <linux/sockios.h>
-#include <linux/if_packet.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
/* Use resolv.h */
#ifdef HAVE_SYS_TYPES_H
return receive_fd(remote);
}
+#ifdef HOST_OS_LINUX
/* Proxy for ethtool ioctl */
int
-priv_ethtool(char *ifname, struct ethtool_cmd *ethc)
+priv_ethtool(char *ifname, void *ethc, size_t length)
{
int cmd, rc, len;
cmd = PRIV_ETHTOOL;
must_read(remote, &rc, sizeof(int));
if (rc != 0)
return rc;
- must_read(remote, ethc, sizeof(struct ethtool_cmd));
+ must_read(remote, ethc, length);
return rc;
}
+#endif
int
-priv_iface_init(const char *name)
+priv_iface_init(int index)
{
int cmd, rc;
cmd = PRIV_IFACE_INIT;
must_write(remote, &cmd, sizeof(int));
- must_write(remote, name, IFNAMSIZ);
+ must_write(remote, &index, sizeof(int));
must_read(remote, &rc, sizeof(int));
if (rc != 0) return -1;
return receive_fd(remote);
SYSFS_CLASS_NET "[^.][^/]*/brforward",
SYSFS_CLASS_NET "[^.][^/]*/brport",
SYSFS_CLASS_NET "[^.][^/]*/brif/[^.][^/]*/port_no",
- SYSFS_CLASS_NET "[^.][^/]*/ifalias",
SYSFS_CLASS_DMI "product_version",
SYSFS_CLASS_DMI "product_serial",
SYSFS_CLASS_DMI "product_name",
close(fd);
}
+#ifdef HOST_OS_LINUX
+#include <linux/ethtool.h>
+#include <linux/sockios.h>
static void
asroot_ethtool()
{
must_write(remote, &rc, sizeof(int));
must_write(remote, ðc, sizeof(struct ethtool_cmd));
}
+#endif
static void
asroot_iface_init()
{
struct sockaddr_ll sa;
int s, rc = 0;
- char ifname[IFNAMSIZ];
+ int ifindex;
- must_read(remote, ifname, IFNAMSIZ);
- ifname[IFNAMSIZ-1] = '\0';
+ must_read(remote, &ifindex, sizeof(ifindex));
/* Open listening socket to receive/send frames */
if ((s = socket(PF_PACKET, SOCK_RAW,
memset(&sa, 0, sizeof(sa));
sa.sll_family = AF_PACKET;
sa.sll_protocol = 0;
- sa.sll_ifindex = if_nametoindex(ifname);
+ sa.sll_ifindex = ifindex;
if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
rc = errno;
must_write(remote, &rc, sizeof(rc));
void
lldpd_chassis_cleanup(struct lldpd_chassis *chassis, int all)
{
+ lldpd_chassis_mgmt_cleanup(chassis);
log_debug("alloc", "cleanup chassis %s",
chassis->c_name ? chassis->c_name : "(unknwon)");
#ifdef ENABLE_LLDPMED
free(chassis->c_id);
free(chassis->c_name);
free(chassis->c_descr);
- lldpd_chassis_mgmt_cleanup(chassis);
if (all)
free(chassis);
}
#include <sys/types.h>
#include <sys/socket.h>
-#ifndef INCLUDE_LINUX_IF_H
-# include <net/if.h>
+
+/* This is not very convenient, but we need net/if.h for IFNAMSIZ and others but
+ * we may also need linux/if.h in some modules. And they conflict each others.
+ */
+#ifdef HOST_OS_LINUX
+# include <linux/if.h>
#else
-# include <arpa/inet.h>
-# include <linux/if.h>
+# include <net/if.h>
#endif
+
#include <net/ethernet.h>
#include <netinet/in.h>
#include <sys/queue.h>
-TESTS = check_marshal check_lldp check_cdp check_sonmp check_edp check_ifaddrs
+TESTS = check_marshal check_lldp check_cdp check_sonmp check_edp
if HAVE_CHECK
$(top_srcdir)/src/daemon/lldpd.h \
common.h common.c
-check_ifaddrs_SOURCES = check_ifaddrs.c \
- $(top_srcdir)/src/daemon/lldpd.h \
- $(top_srcdir)/src/compat/getifaddrs.c
-
AM_CFLAGS = @CHECK_CFLAGS@
LDADD = $(top_builddir)/src/daemon/liblldpd.la @CHECK_LIBS@ @LIBEVENT_LDFLAGS@
+++ /dev/null
-#include <stdio.h>
-#include <arpa/inet.h>
-#include <check.h>
-#include "common.h"
-
-#define DUMP "ifdump.txt"
-
-/* This is not a real test. It should dump into a file the list of interfaces */
-
-static const char *
-addr_string (struct sockaddr *sa) {
- static char buf[64];
- const char *res;
- if (sa == NULL)
- return "NULL";
- switch (sa->sa_family) {
- case AF_INET:
- res = inet_ntop(AF_INET,
- &((struct sockaddr_in *)sa)->sin_addr,
- buf, sizeof(buf));
- break;
- case AF_INET6:
- res = inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *)sa)->sin6_addr,
- buf, sizeof(buf));
- break;
- case AF_UNSPEC:
- return "<--->";
- case AF_PACKET:
- return "<pkt>";
- default:
- snprintf(buf, 64, "<%4d>", sa->sa_family);
- return buf;
- }
- strcpy(buf, res);
- if (strlen(buf) > 26)
- memcpy(buf + 21, "[...]", strlen("[...]") + 1);
- return buf;
-}
-
-START_TEST (test_ifaddrs)
-{
- struct ifaddrs *ifap, *ifa;
- FILE* dump;
-
- if (getifaddrs(&ifap) < 0) {
- fail("unable to get interface list");
- return;
- }
- dump = fopen(DUMP, "w+");
- if (dump == NULL) {
- fail("unable to open dump file " DUMP);
- return;
- }
- fprintf(dump,
- "Name Flags Address Netmask Broadcast/Destination\n");
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- fprintf(dump, "%-15s%#.5x ",
- ifa->ifa_name, ifa->ifa_flags);
- fprintf(dump, "%-26s ",
- addr_string(ifa->ifa_addr));
- fprintf(dump, "%-26s ",
- addr_string(ifa->ifa_netmask));
- fprintf(dump, "%-26s\n",
- addr_string(ifa->ifa_broadaddr));
- }
- fclose(dump);
-}
-END_TEST
-
-Suite *
-ifaddrs_suite(void)
-{
- Suite *s = suite_create("getifaddrs");
-
- /* Single objects packing/unpacking */
- TCase *tc_core = tcase_create("getifaddrs");
- tcase_add_test(tc_core, test_ifaddrs);
- suite_add_tcase(s, tc_core);
-
- return s;
-}
-
-int
-main()
-{
- int number_failed;
- Suite *s = ifaddrs_suite ();
- SRunner *sr = srunner_create (s);
- srunner_run_all (sr, CK_ENV);
- number_failed = srunner_ntests_failed (sr);
- srunner_free (sr);
- return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
-}