From 32d2064523461b3761b51ad9c38f098c9ac2dbc9 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 19:33:36 +0100 Subject: libsystemd-network: sd-event uses 64bit priorities, expose them in the APIs as such --- src/libsystemd/sd-netlink/sd-netlink.c | 2 +- src/libsystemd/sd-resolve/sd-resolve.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/libsystemd') diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 4833815b43..f5c2b33f46 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -774,7 +774,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) { return 1; } -int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int priority) { +int sd_netlink_attach_event(sd_netlink *rtnl, sd_event *event, int64_t priority) { int r; assert_return(rtnl, -EINVAL); diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index d693b2c2b0..910e75441f 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -1191,7 +1191,7 @@ static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userd return 1; } -_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int priority) { +_public_ int sd_resolve_attach_event(sd_resolve *resolve, sd_event *event, int64_t priority) { int r; assert_return(resolve, -EINVAL); -- cgit v1.2.3-54-g00ecf From 0ef6f4542584873e10d5c942105ad0ffc53d6108 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 16 Feb 2016 20:05:15 +0100 Subject: tree-wide: place #pragma once at the same place everywhere Usually, we place the #pragma once before the copyright blurb in header files, but in a few cases we didn't. Move those around, so that we do the same thing everywhere. --- src/analyze/analyze-verify.h | 4 ++-- src/basic/btrfs-util.h | 4 ++-- src/basic/gunicode.h | 4 ++-- src/basic/login-util.h | 4 ++-- src/basic/sigbus.h | 4 ++-- src/journal-remote/journal-remote-parse.h | 4 ++-- src/journal-remote/journal-remote-write.h | 5 ++--- src/journal-remote/journal-remote.h | 5 ++--- src/journal-remote/microhttpd-util.h | 4 ++-- src/libsystemd-network/dhcp-server-internal.h | 4 ++-- src/libsystemd-network/lldp-internal.h | 4 ++-- src/libsystemd-network/lldp-network.c | 1 - src/libsystemd-network/lldp-network.h | 4 ++-- src/libsystemd-network/lldp-tlv.h | 4 ++-- src/libsystemd-network/lldp.h | 4 ++-- src/libsystemd/sd-device/device-internal.h | 4 ++-- src/libsystemd/sd-hwdb/hwdb-internal.h | 3 ++- src/libudev/libudev-device-internal.h | 4 ++-- src/network/networkd-netdev-bridge.h | 4 ++-- src/network/networkd-netdev-dummy.h | 4 ++-- src/network/networkd-netdev-ipvlan.h | 4 ++-- src/network/networkd-netdev-macvlan.h | 4 ++-- src/network/networkd-netdev-tunnel.h | 4 ++-- src/network/networkd-netdev-tuntap.h | 4 ++-- src/network/networkd-netdev-veth.h | 4 ++-- src/network/networkd-netdev-vlan.h | 4 ++-- src/network/networkd-netdev-vxlan.h | 4 ++-- src/network/networkd-netdev.h | 4 ++-- src/network/networkd-wait-online.h | 4 ++-- src/network/networkd.h | 4 ++-- src/resolve/dns-type.h | 4 ++-- src/shared/dns-domain.h | 5 ++--- src/shared/gpt.h | 4 ++-- src/shared/install-printf.h | 4 ++-- src/shared/sleep-config.h | 4 ++-- src/udev/mtd_probe/mtd_probe.h | 4 ++-- src/udev/net/ethtool-util.h | 4 ++-- src/udev/net/link-config.h | 4 ++-- src/udev/scsi_id/scsi.h | 4 ++-- src/udev/scsi_id/scsi_id.h | 4 ++-- src/udev/udev.h | 4 ++-- src/udev/udevadm-util.h | 4 ++-- 42 files changed, 82 insertions(+), 85 deletions(-) (limited to 'src/libsystemd') diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h index 54adad93e1..27c253a562 100644 --- a/src/analyze/analyze-verify.h +++ b/src/analyze/analyze-verify.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include "path-lookup.h" diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 37802c2565..1d852d502c 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include #include diff --git a/src/basic/gunicode.h b/src/basic/gunicode.h index b03aa43160..5975bc8fc9 100644 --- a/src/basic/gunicode.h +++ b/src/basic/gunicode.h @@ -1,11 +1,11 @@ +#pragma once + /* gunicode.h - Unicode manipulation functions * * Copyright (C) 1999, 2000 Tom Tromey * Copyright 2000, 2005 Red Hat, Inc. */ -#pragma once - #include #include #include diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 89a337d7c1..b01ee25c88 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include diff --git a/src/basic/sigbus.h b/src/basic/sigbus.h index cce9eb201b..980243d9ce 100644 --- a/src/basic/sigbus.h +++ b/src/basic/sigbus.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - void sigbus_install(void); void sigbus_reset(void); diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h index 0b8b6af736..1740a21f92 100644 --- a/src/journal-remote/journal-remote-parse.h +++ b/src/journal-remote/journal-remote-parse.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-event.h" #include "journal-remote-write.h" diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h index 6b645a353c..53ba45fc04 100644 --- a/src/journal-remote/journal-remote-write.h +++ b/src/journal-remote/journal-remote-write.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - - #include "journal-file.h" typedef struct RemoteServer RemoteServer; diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h index 6466a1c101..30ad7df996 100644 --- a/src/journal-remote/journal-remote.h +++ b/src/journal-remote/journal-remote.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - - #include "sd-event.h" #include "hashmap.h" diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h index 70c4d29c0f..ea160f212b 100644 --- a/src/journal-remote/microhttpd-util.h +++ b/src/journal-remote/microhttpd-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index bf123f1439..adb557167a 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-dhcp-server.h" #include "sd-event.h" diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 15b4a11b15..9122879e7e 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-event.h" #include "list.h" diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index c81ac6b893..10729e77b2 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -53,7 +53,6 @@ int lldp_network_bind_raw_socket(int ifindex) { }; _cleanup_close_ int fd = -1; - int r; assert(ifindex > 0); diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h index dcf31faa95..c4cf8c79f1 100644 --- a/src/libsystemd-network/lldp-network.h +++ b/src/libsystemd-network/lldp-network.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-event.h" int lldp_network_bind_raw_socket(int ifindex); diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index 8e7706c612..1ddca2882f 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include "sd-lldp.h" diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h index f881f490b4..88bef687eb 100644 --- a/src/libsystemd-network/lldp.h +++ b/src/libsystemd-network/lldp.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } /* IEEE 802.3AB Clause 9: TLV Types */ diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h index b96441de56..ab222e27de 100644 --- a/src/libsystemd/sd-device/device-internal.h +++ b/src/libsystemd/sd-device/device-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "hashmap.h" #include "set.h" diff --git a/src/libsystemd/sd-hwdb/hwdb-internal.h b/src/libsystemd/sd-hwdb/hwdb-internal.h index 13fddfc8ad..8ffb5e5c74 100644 --- a/src/libsystemd/sd-hwdb/hwdb-internal.h +++ b/src/libsystemd/sd-hwdb/hwdb-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -16,7 +18,6 @@ You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ -#pragma once #include "sparse-endian.h" #include "util.h" diff --git a/src/libudev/libudev-device-internal.h b/src/libudev/libudev-device-internal.h index 40d59201cf..0e9af8ec09 100644 --- a/src/libudev/libudev-device-internal.h +++ b/src/libudev/libudev-device-internal.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -18,8 +20,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "libudev.h" #include "sd-device.h" diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index b2bf7e15f1..27f26f7870 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct Bridge Bridge; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h index 29f75a149b..42da62ebe4 100644 --- a/src/network/networkd-netdev-dummy.h +++ b/src/network/networkd-netdev-dummy.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct Dummy Dummy; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/networkd-netdev-ipvlan.h index 5b85ef2150..4bd0b67866 100644 --- a/src/network/networkd-netdev-ipvlan.h +++ b/src/network/networkd-netdev-ipvlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct IPVlan IPVlan; #include "missing.h" diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h index 8b42684de6..622ef9ef53 100644 --- a/src/network/networkd-netdev-macvlan.h +++ b/src/network/networkd-netdev-macvlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct MacVlan MacVlan; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index ea1d9a79e7..0d41f80a3c 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct Tunnel Tunnel; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h index b970b0ce3b..cbb7ee05a6 100644 --- a/src/network/networkd-netdev-tuntap.h +++ b/src/network/networkd-netdev-tuntap.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct TunTap TunTap; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h index f7fdf906ab..ae5785783c 100644 --- a/src/network/networkd-netdev-veth.h +++ b/src/network/networkd-netdev-veth.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct Veth Veth; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h index 8701c4b785..1de6a1cc36 100644 --- a/src/network/networkd-netdev-vlan.h +++ b/src/network/networkd-netdev-vlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct VLan VLan; #include "networkd-netdev.h" diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index 459ce53f5e..a4bb44635a 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - typedef struct VxLan VxLan; #include "in-addr-util.h" diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 3eacee824b..7ea825fcb4 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "list.h" typedef struct NetDev NetDev; diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h index 421c2bdf44..f91995c306 100644 --- a/src/network/networkd-wait-online.h +++ b/src/network/networkd-wait-online.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "sd-event.h" #include "sd-netlink.h" #include "sd-network.h" diff --git a/src/network/networkd.h b/src/network/networkd.h index 7ee922621a..6bdd8302a0 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include "sd-bus.h" diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index db9666b970..7b79d29d7e 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "macro.h" /* DNS record types, taken from diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 2de3642cb3..af780f0b8b 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,9 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - - #include #include #include diff --git a/src/shared/gpt.h b/src/shared/gpt.h index 52ab29ed5f..55b41bbcd8 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include #include "sd-id128.h" diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h index acf519f4f7..8a570fc265 100644 --- a/src/shared/install-printf.h +++ b/src/shared/install-printf.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "install.h" int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret); diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h index 51f4621844..ad10039ff4 100644 --- a/src/shared/sleep-config.h +++ b/src/shared/sleep-config.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - int parse_sleep_config(const char *verb, char ***modes, char ***states); int can_sleep(const char *verb); diff --git a/src/udev/mtd_probe/mtd_probe.h b/src/udev/mtd_probe/mtd_probe.h index caea5c2693..68e4954537 100644 --- a/src/udev/mtd_probe/mtd_probe.h +++ b/src/udev/mtd_probe/mtd_probe.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2010 - Maxim Levitsky * @@ -17,8 +19,6 @@ * Boston, MA 02110-1301 USA */ -#pragma once - #include #include "macro.h" diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h index 2e6e1d7150..7716516e76 100644 --- a/src/udev/net/ethtool-util.h +++ b/src/udev/net/ethtool-util.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include /* we can't use DUPLEX_ prefix, as it diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index f525fe2116..9df5529d05 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -1,3 +1,5 @@ +#pragma once + /*** This file is part of systemd. @@ -17,8 +19,6 @@ along with systemd; If not, see . ***/ -#pragma once - #include "libudev.h" #include "condition.h" diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h index 3bf1a94200..a27a84a40a 100644 --- a/src/udev/scsi_id/scsi.h +++ b/src/udev/scsi_id/scsi.h @@ -1,3 +1,5 @@ +#pragma once + /* * scsi.h * @@ -10,8 +12,6 @@ * Free Software Foundation version 2 of the License. */ -#pragma once - #include struct scsi_ioctl_command { diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h index 141b116a88..5c2e1c28ee 100644 --- a/src/udev/scsi_id/scsi_id.h +++ b/src/udev/scsi_id/scsi_id.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) IBM Corp. 2003 * @@ -15,8 +17,6 @@ * along with this program. If not, see . */ -#pragma once - #define MAX_PATH_LEN 512 /* diff --git a/src/udev/udev.h b/src/udev/udev.h index 1f9c8120c0..068713327d 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2003 Greg Kroah-Hartman * Copyright (C) 2003-2010 Kay Sievers @@ -16,8 +18,6 @@ * along with this program. If not, see . */ -#pragma once - #include #include diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h index 37e4fe8369..dc712b0d93 100644 --- a/src/udev/udevadm-util.h +++ b/src/udev/udevadm-util.h @@ -1,3 +1,5 @@ +#pragma once + /* * Copyright (C) 2014 Zbigniew JÄ™drzejewski-Szmek * @@ -15,8 +17,6 @@ * along with this program. If not, see . */ -#pragma once - #include "udev.h" struct udev_device *find_device(struct udev *udev, -- cgit v1.2.3-54-g00ecf From 1c4a6088ed13c449db16191890b20d20574e6ac0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Feb 2016 22:47:34 +0100 Subject: sd-netlink: fix ifi_iftype type The iftype is an unsigned short, and not just an unsigned. --- src/libsystemd/sd-netlink/rtnl-message.c | 2 +- src/network/networkctl.c | 8 ++++---- src/systemd/sd-netlink.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/libsystemd') diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 090552f576..255526bf32 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -616,7 +616,7 @@ int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) { return 0; } -int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type) { +int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) { struct ifinfomsg *ifi; assert_return(m, -EINVAL); diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 60724fce80..185bdaf293 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -58,7 +58,7 @@ static void pager_open_if_enabled(void) { pager_open(false); } -static int link_get_type_string(int iftype, sd_device *d, char **ret) { +static int link_get_type_string(unsigned short iftype, sd_device *d, char **ret) { const char *t; char *p; @@ -106,7 +106,7 @@ static int link_get_type_string(int iftype, sd_device *d, char **ret) { typedef struct LinkInfo { const char *name; int ifindex; - unsigned iftype; + unsigned short iftype; } LinkInfo; static int link_info_compare(const void *a, const void *b) { @@ -123,7 +123,7 @@ static int decode_and_sort_links(sd_netlink_message *m, LinkInfo **ret) { for (i = m; i; i = sd_netlink_message_next(i)) { const char *name; - unsigned iftype; + unsigned short iftype; uint16_t type; int ifindex; @@ -515,7 +515,7 @@ static int link_status_one( _cleanup_strv_free_ char **carrier_bound_to = NULL; _cleanup_strv_free_ char **carrier_bound_by = NULL; struct ether_addr e; - unsigned iftype; + unsigned short iftype; int r, ifindex; bool have_mac; uint32_t mtu; diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 71bcd24014..af7a797567 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -131,7 +131,7 @@ int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type); int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family); int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex); int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags); -int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned *type); +int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type); int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen); -- cgit v1.2.3-54-g00ecf From 34437b4f9c9c51b0a6f93788bdb9a105b8e46b66 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 17:58:52 +0100 Subject: sd-lldp: rework sd-lldp API This reworks the sd-lldp substantially, simplifying things on one hand, and extending the logic a bit on the other. Specifically: - Besides the sd_lldp object only one other object is maintained now, sd_lldp_neighbor. It's used both as storage for literal LLDP packets, and for maintainging info about peers in the database. Separation between packet, TLV and chassis data is not maintained anymore. This should be a major simplification. - The sd-lldp API has been extended so that a couple of per-neighbor fields may be queried directly, without iterating through the object. Other fields that may appear multiple times, OTOH have to be iterated through. - The maximum number of entries in the neighbor database is now configurable during runtime. - The generation of callbacks from sd_lldp objects is more restricted: callbacks are only invoked when actual data changed. - The TTL information is now hooked with a timer event, so that removals from the neighbor database due to TTLs now result in a callback event. - Querying LLDP neighbor database will now return a strictly ordered array, to guarantee stability. - A "capabilities" mask may now be configured, that selects what type of LLDP neighbor data is collected. This may be used to restrict collection of LLDP info about routers instead of all neighbors. This is now exposed via networkd's LLDP= setting. - sd-lldp's API to serialize the collected data to text files has been removed. Instead, there's now an API to extract the raw binary data from LLDP neighbor objects, as well as one to convert this raw binary data back to an LLDP neighbor object. networkd will save this raw binary data to /run now, and the client side can simply parse the information. - support for parsing the more exotic TLVs has been removed, since we are not using that. Instead there are now APIs to extract the raw data from TLVs. Given how easy it is to parse the TLVs clients should do so now directly instead of relying on our APIs for that. - A lot of the APIs that parse out LLDP strings have been simplified so that they actually return strings, instead of char arrays with a length. To deal with possibly dangerous characters the strings are escaped if needed. - APIs to extract and format the chassis and port IDs as strings has been added. - lldp.h has been simplified a lot. The enums are anonymous now, since they were never used as enums, but simply as constants. Most definitions we don't actually use ourselves have eben removed. --- Makefile.am | 9 +- man/systemd.network.xml | 8 +- src/libsystemd-network/lldp-internal.c | 360 -------------- src/libsystemd-network/lldp-internal.h | 74 +-- src/libsystemd-network/lldp-neighbor.c | 792 +++++++++++++++++++++++++++++++ src/libsystemd-network/lldp-neighbor.h | 106 +++++ src/libsystemd-network/lldp-tlv.c | 638 ------------------------- src/libsystemd-network/lldp-tlv.h | 94 ---- src/libsystemd-network/lldp.h | 78 ++- src/libsystemd-network/sd-lldp.c | 731 ++++++++++------------------ src/libsystemd-network/test-lldp.c | 320 +++---------- src/libsystemd/sd-network/sd-network.c | 27 +- src/network/networkctl.c | 293 ++++-------- src/network/networkd-link.c | 124 +++-- src/network/networkd-network-gperf.gperf | 2 +- src/network/networkd-network.c | 10 + src/network/networkd-network.h | 14 +- src/systemd/sd-lldp.h | 76 +-- src/systemd/sd-network.h | 2 - 19 files changed, 1491 insertions(+), 2267 deletions(-) delete mode 100644 src/libsystemd-network/lldp-internal.c create mode 100644 src/libsystemd-network/lldp-neighbor.c create mode 100644 src/libsystemd-network/lldp-neighbor.h delete mode 100644 src/libsystemd-network/lldp-tlv.c delete mode 100644 src/libsystemd-network/lldp-tlv.h (limited to 'src/libsystemd') diff --git a/Makefile.am b/Makefile.am index 06ca3532b4..70fcedf0da 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3299,12 +3299,10 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/dhcp-identifier.h \ src/libsystemd-network/dhcp-identifier.c \ src/libsystemd-network/lldp.h \ - src/libsystemd-network/lldp-tlv.h \ - src/libsystemd-network/lldp-tlv.c \ src/libsystemd-network/lldp-network.h \ src/libsystemd-network/lldp-network.c \ - src/libsystemd-network/lldp-internal.h \ - src/libsystemd-network/lldp-internal.c \ + src/libsystemd-network/lldp-neighbor.h \ + src/libsystemd-network/lldp-neighbor.c \ src/libsystemd-network/sd-lldp.c libsystemd_network_la_LIBADD = \ @@ -3387,9 +3385,6 @@ test_dhcp6_client_LDADD = \ libshared.la test_lldp_SOURCES = \ - src/libsystemd-network/lldp.h \ - src/libsystemd-network/lldp-tlv.h \ - src/libsystemd-network/lldp-tlv.c \ src/libsystemd-network/test-lldp.c test_lldp_LDADD = \ diff --git a/man/systemd.network.xml b/man/systemd.network.xml index adfe1ac9b3..2de2a550db 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -335,7 +335,13 @@ LLDP= - A boolean. When true, enables LLDP link receive support. + Controls support for LLDP reception. Accepts a boolean or the special value + routers-only. When true, incoming LLDP packets are accepted and a database of all LLDP + neighbors maintained. If routers-only is set only LLDP data of various types of routers + is collected and LLDP data about other types of devices ignored (such as stations, telephones and + others). If false, LLDP reception is disabled. Defaults to false. Use + networkctl1 to query the + collected neighbor data. diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c deleted file mode 100644 index c8740ce5f0..0000000000 --- a/src/libsystemd-network/lldp-internal.c +++ /dev/null @@ -1,360 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd 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; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include "sd-lldp.h" - -#include "alloc-util.h" -#include "lldp-internal.h" - -/* We store maximum 1K chassis entries */ -#define LLDP_MIB_MAX_CHASSIS 1024 - -/* Maximum Ports can be attached to any chassis */ -#define LLDP_MIB_MAX_PORT_PER_CHASSIS 32 - -/* 10.5.5.2.2 mibUpdateObjects () - * The mibUpdateObjects () procedure updates the MIB objects corresponding to - * the TLVs contained in the received LLDPDU for the LLDP remote system - * indicated by the LLDP remote systems update process defined in 10.3.5 */ - -int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv) { - lldp_neighbour_port *p; - uint16_t length, ttl; - uint8_t *data; - uint8_t type; - int r; - - assert_return(c, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - /* Update the packet if we already have */ - LIST_FOREACH(port, p, c->ports) { - - if ((p->type == type && p->length == length && !memcmp(p->data, data, p->length))) { - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - return r; - - p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - - sd_lldp_packet_unref(p->packet); - p->packet = tlv; - - prioq_reshuffle(p->c->by_expiry, p, &p->prioq_idx); - - return 0; - } - } - - return -1; -} - -int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv) { - lldp_neighbour_port *p, *q; - uint8_t *data; - uint16_t length; - uint8_t type; - int r; - - assert_return(c, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - LIST_FOREACH_SAFE(port, p, q, c->ports) { - - /* Find the port */ - if (p->type == type && p->length == length && !memcmp(p->data, data, p->length)) { - lldp_neighbour_port_remove_and_free(p); - break; - } - } - - return 0; -} - -int lldp_mib_add_objects(Prioq *by_expiry, - Hashmap *neighbour_mib, - tlv_packet *tlv) { - _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; - _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; - lldp_chassis_id chassis_id; - bool new_chassis = false; - uint8_t subtype, *data; - uint16_t ttl, length; - int r; - - assert_return(by_expiry, -EINVAL); - assert_return(neighbour_mib, -EINVAL); - assert_return(tlv, -EINVAL); - - r = sd_lldp_packet_read_chassis_id(tlv, &subtype, &data, &length); - if (r < 0) - goto drop; - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - goto drop; - - /* Make hash key */ - chassis_id.type = subtype; - chassis_id.length = length; - chassis_id.data = data; - - /* Try to find the Chassis */ - c = hashmap_get(neighbour_mib, &chassis_id); - if (!c) { - - /* Don't create chassis if ttl 0 is received . Silently drop it */ - if (ttl == 0) { - log_lldp("TTL value 0 received. Skiping Chassis creation."); - goto drop; - } - - /* Admission Control: Can we store this packet ? */ - if (hashmap_size(neighbour_mib) >= LLDP_MIB_MAX_CHASSIS) { - - log_lldp("Exceeding number of chassie: %d. Dropping ...", - hashmap_size(neighbour_mib)); - goto drop; - } - - r = lldp_chassis_new(tlv, by_expiry, neighbour_mib, &c); - if (r < 0) - goto drop; - - new_chassis = true; - - r = hashmap_put(neighbour_mib, &c->chassis_id, c); - if (r < 0) - goto drop; - - } else { - - /* When the TTL field is set to zero, the receiving LLDP agent is notified all - * system information associated with the LLDP agent/port is to be deleted */ - if (ttl == 0) { - log_lldp("TTL value 0 received . Deleting associated Port ..."); - - lldp_mib_remove_objects(c, tlv); - - c = NULL; - goto drop; - } - - /* if we already have this port just update it */ - r = lldp_mib_update_objects(c, tlv); - if (r >= 0) { - c = NULL; - return r; - } - - /* Admission Control: Can this port attached to the existing chassis ? */ - if (c->n_ref >= LLDP_MIB_MAX_PORT_PER_CHASSIS) { - log_lldp("Port limit reached. Chassis has: %d ports. Dropping ...", c->n_ref); - - c = NULL; - goto drop; - } - } - - /* This is a new port */ - r = lldp_neighbour_port_new(c, tlv, &p); - if (r < 0) - goto drop; - - r = prioq_put(c->by_expiry, p, &p->prioq_idx); - if (r < 0) - goto drop; - - /* Attach new port to chassis */ - LIST_PREPEND(port, c->ports, p); - c->n_ref ++; - - p = NULL; - c = NULL; - - return 0; - - drop: - sd_lldp_packet_unref(tlv); - - if (new_chassis) - hashmap_remove(neighbour_mib, &c->chassis_id); - - return r; -} - -void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p) { - lldp_chassis *c; - - assert(p); - assert(p->c); - - c = p->c; - - prioq_remove(c->by_expiry, p, &p->prioq_idx); - - LIST_REMOVE(port, c->ports, p); - lldp_neighbour_port_free(p); - - /* Drop the Chassis if no port is attached */ - c->n_ref --; - if (c->n_ref <= 1) { - hashmap_remove(c->neighbour_mib, &c->chassis_id); - lldp_chassis_free(c); - } -} - -void lldp_neighbour_port_free(lldp_neighbour_port *p) { - - if(!p) - return; - - sd_lldp_packet_unref(p->packet); - - free(p->data); - free(p); -} - -int lldp_neighbour_port_new(lldp_chassis *c, - tlv_packet *tlv, - lldp_neighbour_port **ret) { - _cleanup_lldp_neighbour_port_free_ lldp_neighbour_port *p = NULL; - uint16_t length, ttl; - uint8_t *data; - uint8_t type; - int r; - - assert(tlv); - - r = sd_lldp_packet_read_port_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - r = sd_lldp_packet_read_ttl(tlv, &ttl); - if (r < 0) - return r; - - p = new0(lldp_neighbour_port, 1); - if (!p) - return -ENOMEM; - - p->c = c; - p->type = type; - p->length = length; - p->packet = tlv; - p->prioq_idx = PRIOQ_IDX_NULL; - p->until = ttl * USEC_PER_SEC + now(clock_boottime_or_monotonic()); - - p->data = memdup(data, length); - if (!p->data) - return -ENOMEM; - - *ret = p; - p = NULL; - - return 0; -} - -void lldp_chassis_free(lldp_chassis *c) { - - if (!c) - return; - - if (c->n_ref > 1) - return; - - free(c->chassis_id.data); - free(c); -} - -int lldp_chassis_new(tlv_packet *tlv, - Prioq *by_expiry, - Hashmap *neighbour_mib, - lldp_chassis **ret) { - _cleanup_lldp_chassis_free_ lldp_chassis *c = NULL; - uint16_t length; - uint8_t *data; - uint8_t type; - int r; - - assert(tlv); - - r = sd_lldp_packet_read_chassis_id(tlv, &type, &data, &length); - if (r < 0) - return r; - - c = new0(lldp_chassis, 1); - if (!c) - return -ENOMEM; - - c->n_ref = 1; - c->chassis_id.type = type; - c->chassis_id.length = length; - - c->chassis_id.data = memdup(data, length); - if (!c->chassis_id.data) - return -ENOMEM; - - LIST_HEAD_INIT(c->ports); - - c->by_expiry = by_expiry; - c->neighbour_mib = neighbour_mib; - - *ret = c; - c = NULL; - - return 0; -} - -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *packet = NULL; - tlv_packet *p; - uint16_t length; - int r; - - assert(fd); - assert(userdata); - - r = tlv_packet_new(&packet); - if (r < 0) - return r; - - length = read(fd, &packet->pdu, sizeof(packet->pdu)); - - /* Silently drop the packet */ - if ((size_t) length > ETHER_MAX_LEN) - return 0; - - packet->userdata = userdata; - - p = packet; - packet = NULL; - - return lldp_handle_packet(p, (uint16_t) length); -} diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 9122879e7e..279975b5c2 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -21,71 +21,31 @@ ***/ #include "sd-event.h" +#include "sd-lldp.h" -#include "list.h" -#include "lldp-tlv.h" +#include "hashmap.h" #include "log.h" #include "prioq.h" -typedef struct lldp_neighbour_port lldp_neighbour_port; -typedef struct lldp_chassis lldp_chassis; -typedef struct lldp_chassis_id lldp_chassis_id; -typedef struct lldp_agent_statistics lldp_agent_statistics; +struct sd_lldp { + int ifindex; + int fd; -struct lldp_neighbour_port { - uint8_t type; - uint8_t *data; + sd_event *event; + int64_t event_priority; + sd_event_source *io_event_source; + sd_event_source *timer_event_source; - uint16_t length; - usec_t until; + Prioq *neighbor_by_expiry; + Hashmap *neighbor_by_id; - unsigned prioq_idx; + uint64_t neighbors_max; - lldp_chassis *c; - tlv_packet *packet; + sd_lldp_callback_t callback; + void *userdata; - LIST_FIELDS(lldp_neighbour_port, port); + uint16_t capability_mask; }; -int lldp_neighbour_port_new(lldp_chassis *c, tlv_packet *tlv, lldp_neighbour_port **ret); -void lldp_neighbour_port_free(lldp_neighbour_port *p); -void lldp_neighbour_port_remove_and_free(lldp_neighbour_port *p); - -DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_neighbour_port *, lldp_neighbour_port_free); -#define _cleanup_lldp_neighbour_port_free_ _cleanup_(lldp_neighbour_port_freep) - -struct lldp_chassis_id { - uint8_t type; - uint16_t length; - - uint8_t *data; -}; - -struct lldp_chassis { - unsigned n_ref; - - lldp_chassis_id chassis_id; - - Prioq *by_expiry; - Hashmap *neighbour_mib; - - LIST_HEAD(lldp_neighbour_port, ports); -}; - -int lldp_chassis_new(tlv_packet *tlv, - Prioq *by_expiry, - Hashmap *neighbour_mib, - lldp_chassis **ret); - -void lldp_chassis_free(lldp_chassis *c); - -DEFINE_TRIVIAL_CLEANUP_FUNC(lldp_chassis *, lldp_chassis_free); -#define _cleanup_lldp_chassis_free_ _cleanup_(lldp_chassis_freep) - -int lldp_mib_update_objects(lldp_chassis *c, tlv_packet *tlv); -int lldp_mib_add_objects(Prioq *by_expiry, Hashmap *neighbour_mib, tlv_packet *tlv); -int lldp_mib_remove_objects(lldp_chassis *c, tlv_packet *tlv); - -int lldp_handle_packet(tlv_packet *m, uint16_t length); -int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata); -#define log_lldp(fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) +#define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, __FILE__, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) +#define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__) diff --git a/src/libsystemd-network/lldp-neighbor.c b/src/libsystemd-network/lldp-neighbor.c new file mode 100644 index 0000000000..c61941cd70 --- /dev/null +++ b/src/libsystemd-network/lldp-neighbor.c @@ -0,0 +1,792 @@ +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd 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; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include "alloc-util.h" +#include "escape.h" +#include "ether-addr-util.h" +#include "hexdecoct.h" +#include "in-addr-util.h" +#include "lldp-internal.h" +#include "lldp-neighbor.h" +#include "lldp.h" +#include "unaligned.h" + +static void lldp_neighbor_id_hash_func(const void *p, struct siphash *state) { + const LLDPNeighborID *id = p; + + siphash24_compress(id->chassis_id, id->chassis_id_size, state); + siphash24_compress(&id->chassis_id_size, sizeof(id->chassis_id_size), state); + siphash24_compress(id->port_id, id->port_id_size, state); + siphash24_compress(&id->port_id_size, sizeof(id->port_id_size), state); +} + +static int lldp_neighbor_id_compare_func(const void *a, const void *b) { + const LLDPNeighborID *x = a, *y = b; + int r; + + r = memcmp(x->chassis_id, y->chassis_id, MIN(x->chassis_id_size, y->chassis_id_size)); + if (r != 0) + return r; + + if (x->chassis_id_size < y->chassis_id_size) + return -1; + + if (x->chassis_id_size > y->chassis_id_size) + return 1; + + r = memcmp(x->port_id, y->port_id, MIN(x->port_id_size, y->port_id_size)); + if (r != 0) + return r; + + if (x->port_id_size < y->port_id_size) + return -1; + if (x->port_id_size > y->port_id_size) + return 1; + + return 0; +} + +const struct hash_ops lldp_neighbor_id_hash_ops = { + .hash = lldp_neighbor_id_hash_func, + .compare = lldp_neighbor_id_compare_func +}; + +int lldp_neighbor_prioq_compare_func(const void *a, const void *b) { + const sd_lldp_neighbor *x = a, *y = b; + + if (x->until < y->until) + return -1; + + if (x->until > y->until) + return 1; + + return 0; +} + +_public_ sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n) { + if (!n) + return NULL; + + assert(n->n_ref > 0 || n->lldp); + n->n_ref++; + + return n; +} + +static void lldp_neighbor_free(sd_lldp_neighbor *n) { + assert(n); + + free(n->id.port_id); + free(n->id.chassis_id); + free(n->port_description); + free(n->system_name); + free(n->system_description); + free(n->chassis_id_as_string); + free(n->port_id_as_string); + free(n); +} + +_public_ sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n) { + + /* Drops one reference from the neighbor. Note that the object is not freed unless it is already unlinked from + * the sd_lldp object. */ + + if (!n) + return NULL; + + assert(n->n_ref > 0); + n->n_ref--; + + if (n->n_ref <= 0 && !n->lldp) + lldp_neighbor_free(n); + + return NULL; +} + +sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) { + + /* Removes the neighbor object from the LLDP object, and frees it if it also has no other reference. */ + + if (!n) + return NULL; + + if (!n->lldp) + return NULL; + + assert_se(hashmap_remove(n->lldp->neighbor_by_id, &n->id) == n); + assert_se(prioq_remove(n->lldp->neighbor_by_expiry, n, &n->prioq_idx) >= 0); + + n->lldp = NULL; + + if (n->n_ref <= 0) + lldp_neighbor_free(n); + + return NULL; +} + +sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) { + sd_lldp_neighbor *n; + + n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size); + if (!n) + return NULL; + + n->raw_size = raw_size; + n->n_ref = 1; + + return n; +} + +static int parse_string(char **s, const void *q, size_t n) { + const char *p = q; + char *k; + + assert(s); + assert(p || n == 0); + + if (*s) { + log_lldp("Found duplicate string, ignoring field."); + return 0; + } + + /* Strip trailing NULs, just to be nice */ + while (n > 0 && p[n-1] == 0) + n--; + + if (n <= 0) /* Ignore empty strings */ + return 0; + + /* Look for inner NULs */ + if (memchr(p, 0, n)) { + log_lldp("Found inner NUL in string, ignoring field."); + return 0; + } + + /* Let's escape weird chars, for security reasons */ + k = cescape_length(p, n); + if (!k) + return -ENOMEM; + + free(*s); + *s = k; + + return 1; +} + +int lldp_neighbor_parse(sd_lldp_neighbor *n) { + struct ether_header h; + const uint8_t *p; + size_t left; + int r; + + assert(n); + + if (n->raw_size < sizeof(struct ether_header)) { + log_lldp("Recieved truncated packet, ignoring."); + return -EBADMSG; + } + + memcpy(&h, LLDP_NEIGHBOR_RAW(n), sizeof(h)); + + if (h.ether_type != htobe16(ETHERTYPE_LLDP)) { + log_lldp("Received packet with wrong type, ignoring."); + return -EBADMSG; + } + + if (h.ether_dhost[0] != 0x01 || + h.ether_dhost[1] != 0x80 || + h.ether_dhost[2] != 0xc2 || + h.ether_dhost[3] != 0x00 || + h.ether_dhost[4] != 0x00 || + !IN_SET(h.ether_dhost[5], 0x00, 0x03, 0x0e)) { + log_lldp("Received packet with wrong destination address, ignoring."); + return -EBADMSG; + } + + memcpy(&n->source_address, h.ether_shost, sizeof(struct ether_addr)); + memcpy(&n->destination_address, h.ether_dhost, sizeof(struct ether_addr)); + + p = (const uint8_t*) LLDP_NEIGHBOR_RAW(n) + sizeof(struct ether_header); + left = n->raw_size - sizeof(struct ether_header); + + for (;;) { + uint8_t type; + uint16_t length; + + if (left < 2) { + log_lldp("TLV lacks header, ignoring."); + return -EBADMSG; + } + + type = p[0] >> 1; + length = p[1] + (((uint16_t) (p[0] & 1)) << 8); + p += 2, left -= 2; + + if (left < length) { + log_lldp("TLV truncated, ignoring datagram."); + return -EBADMSG; + } + + switch (type) { + + case LLDP_TYPE_END: + if (length != 0) { + log_lldp("End marker TLV not zero-sized, ignoring datagram."); + return -EBADMSG; + } + if (left != 0) { + log_lldp("Trailing garbage in datagram, ignoring datagram."); + return -EBADMSG; + } + + goto end_marker; + + case LLDP_TYPE_CHASSIS_ID: + if (length < 2 || length > 256) { /* includes the chassis subtype, hence one extra byte */ + log_lldp("Chassis ID field size out of range, ignoring datagram."); + return -EBADMSG; + } + if (n->id.chassis_id) { + log_lldp("Duplicate chassis ID field, ignoring datagram."); + return -EBADMSG; + } + + n->id.chassis_id = memdup(p, length); + if (!n->id.chassis_id) + return -ENOMEM; + + n->id.chassis_id_size = length; + break; + + case LLDP_TYPE_PORT_ID: + if (length < 2 || length > 256) { /* includes the port subtype, hence one extra byte */ + log_lldp("Port ID field size out of range, ignoring datagram."); + return -EBADMSG; + } + if (n->id.port_id) { + log_lldp("Duplicate port ID field, ignoring datagram."); + return -EBADMSG; + } + + n->id.port_id = memdup(p, length); + if (!n->id.port_id) + return -ENOMEM; + + n->id.port_id_size = length; + break; + + case LLDP_TYPE_TTL: + if (length != 2) { + log_lldp("TTL field has wrong size, ignoring datagram."); + return -EBADMSG; + } + + if (n->has_ttl) { + log_lldp("Duplicate TTL field, ignoring datagram."); + return -EBADMSG; + } + + n->ttl = unaligned_read_be16(p); + n->has_ttl = true; + break; + + case LLDP_TYPE_PORT_DESCRIPTION: + r = parse_string(&n->port_description, p, length); + if (r < 0) + return r; + break; + + case LLDP_TYPE_SYSTEM_NAME: + r = parse_string(&n->system_name, p, length); + if (r < 0) + return r; + break; + + case LLDP_TYPE_SYSTEM_DESCRIPTION: + r = parse_string(&n->system_description, p, length); + if (r < 0) + return r; + break; + + case LLDP_TYPE_SYSTEM_CAPABILITIES: + if (length != 4) + log_lldp("System capabilities field has wrong size, ignoring."); + else { + n->system_capabilities = unaligned_read_be16(p); + n->enabled_capabilities = unaligned_read_be16(p + 2); + n->has_capabilities = true; + } + + break; + + case LLDP_TYPE_PRIVATE: + if (length < 4) + log_lldp("Found private TLV that is too short, ignoring."); + + break; + } + + + p += length, left -= length; + } + +end_marker: + if (!n->id.chassis_id || !n->id.port_id || !n->has_ttl) { + log_lldp("One or more mandatory TLV missing in datagram. Ignoring."); + return -EBADMSG; + + } + + n->rindex = sizeof(struct ether_header); + + return 0; +} + +void lldp_neighbor_start_ttl(sd_lldp_neighbor *n) { + assert(n); + + if (n->ttl > 0) + n->until = usec_add(now(clock_boottime_or_monotonic()), n->ttl * USEC_PER_SEC); + else + n->until = 0; + + if (n->lldp) + prioq_reshuffle(n->lldp->neighbor_by_expiry, n, &n->prioq_idx); +} + +bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b) { + if (a == b) + return true; + + if (!a || !b) + return false; + + if (a->raw_size != b->raw_size) + return false; + + return memcmp(LLDP_NEIGHBOR_RAW(a), LLDP_NEIGHBOR_RAW(b), a->raw_size) == 0; +} + +_public_ int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address) { + assert_return(n, -EINVAL); + assert_return(address, -EINVAL); + + *address = n->source_address; + return 0; +} + +_public_ int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address) { + assert_return(n, -EINVAL); + assert_return(address, -EINVAL); + + *address = n->destination_address; + return 0; +} + +_public_ int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + *ret = LLDP_NEIGHBOR_RAW(n); + *size = n->raw_size; + + return 0; +} + +_public_ int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + assert(n->id.chassis_id_size > 0); + + *type = *(uint8_t*) n->id.chassis_id; + *ret = (uint8_t*) n->id.chassis_id + 1; + *size = n->id.chassis_id_size - 1; + + return 0; +} + +static int format_mac_address(const void *data, size_t sz, char **ret) { + struct ether_addr a; + char *k; + + assert(data || sz <= 0); + + if (sz != 7) + return 0; + + memcpy(&a, (uint8_t*) data + 1, sizeof(a)); + + k = new(char, ETHER_ADDR_TO_STRING_MAX); + if (!k) + return -ENOMEM; + + *ret = ether_addr_to_string(&a, k); + return 1; +} + +static int format_network_address(const void *data, size_t sz, char **ret) { + union in_addr_union a; + int family; + + if (sz == 6 && ((uint8_t*) data)[1] == 1) { + memcpy(&a.in, (uint8_t*) data + 2, sizeof(a.in)); + family = AF_INET; + } else if (sz == 18 && ((uint8_t*) data)[1] == 2) { + memcpy(&a.in6, (uint8_t*) data + 2, sizeof(a.in6)); + family = AF_INET6; + } else + return 0; + + return in_addr_to_string(family, &a, ret); +} + +_public_ int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret) { + char *k; + int r; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (n->chassis_id_as_string) { + *ret = n->chassis_id_as_string; + return 0; + } + + assert(n->id.chassis_id_size > 0); + + switch (*(uint8_t*) n->id.chassis_id) { + + case LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT: + case LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS: + case LLDP_CHASSIS_SUBTYPE_PORT_COMPONENT: + case LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME: + case LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED: + k = cescape_length((char*) n->id.chassis_id + 1, n->id.chassis_id_size - 1); + if (!k) + return -ENOMEM; + + goto done; + + case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: + r = format_mac_address(n->id.chassis_id, n->id.chassis_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + + case LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS: + r = format_network_address(n->id.chassis_id, n->id.chassis_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + } + + /* Generic fallback */ + k = hexmem(n->id.chassis_id, n->id.chassis_id_size); + if (!k) + return -ENOMEM; + +done: + *ret = n->chassis_id_as_string = k; + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + assert(n->id.port_id_size > 0); + + *type = *(uint8_t*) n->id.port_id; + *ret = (uint8_t*) n->id.port_id + 1; + *size = n->id.port_id_size - 1; + + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret) { + char *k; + int r; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (n->port_id_as_string) { + *ret = n->port_id_as_string; + return 0; + } + + assert(n->id.port_id_size > 0); + + switch (*(uint8_t*) n->id.port_id) { + + case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: + case LLDP_PORT_SUBTYPE_PORT_COMPONENT: + case LLDP_PORT_SUBTYPE_INTERFACE_NAME: + case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: + k = cescape_length((char*) n->id.port_id + 1, n->id.port_id_size - 1); + if (!k) + return -ENOMEM; + + goto done; + + case LLDP_PORT_SUBTYPE_MAC_ADDRESS: + r = format_mac_address(n->id.port_id, n->id.port_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + + case LLDP_PORT_SUBTYPE_NETWORK_ADDRESS: + r = format_network_address(n->id.port_id, n->id.port_id_size, &k); + if (r < 0) + return r; + if (r > 0) + goto done; + + break; + } + + /* Generic fallback */ + k = hexmem(n->id.port_id, n->id.port_id_size); + if (!k) + return -ENOMEM; + +done: + *ret = n->port_id_as_string = k; + return 0; +} + +_public_ int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + *ret = n->ttl; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->system_name) + return -ENODATA; + + *ret = n->system_name; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->system_description) + return -ENODATA; + + *ret = n->system_description; + return 0; +} + +_public_ int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->port_description) + return -ENODATA; + + *ret = n->port_description; + return 0; +} + +_public_ int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->has_capabilities) + return -ENODATA; + + *ret = n->system_capabilities; + return 0; +} + +_public_ int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret) { + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + + if (!n->has_capabilities) + return -ENODATA; + + *ret = n->enabled_capabilities; + return 0; +} + +int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + int r; + + assert_return(ret, -EINVAL); + assert_return(raw || raw_size <= 0, -EINVAL); + + n = lldp_neighbor_new(raw_size); + if (!n) + return -ENOMEM; + + memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size); + r = lldp_neighbor_parse(n); + if (r < 0) + return r; + + *ret = n; + n = 0; + + return r; +} + +_public_ int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n) { + assert_return(n, -EINVAL); + + assert(n->raw_size >= sizeof(struct ether_header)); + n->rindex = sizeof(struct ether_header); + + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n) { + size_t length; + + assert_return(n, -EINVAL); + + if (n->rindex == n->raw_size) /* EOF */ + return -ESPIPE; + + if (n->rindex + 2 > n->raw_size) /* Truncated message */ + return -EBADMSG; + + length = LLDP_NEIGHBOR_LENGTH(n); + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + n->rindex += 2 + length; + return n->rindex < n->raw_size; +} + +_public_ int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type) { + assert_return(n, -EINVAL); + assert_return(type, -EINVAL); + + if (n->rindex == n->raw_size) /* EOF */ + return -ESPIPE; + + if (n->rindex + 2 > n->raw_size) + return -EBADMSG; + + *type = LLDP_NEIGHBOR_TYPE(n); + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type) { + uint8_t k; + int r; + + assert_return(n, -EINVAL); + + r = sd_lldp_neighbor_tlv_get_type(n, &k); + if (r < 0) + return r; + + return type == k; +} + +_public_ int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype) { + const uint8_t *d; + size_t length; + int r; + + assert_return(n, -EINVAL); + assert_return(oui, -EINVAL); + assert_return(subtype, -EINVAL); + + r = sd_lldp_neighbor_tlv_is_type(n, LLDP_TYPE_PRIVATE); + if (r < 0) + return r; + if (r == 0) + return -ENXIO; + + length = LLDP_NEIGHBOR_LENGTH(n); + if (length < 4) + return -EBADMSG; + + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + d = LLDP_NEIGHBOR_DATA(n); + memcpy(oui, d, 3); + *subtype = d[3]; + + return 0; +} + +_public_ int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype) { + uint8_t k[3], st; + int r; + + r = sd_lldp_neighbor_tlv_get_oui(n, k, &st); + if (r == -ENXIO) + return 0; + if (r < 0) + return r; + + return memcmp(k, oui, 3) == 0 && st == subtype; +} + +_public_ int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size) { + size_t length; + + assert_return(n, -EINVAL); + assert_return(ret, -EINVAL); + assert_return(size, -EINVAL); + + /* Note that this returns the full TLV, including the TLV header */ + + if (n->rindex + 2 > n->raw_size) + return -EBADMSG; + + length = LLDP_NEIGHBOR_LENGTH(n); + + if (n->rindex + 2 + length > n->raw_size) + return -EBADMSG; + + *ret = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; + *size = length + 2; + + return 0; +} diff --git a/src/libsystemd-network/lldp-neighbor.h b/src/libsystemd-network/lldp-neighbor.h new file mode 100644 index 0000000000..f203bfa604 --- /dev/null +++ b/src/libsystemd-network/lldp-neighbor.h @@ -0,0 +1,106 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 Lennart Poettering + + systemd 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; either version 2.1 of the License, or + (at your option) any later version. + + systemd 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include +#include + +#include "sd-lldp.h" + +#include "hash-funcs.h" +#include "lldp-internal.h" +#include "time-util.h" + +typedef struct LLDPNeighborID { + /* The spec calls this an "MSAP identifier" */ + void *chassis_id; + size_t chassis_id_size; + + void *port_id; + size_t port_id_size; +} LLDPNeighborID; + +struct sd_lldp_neighbor { + /* Neighbor objects stay around as long as they are linked into an "sd_lldp" object or n_ref > 0. */ + sd_lldp *lldp; + unsigned n_ref; + + usec_t until; + unsigned prioq_idx; + + struct ether_addr source_address; + struct ether_addr destination_address; + + LLDPNeighborID id; + + /* The raw packet size. The data is appended to the object, accessible via LLDP_NEIGHBOR_RAW() */ + size_t raw_size; + + /* The current read index for the iterative TLV interface */ + size_t rindex; + + /* And a couple of fields parsed out. */ + bool has_ttl:1; + bool has_capabilities:1; + bool has_port_vlan_id:1; + + uint16_t ttl; + + uint16_t system_capabilities; + uint16_t enabled_capabilities; + + char *port_description; + char *system_name; + char *system_description; + + uint16_t port_vlan_id; + + char *chassis_id_as_string; + char *port_id_as_string; +}; + +static inline void *LLDP_NEIGHBOR_RAW(const sd_lldp_neighbor *n) { + return (uint8_t*) n + ALIGN(sizeof(sd_lldp_neighbor)); +} + +static inline uint8_t LLDP_NEIGHBOR_TYPE(const sd_lldp_neighbor *n) { + return ((uint8_t*) LLDP_NEIGHBOR_RAW(n))[n->rindex] >> 1; +} + +static inline size_t LLDP_NEIGHBOR_LENGTH(const sd_lldp_neighbor *n) { + uint8_t *p; + + p = (uint8_t*) LLDP_NEIGHBOR_RAW(n) + n->rindex; + return p[1] + (((size_t) (p[0] & 1)) << 8); +} + +static inline void* LLDP_NEIGHBOR_DATA(const sd_lldp_neighbor *n) { + return ((uint8_t*) LLDP_NEIGHBOR_RAW(n)) + n->rindex + 2; +} + +extern const struct hash_ops lldp_neighbor_id_hash_ops; +int lldp_neighbor_prioq_compare_func(const void *a, const void *b); + +sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n); +sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size); +int lldp_neighbor_parse(sd_lldp_neighbor *n); +void lldp_neighbor_start_ttl(sd_lldp_neighbor *n); +bool lldp_neighbor_equal(const sd_lldp_neighbor *a, const sd_lldp_neighbor *b); diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c deleted file mode 100644 index 9170b50691..0000000000 --- a/src/libsystemd-network/lldp-tlv.c +++ /dev/null @@ -1,638 +0,0 @@ -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd 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; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "alloc-util.h" -#include "lldp-tlv.h" -#include "macro.h" - -int tlv_section_new(tlv_section **ret) { - tlv_section *s; - - s = new0(tlv_section, 1); - if (!s) - return -ENOMEM; - - *ret = s; - - return 0; -} - -void tlv_section_free(tlv_section *m) { - - if (!m) - return; - - free(m); -} - -int tlv_packet_new(tlv_packet **ret) { - tlv_packet *m; - - m = new0(tlv_packet, 1); - if (!m) - return -ENOMEM; - - LIST_HEAD_INIT(m->sections); - m->n_ref = 1; - - *ret = m; - - return 0; -} - -tlv_packet *sd_lldp_packet_ref(tlv_packet *m) { - - if (!m) - return NULL; - - assert(m->n_ref > 0); - m->n_ref++; - - return m; -} - -tlv_packet *sd_lldp_packet_unref(tlv_packet *m) { - tlv_section *s, *n; - - if (!m) - return NULL; - - assert(m->n_ref > 0); - m->n_ref--; - - if (m->n_ref > 0) - return m; - - LIST_FOREACH_SAFE(section, s, n, m->sections) - tlv_section_free(s); - - free(m); - return NULL; -} - -int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length) { - uint8_t *p; - - assert_return(m, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_length, -EINVAL); - - if (m->length + data_length > ETHER_MAX_LEN) - return -ENOMEM; - - p = m->pdu + m->length; - memcpy(p, data, data_length); - m->length += data_length; - - return 0; -} - -int tlv_packet_append_u8(tlv_packet *m, uint8_t data) { - - assert_return(m, -EINVAL); - - return tlv_packet_append_bytes(m, &data, sizeof(uint8_t)); -} - -int tlv_packet_append_u16(tlv_packet *m, uint16_t data) { - uint16_t type; - - assert_return(m, -EINVAL); - - type = htons(data); - - return tlv_packet_append_bytes(m, &type, sizeof(uint16_t)); -} - -int tlv_packet_append_u32(tlv_packet *m, uint32_t data) { - uint32_t type; - - assert_return(m, -EINVAL); - - type = htonl(data); - - return tlv_packet_append_bytes(m, &type, sizeof(uint32_t)); -} - -int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size) { - - assert_return(m, -EINVAL); - - return tlv_packet_append_bytes(m, data, size); -} - -int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type) { - - assert_return(m, -EINVAL); - - m->container_pos = m->pdu + m->length; - - return tlv_packet_append_u16(m, type << 9); -} - -int lldp_tlv_packet_close_container(tlv_packet *m) { - uint16_t type; - - assert_return(m, -EINVAL); - assert_return(m->container_pos, -EINVAL); - - memcpy(&type, m->container_pos, sizeof(uint16_t)); - - type |= htons(((m->pdu + m->length) - (m->container_pos + 2)) & 0x01ff); - memcpy(m->container_pos, &type, sizeof(uint16_t)); - - return 0; -} - -static inline int tlv_packet_read_internal(tlv_section *m, void **data) { - - assert_return(m->read_pos, -EINVAL); - - *data = m->read_pos; - - return 0; -} - -int tlv_packet_read_u8(tlv_packet *m, uint8_t *data) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(data, val, sizeof(uint8_t)); - - m->container->read_pos ++; - - return 0; -} - -int tlv_packet_read_u16(tlv_packet *m, uint16_t *data) { - uint16_t t; - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(&t, val, sizeof(uint16_t)); - *data = ntohs(t); - - m->container->read_pos += 2; - - return 0; -} - -int tlv_packet_read_u32(tlv_packet *m, uint32_t *data) { - uint32_t t; - void *val; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - memcpy(&t, val, sizeof(uint32_t)); - *data = ntohl(t); - - m->container->read_pos += 4; - - return r; -} - -int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - *data = (char *) val; - *data_length = m->container->data + m->container->length - m->container->read_pos; - - m->container->read_pos += *data_length; - - return 0; -} - -int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length) { - void *val = NULL; - int r; - - assert_return(m, -EINVAL); - - r = tlv_packet_read_internal(m->container, &val); - if (r < 0) - return r; - - *data = (uint8_t *) val; - *data_length = m->container->data + m->container->length - m->container->read_pos; - - m->container->read_pos += *data_length; - - return 0; -} - -/* parse raw TLV packet */ -int tlv_packet_parse_pdu(tlv_packet *m, uint16_t size) { - tlv_section *section, *tail; - uint16_t t, l; - uint8_t *p; - int r; - - assert_return(m, -EINVAL); - assert_return(size, -EINVAL); - - p = m->pdu; - - /* extract Ethernet header */ - memcpy(&m->mac, p, ETH_ALEN); - p += sizeof(struct ether_header); - - for (l = 0; l <= size; ) { - r = tlv_section_new(§ion); - if (r < 0) - return r; - - memcpy(&t, p, sizeof(uint16_t)); - - section->type = ntohs(t) >> 9; - section->length = ntohs(t) & 0x01ff; - - if (section->type == LLDP_TYPE_END || section->type >=_LLDP_TYPE_MAX) { - tlv_section_free(section); - break; - } - - p += 2; - - if (section->type == LLDP_TYPE_PRIVATE && - section->length >= LLDP_OUI_LEN + 1) { - section->oui = p; - p += LLDP_OUI_LEN; - section->subtype = *p++; - - section->length -= LLDP_OUI_LEN + 1; - l += LLDP_OUI_LEN + 1; - } - - section->data = p; - - LIST_FIND_TAIL(section, m->sections, tail); - LIST_INSERT_AFTER(section, m->sections, tail, section); - - p += section->length; - l += (section->length + 2); - } - - return 0; -} - -int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type) { - tlv_section *s; - - assert_return(m, -EINVAL); - assert_return(type != LLDP_TYPE_PRIVATE, -EINVAL); - - LIST_FOREACH(section, s, m->sections) - if (s->type == type) - break; - if (!s) - return -1; - - m->container = s; - - m->container->read_pos = s->data; - if (!m->container->read_pos) { - m->container = NULL; - return -1; - } - - return 0; -} - -int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype) { - tlv_section *s; - - assert_return(m, -EINVAL); - assert_return(oui, -EINVAL); - - LIST_FOREACH(section, s, m->sections) { - if (s->type == LLDP_TYPE_PRIVATE && - s->oui && - s->subtype == subtype && - !memcmp(s->oui, oui, LLDP_OUI_LEN)) - break; - } - - if (!s) - return -1; - - m->container = s; - - m->container->read_pos = s->data; - if (!m->container->read_pos) { - m->container = NULL; - return -1; - } - - return 0; -} - -int lldp_tlv_packet_exit_container(tlv_packet *m) { - assert_return(m, -EINVAL); - - m->container = 0; - - return 0; -} - -static int lldp_tlv_packet_read_u16_tlv(tlv_packet *tlv, uint16_t type, uint16_t *value) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, type); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, value); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -static int lldp_tlv_packet_read_string_tlv(tlv_packet *tlv, uint16_t type, char **data, uint16_t *length) { - char *s; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, type); - if (r < 0) - return r; - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (char *) s; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_chassis_id(tlv_packet *tlv, - uint8_t *type, - uint8_t **data, - uint16_t *length) { - uint8_t subtype; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_CHASSIS_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, &subtype); - if (r < 0) - goto out; - - switch (subtype) { - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - - r = tlv_packet_read_bytes(tlv, data, length); - if (r < 0) - goto out; - - break; - default: - r = -EOPNOTSUPP; - break; - } - - *type = subtype; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_port_id(tlv_packet *tlv, - uint8_t *type, - uint8_t **data, - uint16_t *length) { - uint8_t subtype; - char *s; - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container(tlv, LLDP_TYPE_PORT_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, &subtype); - if (r < 0) - goto out; - - switch (subtype) { - case LLDP_PORT_SUBTYPE_PORT_COMPONENT: - case LLDP_PORT_SUBTYPE_INTERFACE_ALIAS: - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - case LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED: - - r = tlv_packet_read_string(tlv, &s, length); - if (r < 0) - goto out; - - *data = (uint8_t *) s; - - break; - case LLDP_PORT_SUBTYPE_MAC_ADDRESS: - - r = tlv_packet_read_bytes(tlv, data, length); - if (r < 0) - goto out; - - break; - default: - r = -EOPNOTSUPP; - break; - } - - *type = subtype; - - out: - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_ttl(tlv_packet *tlv, uint16_t *ttl) { - return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_TTL, ttl); -} - -int sd_lldp_packet_read_system_name(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_NAME, data, length); -} - -int sd_lldp_packet_read_system_description(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_SYSTEM_DESCRIPTION, data, length); -} - -int sd_lldp_packet_read_port_description(tlv_packet *tlv, - char **data, - uint16_t *length) { - return lldp_tlv_packet_read_string_tlv(tlv, LLDP_TYPE_PORT_DESCRIPTION, data, length); -} - -int sd_lldp_packet_read_system_capability(tlv_packet *tlv, uint16_t *data) { - return lldp_tlv_packet_read_u16_tlv(tlv, LLDP_TYPE_SYSTEM_CAPABILITIES, data); -} - -int sd_lldp_packet_read_port_vlan_id(tlv_packet *tlv, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, id); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, flags); - if (r >= 0) - r = tlv_packet_read_u16(tlv, id); - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_vlan_name(tlv_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length) { - int r, r2; - uint8_t len = 0; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_VLAN_NAME); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, vlan_id); - if (r >= 0) - r = tlv_packet_read_u8(tlv, &len); - if (r >= 0) - r = tlv_packet_read_string(tlv, name, length); - - if (r >= 0 && len < *length) - *length = len; - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_management_vid(tlv_packet *tlv, uint16_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID); - if (r < 0) - return r; - - r = tlv_packet_read_u16(tlv, id); - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id) { - int r, r2; - - assert_return(tlv, -EINVAL); - - r = lldp_tlv_packet_enter_container_oui(tlv, LLDP_OUI_802_1, LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION); - if (r < 0) - return r; - - r = tlv_packet_read_u8(tlv, status); - if (r >= 0) - r = tlv_packet_read_u32(tlv, id); - - r2 = lldp_tlv_packet_exit_container(tlv); - - return r < 0 ? r : r2; -} - -int sd_lldp_packet_get_destination_type(tlv_packet *tlv, int *dest) { - assert_return(tlv, -EINVAL); - assert_return(dest, -EINVAL); - - /* 802.1AB-2009, Table 7-1 */ - if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE; - else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_NON_TPMR_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE; - else if (!memcmp(&tlv->mac, LLDP_MAC_NEAREST_CUSTOMER_BRIDGE, ETH_ALEN)) - *dest = SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE; - else - return -EINVAL; - - return 0; -} diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h deleted file mode 100644 index 1ddca2882f..0000000000 --- a/src/libsystemd-network/lldp-tlv.h +++ /dev/null @@ -1,94 +0,0 @@ -#pragma once - -/*** - This file is part of systemd. - - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani - - systemd 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; either version 2.1 of the License, or - (at your option) any later version. - - systemd 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 - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include - -#include "sd-lldp.h" - -#include "list.h" -#include "lldp.h" -#include "util.h" - -typedef struct sd_lldp_packet tlv_packet; -typedef struct sd_lldp_section tlv_section; - -#define LLDP_OUI_LEN 3 - -struct sd_lldp_section { - uint16_t type; - uint16_t length; - uint8_t *oui; - uint8_t subtype; - - uint8_t *read_pos; - uint8_t *data; - - LIST_FIELDS(tlv_section, section); -}; - -#define LLDP_MAC_NEAREST_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } -#define LLDP_MAC_NEAREST_NON_TPMR_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 } -#define LLDP_MAC_NEAREST_CUSTOMER_BRIDGE (uint8_t[]) { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 } - -int tlv_section_new(tlv_section **ret); -void tlv_section_free(tlv_section *ret); - -struct sd_lldp_packet { - unsigned n_ref; - - uint16_t type; - uint16_t length; - usec_t ts; - - uint8_t *container_pos; - uint8_t pdu[ETHER_MAX_LEN]; - - void *userdata; - - struct ether_addr mac; - tlv_section *container; - - LIST_HEAD(tlv_section, sections); -}; - -int tlv_packet_new(tlv_packet **ret); - -int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); -int lldp_tlv_packet_close_container(tlv_packet *m); - -int tlv_packet_append_bytes(tlv_packet *m, const void *data, size_t data_length); -int tlv_packet_append_u8(tlv_packet *m, uint8_t data); -int tlv_packet_append_u16(tlv_packet *m, uint16_t data); -int tlv_packet_append_u32(tlv_packet *m, uint32_t data); -int tlv_packet_append_string(tlv_packet *m, char *data, uint16_t size); - -int lldp_tlv_packet_enter_container(tlv_packet *m, uint16_t type); -int lldp_tlv_packet_enter_container_oui(tlv_packet *m, const uint8_t *oui, uint8_t subtype); -int lldp_tlv_packet_exit_container(tlv_packet *m); - -int tlv_packet_read_bytes(tlv_packet *m, uint8_t **data, uint16_t *data_length); -int tlv_packet_read_string(tlv_packet *m, char **data, uint16_t *data_length); -int tlv_packet_read_u8(tlv_packet *m, uint8_t *data); -int tlv_packet_read_u16(tlv_packet *m, uint16_t *data); -int tlv_packet_read_u32(tlv_packet *m, uint32_t *data); - -int tlv_packet_parse_pdu(tlv_packet *t, uint16_t size); diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h index 88bef687eb..d61ecabcfc 100644 --- a/src/libsystemd-network/lldp.h +++ b/src/libsystemd-network/lldp.h @@ -23,7 +23,7 @@ #define LLDP_MULTICAST_ADDR { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x0e } /* IEEE 802.3AB Clause 9: TLV Types */ -typedef enum LLDPTypes { +enum { LLDP_TYPE_END = 0, LLDP_TYPE_CHASSIS_ID = 1, LLDP_TYPE_PORT_ID = 2, @@ -34,12 +34,10 @@ typedef enum LLDPTypes { LLDP_TYPE_SYSTEM_CAPABILITIES = 7, LLDP_TYPE_MGMT_ADDRESS = 8, LLDP_TYPE_PRIVATE = 127, - _LLDP_TYPE_MAX, - _LLDP_TYPE_INVALID = -1, -} LLDPTypes; +}; /* IEEE 802.3AB Clause 9.5.2: Chassis subtypes */ -typedef enum LLDPChassisSubtypes { +enum { LLDP_CHASSIS_SUBTYPE_RESERVED = 0, LLDP_CHASSIS_SUBTYPE_CHASSIS_COMPONENT = 1, LLDP_CHASSIS_SUBTYPE_INTERFACE_ALIAS = 2, @@ -48,25 +46,21 @@ typedef enum LLDPChassisSubtypes { LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, - _LLDP_CHASSIS_SUBTYPE_MAX, - _LLDP_CHASSIS_SUBTYPE_INVALID = -1, -} LLDPChassisSubtypes; +}; /* IEEE 802.3AB Clause 9.5.3: Port subtype */ -typedef enum LLDPPortSubtypes { +enum { LLDP_PORT_SUBTYPE_RESERVED = 0, LLDP_PORT_SUBTYPE_INTERFACE_ALIAS = 1, LLDP_PORT_SUBTYPE_PORT_COMPONENT = 2, LLDP_PORT_SUBTYPE_MAC_ADDRESS = 3, - LLDP_PORT_SUBTYPE_NETWORK = 4, + LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, - _LLDP_PORT_SUBTYPE_MAX, - _LLDP_PORT_SUBTYPE_INVALID = -1 -} LLDPPortSubtypes; +}; -typedef enum LLDPSystemCapabilities { +enum { LLDP_SYSTEM_CAPABILITIES_OTHER = 1 << 0, LLDP_SYSTEM_CAPABILITIES_REPEATER = 1 << 1, LLDP_SYSTEM_CAPABILITIES_BRIDGE = 1 << 2, @@ -78,47 +72,31 @@ typedef enum LLDPSystemCapabilities { LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, - _LLDP_SYSTEM_CAPABILITIES_MAX, - _LLDP_SYSTEM_CAPABILITIES_INVALID = -1, -} LLDPSystemCapabilities; +}; + +#define _LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1) -typedef enum LLDPMedSubtype { - LLDP_MED_SUBTYPE_RESERVED = 0, - LLDP_MED_SUBTYPE_CAPABILITIES = 1, - LLDP_MED_SUBTYPE_NETWORK_POLICY = 2, - LLDP_MED_SUBTYPE_LOCATION_ID = 3, - LLDP_MED_SUBTYPE_EXTENDED_PVMDI = 4, - LLDP_MED_SUBTYPE_INV_HWREV = 5, - LLDP_MED_SUBTYPE_INV_FWREV = 6, - LLDP_MED_SUBTYPE_INV_SWREV = 7, - LLDP_MED_SUBTYPE_INV_SERIAL = 8, - LLDP_MED_SUBTYPE_INV_MANUFACTURER = 9, - LLDP_MED_SUBTYPE_INV_MODELNAME = 10, - LLDP_MED_SUBTYPE_INV_ASSETID = 11, - _LLDP_MED_SUBTYPE_MAX, - _LLDP_MED_SUBTYPE_INVALID = -1, -} LLDPMedSubtype; +#define _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \ + ((uint16_t) \ + (LLDP_SYSTEM_CAPABILITIES_REPEATER| \ + LLDP_SYSTEM_CAPABILITIES_BRIDGE| \ + LLDP_SYSTEM_CAPABILITIES_WLAN_AP| \ + LLDP_SYSTEM_CAPABILITIES_ROUTER| \ + LLDP_SYSTEM_CAPABILITIES_DOCSIS| \ + LLDP_SYSTEM_CAPABILITIES_CVLAN| \ + LLDP_SYSTEM_CAPABILITIES_SVLAN| \ + LLDP_SYSTEM_CAPABILITIES_TPMR)) -typedef enum LLDPMedCapability { - LLDP_MED_CAPABILITY_CAPAPILITIES = 1 << 0, - LLDP_MED_CAPABILITY_NETWORK_POLICY = 1 << 1, - LLDP_MED_CAPABILITY_LOCATION_ID = 1 << 2, - LLDP_MED_CAPABILITY_EXTENDED_PSE = 1 << 3, - LLDP_MED_CAPABILITY_EXTENDED_PD = 1 << 4, - LLDP_MED_CAPABILITY_INVENTORY = 1 << 5, - LLDP_MED_CAPABILITY_MAX, - LLDP_MED_CAPABILITY_INVALID = -1, -} LLDPMedCapability; #define LLDP_OUI_802_1 (uint8_t[]) { 0x00, 0x80, 0xc2 } #define LLDP_OUI_802_3 (uint8_t[]) { 0x00, 0x12, 0x0f } enum { - LLDP_OUI_SUBTYPE_802_1_PORT_VLAN_ID = 1, - LLDP_OUI_SUBTYPE_802_1_PORT_PROTOCOL_VLAN_ID = 2, - LLDP_OUI_SUBTYPE_802_1_VLAN_NAME = 3, - LLDP_OUI_SUBTYPE_802_1_PROTOCOL_IDENTITY = 4, - LLDP_OUI_SUBTYPE_802_1_VID_USAGE_DIGEST = 5, - LLDP_OUI_SUBTYPE_802_1_MANAGEMENT_VID = 6, - LLDP_OUI_SUBTYPE_802_1_LINK_AGGREGATION = 7, + LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID = 1, + LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID = 2, + LLDP_OUI_802_1_SUBTYPE_VLAN_NAME = 3, + LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, + LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, + LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, + LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, }; diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 34117cc205..65cfa4e184 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -1,21 +1,21 @@ /*** - This file is part of systemd. + This file is part of systemd. - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright (C) 2014 Tom Gundersen + Copyright (C) 2014 Susant Sahani - systemd 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; either version 2.1 of the License, or - (at your option) any later version. + systemd 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; either version 2.1 of the License, or + (at your option) any later version. - systemd 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 - Lesser General Public License for more details. + systemd 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 + Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . ***/ #include @@ -24,484 +24,162 @@ #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" -#include "hashmap.h" #include "lldp-internal.h" +#include "lldp-neighbor.h" #include "lldp-network.h" -#include "lldp-tlv.h" -#include "prioq.h" -#include "siphash24.h" -#include "string-util.h" +#include "socket-util.h" -struct sd_lldp { - int ifindex; - int fd; +#define LLDP_DEFAULT_NEIGHBORS_MAX 128U - sd_event *event; - int64_t event_priority; - sd_event_source *event_source; - - Prioq *by_expiry; - Hashmap *neighbour_mib; - - sd_lldp_callback_t callback; - void *userdata; -}; - -static void chassis_id_hash_func(const void *p, struct siphash *state) { - const lldp_chassis_id *id = p; - - assert(id); - assert(id->data); - - siphash24_compress(&id->length, sizeof(id->length), state); - siphash24_compress(id->data, id->length, state); -} - -static int chassis_id_compare_func(const void *_a, const void *_b) { - const lldp_chassis_id *a, *b; - - a = _a; - b = _b; - - assert(!a->length || a->data); - assert(!b->length || b->data); - - if (a->type != b->type) - return -1; - - if (a->length != b->length) - return a->length < b->length ? -1 : 1; - - return memcmp(a->data, b->data, a->length); -} - -static const struct hash_ops chassis_id_hash_ops = { - .hash = chassis_id_hash_func, - .compare = chassis_id_compare_func -}; - -static void lldp_mib_delete_objects(sd_lldp *lldp); - -static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { - int r; +static void lldp_flush_neighbors(sd_lldp *lldp) { + sd_lldp_neighbor *n; assert(lldp); - assert(tlv); - - /* Remove expired packets */ - if (prioq_size(lldp->by_expiry) > 0) - lldp_mib_delete_objects(lldp); - - r = lldp_mib_add_objects(lldp->by_expiry, lldp->neighbour_mib, tlv); - if (r < 0) - goto out; - - if (lldp->callback) - lldp->callback(lldp, SD_LLDP_EVENT_UPDATE_INFO, lldp->userdata); - - log_lldp("Packet added. MIB size: %d , PQ size: %d", - hashmap_size(lldp->neighbour_mib), - prioq_size(lldp->by_expiry)); - - out: - if (r < 0) - log_lldp("Receive frame failed: %s", strerror(-r)); - return 0; + while ((n = hashmap_first(lldp->neighbor_by_id))) + lldp_neighbor_unlink(n); } -/* 10.3.2 LLDPDU validation: rxProcessFrame() */ -int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { - bool system_description = false, system_name = false, chassis_id = false; - bool port_id = false, ttl = false, end = false; - uint16_t type, len, i, l, t; - uint8_t *p, *q; - sd_lldp *lldp; - int r; - - assert(tlv); - assert(length > 0); - - lldp = tlv->userdata; - - p = tlv->pdu; - p += sizeof(struct ether_header); - - for (i = 1, l = 0; l <= length; i++) { - - memcpy(&t, p, sizeof(uint16_t)); - - type = ntohs(t) >> 9; - len = ntohs(t) & 0x01ff; - - if (type == LLDP_TYPE_END) { - if (len != 0) { - log_lldp("TLV type end must be length 0 (not %d). Dropping.", len); - - goto out; - } - - end = true; - - break; - } else if (type >=_LLDP_TYPE_MAX) { - log_lldp("TLV type: %d not recognized. Dropping.", type); - - goto out; - } - - /* skip type and length encoding */ - p += 2; - q = p; - - p += len; - l += (len + 2); - - if (i <= 3) { - if (i != type) { - log_lldp("TLV missing or out of order. Dropping."); - - goto out; - } - } - - switch(type) { - case LLDP_TYPE_CHASSIS_ID: - - if (len < 2) { - log_lldp("Received malformed Chassis ID TLV length: %d. Dropping.", len); - - goto out; - } +static int lldp_make_space(sd_lldp *lldp, size_t extra) { + sd_lldp_neighbor *n; + usec_t t = USEC_INFINITY; + bool changed = false; - if (chassis_id) { - log_lldp("Duplicate Chassis ID TLV found. Dropping."); - - goto out; - } - - /* Look what subtype it has */ - if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) { - log_lldp("Unknown subtype: %d found in Chassis ID TLV. Dropping.", *q); - - goto out; - - } - - chassis_id = true; - - break; - case LLDP_TYPE_PORT_ID: - - if (len < 2) { - log_lldp("Received malformed Port ID TLV length: %d. Dropping.", len); - - goto out; - } - - if (port_id) { - log_lldp("Duplicate Port ID TLV found. Dropping."); - - goto out; - } - - /* Look what subtype it has */ - if (*q == LLDP_PORT_SUBTYPE_RESERVED || *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) { - log_lldp("Unknown subtype: %d found in Port ID TLV. Dropping.", *q); - - goto out; - - } - - port_id = true; - - break; - case LLDP_TYPE_TTL: - - if(len != 2) { - log_lldp("Received invalid TTL TLV lenth: %d. Dropping.", len); - - goto out; - } - - if (ttl) { - log_lldp("Duplicate TTL TLV found. Dropping."); - - goto out; - } + assert(lldp); - ttl = true; + /* Remove all entries that are past their TTL, and more until at least the specified number of extra entries + * are free. */ + for (;;) { + n = prioq_peek(lldp->neighbor_by_expiry); + if (!n) break; - case LLDP_TYPE_SYSTEM_NAME: - - /* According to RFC 1035 the length of a FQDN is limited to 255 characters */ - if (len > 255) { - log_lldp("Received invalid system name length: %d. Dropping.", len); - goto out; - } - if (system_name) { - log_lldp("Duplicate system name found. Dropping."); - goto out; - } + if (hashmap_size(lldp->neighbor_by_id) > LESS_BY(lldp->neighbors_max, extra)) + goto remove_one; - system_name = true; + if (t == USEC_INFINITY) + t = now(clock_boottime_or_monotonic()); + if (n->until > t) break; - case LLDP_TYPE_SYSTEM_DESCRIPTION: - - /* 0 <= n <= 255 octets */ - if (len > 255) { - log_lldp("Received invalid system description length: %d. Dropping.", len); - goto out; - } - if (system_description) { - log_lldp("Duplicate system description found. Dropping."); - goto out; - } + remove_one: + lldp_neighbor_unlink(n); + changed = true; + } - system_description = true; - break; - default: + return changed; +} - if (len == 0) { - log_lldp("TLV type: %d length 0 received. Dropping.", type); +static int lldp_add_neighbor(sd_lldp *lldp, sd_lldp_neighbor *n) { + sd_lldp_neighbor *old; + bool changed = false; + int r; - goto out; - } - break; + assert(lldp); + assert(n); + assert(!n->lldp); + + /* First retrieve the old entry for this MSAP */ + old = hashmap_get(lldp->neighbor_by_id, &n->id); + if (old) { + if (lldp_neighbor_equal(n, old)) { + /* Is this equal, then restart the TTL counter, but don't do anyting else. */ + lldp_neighbor_start_ttl(old); + return 0; } + + /* Data changed, remove the old entry, and add a new one */ + lldp_neighbor_unlink(old); + changed = true; } - if(!chassis_id || !port_id || !ttl || !end) { - log_lldp("One or more mandatory TLV missing. Dropping."); + /* Then, add the new entry in its place, but only if it has a non-zero TTL. */ + if (n->ttl <= 0) + return changed; - goto out; + /* Only add if the neighbor has a capability we are interested in. Note that we also store all neighbors with + * no caps field set. */ + if (n->has_capabilities && + (n->enabled_capabilities & lldp->capability_mask) == 0) + return changed; - } + /* Then, make room for at least one new neighbor */ + lldp_make_space(lldp, 1); - r = tlv_packet_parse_pdu(tlv, length); - if (r < 0) { - log_lldp("Failed to parse the TLV. Dropping."); + r = hashmap_put(lldp->neighbor_by_id, &n->id, n); + if (r < 0) + return r; - goto out; + r = prioq_put(lldp->neighbor_by_expiry, n, &n->prioq_idx); + if (r < 0) { + assert_se(hashmap_remove(lldp->neighbor_by_id, &n->id) == n); + return r; } - return lldp_receive_frame(lldp, tlv); + n->lldp = lldp; - out: - - sd_lldp_packet_unref(tlv); - - return 0; + return true; } -static int ttl_expiry_item_prioq_compare_func(const void *a, const void *b) { - const lldp_neighbour_port *p = a, *q = b; - - if (p->until < q->until) - return -1; - - if (p->until > q->until) - return 1; - - return 0; -} - -/* 10.5.5.2.1 mibDeleteObjects () - * The mibDeleteObjects () procedure deletes all information in the LLDP remote - * systems MIB associated with the MSAP identifier if an LLDPDU is received with - * an rxTTL value of zero (see 10.3.2) or the timing counter rxInfoTTL expires. */ - -static void lldp_mib_delete_objects(sd_lldp *lldp) { - lldp_neighbour_port *p; - usec_t t = 0; - - /* Remove all entries that are past their TTL */ - for (;;) { - - if (prioq_size(lldp->by_expiry) <= 0) - break; +static int lldp_handle_datagram(sd_lldp *lldp, sd_lldp_neighbor *n) { + int r; - p = prioq_peek(lldp->by_expiry); - if (!p) - break; + assert(lldp); + assert(n); - if (t <= 0) - t = now(clock_boottime_or_monotonic()); + r = lldp_neighbor_parse(n); + if (r == -EBADMSG) /* Ignore bad messages */ + return 0; + if (r < 0) + return r; - if (p->until > t) - break; + lldp_neighbor_start_ttl(n); - lldp_neighbour_port_remove_and_free(p); + r = lldp_add_neighbor(lldp, n); + if (r < 0) { + log_lldp_errno(r, "Failed to add datagram. Ignoring."); + return 0; } -} - -static void lldp_mib_objects_flush(sd_lldp *lldp) { - lldp_neighbour_port *p, *q; - lldp_chassis *c; - assert(lldp); - assert(lldp->neighbour_mib); - assert(lldp->by_expiry); - - /* Drop all packets */ - while ((c = hashmap_steal_first(lldp->neighbour_mib))) { + log_lldp("Successfully processed LLDP datagram."); - LIST_FOREACH_SAFE(port, p, q, c->ports) { - lldp_neighbour_port_remove_and_free(p); - } - } + if (r > 0 && lldp->callback) /* Only invoke the callback if something actually changed. */ + lldp->callback(lldp, lldp->userdata); - assert(hashmap_size(lldp->neighbour_mib) == 0); - assert(prioq_size(lldp->by_expiry) == 0); + return 0; } -int sd_lldp_save(sd_lldp *lldp, const char *lldp_file) { - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - uint8_t *mac, *port_id, type; - lldp_neighbour_port *p; - uint16_t data = 0, length = 0; - char buf[LINE_MAX]; - lldp_chassis *c; - usec_t time; - Iterator i; - int r; +static int lldp_receive_datagram(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + ssize_t space, length; + sd_lldp *lldp = userdata; + assert(fd >= 0); assert(lldp); - assert(lldp_file); - - r = fopen_temporary(lldp_file, &f, &temp_path); - if (r < 0) - goto fail; - - fchmod(fileno(f), 0644); - - HASHMAP_FOREACH(c, lldp->neighbour_mib, i) { - LIST_FOREACH(port, p, c->ports) { - _cleanup_free_ char *s = NULL; - char *k, *t; - - r = sd_lldp_packet_read_chassis_id(p->packet, &type, &mac, &length); - if (r < 0) - continue; - - sprintf(buf, "'_Chassis=%02x:%02x:%02x:%02x:%02x:%02x' '_CType=%d' ", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); - - s = strdup(buf); - if (!s) { - r = -ENOMEM; - goto fail; - } - - r = sd_lldp_packet_read_port_id(p->packet, &type, &port_id, &length); - if (r < 0) - continue; - - if (type != LLDP_PORT_SUBTYPE_MAC_ADDRESS) { - k = strndup((char *) port_id, length -1); - if (!k) { - r = -ENOMEM; - goto fail; - } - - sprintf(buf, "'_Port=%s' '_PType=%d' ", k , type); - free(k); - } else { - mac = port_id; - sprintf(buf, "'_Port=%02x:%02x:%02x:%02x:%02x:%02x' '_PType=%d' ", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], type); - } - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - time = now(clock_boottime_or_monotonic()); - - /* Don't write expired packets */ - if (time - p->until <= 0) - continue; - - sprintf(buf, "'_TTL="USEC_FMT"' ", p->until); - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - r = sd_lldp_packet_read_system_name(p->packet, &k, &length); - if (r < 0) - k = strappend(s, "'_NAME=N/A' "); - else { - t = strndup(k, length); - if (!t) { - r = -ENOMEM; - goto fail; - } - - k = strjoin(s, "'_NAME=", t, "' ", NULL); - free(t); - } - - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - (void) sd_lldp_packet_read_system_capability(p->packet, &data); - - sprintf(buf, "'_CAP=%x'", data); - - k = strappend(s, buf); - if (!k) { - r = -ENOMEM; - goto fail; - } - - free(s); - s = k; - - fprintf(f, "%s\n", s); - } - } - r = fflush_and_check(f); - if (r < 0) - goto fail; + space = next_datagram_size_fd(fd); + if (space < 0) + return log_lldp_errno(space, "Failed to determine datagram size to read: %m"); - if (rename(temp_path, lldp_file) < 0) { - r = -errno; - goto fail; - } + n = lldp_neighbor_new(space); + if (!n) + return -ENOMEM; - return 0; + length = recv(fd, LLDP_NEIGHBOR_RAW(n), n->raw_size, MSG_DONTWAIT); + if (length < 0) + return log_lldp_errno(errno, "Failed to read LLDP datagram: %m"); - fail: - if (temp_path) - (void) unlink(temp_path); + if ((size_t) length != n->raw_size) { + log_lldp("Packet size mismatch."); + return -EINVAL; + } - return log_error_errno(r, "Failed to save lldp data %s: %m", lldp_file); + return lldp_handle_datagram(lldp, n); } -int sd_lldp_start(sd_lldp *lldp) { +_public_ int sd_lldp_start(sd_lldp *lldp) { int r; assert_return(lldp, -EINVAL); @@ -509,48 +187,49 @@ int sd_lldp_start(sd_lldp *lldp) { if (lldp->fd >= 0) return 0; - assert(!lldp->event_source); + assert(!lldp->io_event_source); lldp->fd = lldp_network_bind_raw_socket(lldp->ifindex); if (lldp->fd < 0) return lldp->fd; if (lldp->event) { - r = sd_event_add_io(lldp->event, &lldp->event_source, lldp->fd, EPOLLIN, lldp_receive_packet, lldp); + r = sd_event_add_io(lldp->event, &lldp->io_event_source, lldp->fd, EPOLLIN, lldp_receive_datagram, lldp); if (r < 0) goto fail; - r = sd_event_source_set_priority(lldp->event_source, lldp->event_priority); + r = sd_event_source_set_priority(lldp->io_event_source, lldp->event_priority); if (r < 0) goto fail; - (void) sd_event_source_set_description(lldp->event_source, "lldp"); + (void) sd_event_source_set_description(lldp->io_event_source, "lldp-io"); } return 1; fail: - lldp->event_source = sd_event_source_unref(lldp->event_source); + lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); lldp->fd = safe_close(lldp->fd); return r; } -int sd_lldp_stop(sd_lldp *lldp) { +_public_ int sd_lldp_stop(sd_lldp *lldp) { assert_return(lldp, -EINVAL); if (lldp->fd < 0) return 0; - lldp->event_source = sd_event_source_unref(lldp->event_source); + lldp->timer_event_source = sd_event_source_unref(lldp->timer_event_source); + lldp->io_event_source = sd_event_source_unref(lldp->io_event_source); lldp->fd = safe_close(lldp->fd); - lldp_mib_objects_flush(lldp); + lldp_flush_neighbors(lldp); return 1; } -int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { +_public_ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { int r; assert_return(lldp, -EINVAL); @@ -570,17 +249,16 @@ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority) { return 0; } -int sd_lldp_detach_event(sd_lldp *lldp) { +_public_ int sd_lldp_detach_event(sd_lldp *lldp) { assert_return(lldp, -EINVAL); assert_return(lldp->fd < 0, -EBUSY); lldp->event = sd_event_unref(lldp->event); - return 0; } -int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { +_public_ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { assert_return(lldp, -EINVAL); lldp->callback = cb; @@ -589,26 +267,27 @@ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata) { return 0; } -sd_lldp* sd_lldp_unref(sd_lldp *lldp) { +_public_ sd_lldp* sd_lldp_unref(sd_lldp *lldp) { if (!lldp) return NULL; - /* Drop all packets */ - lldp_mib_objects_flush(lldp); + lldp_flush_neighbors(lldp); - hashmap_free(lldp->neighbour_mib); - prioq_free(lldp->by_expiry); + hashmap_free(lldp->neighbor_by_id); + prioq_free(lldp->neighbor_by_expiry); - sd_event_source_unref(lldp->event_source); + sd_event_source_unref(lldp->io_event_source); + sd_event_source_unref(lldp->timer_event_source); sd_event_unref(lldp->event); safe_close(lldp->fd); free(lldp); + return NULL; } -int sd_lldp_new(int ifindex, sd_lldp **ret) { +_public_ int sd_lldp_new(sd_lldp **ret, int ifindex) { _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; int r; @@ -621,12 +300,14 @@ int sd_lldp_new(int ifindex, sd_lldp **ret) { lldp->fd = -1; lldp->ifindex = ifindex; + lldp->neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX; + lldp->capability_mask = (uint16_t) -1; - lldp->neighbour_mib = hashmap_new(&chassis_id_hash_ops); - if (!lldp->neighbour_mib) + lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_id_hash_ops); + if (!lldp->neighbor_by_id) return -ENOMEM; - r = prioq_ensure_allocated(&lldp->by_expiry, ttl_expiry_item_prioq_compare_func); + r = prioq_ensure_allocated(&lldp->neighbor_by_expiry, lldp_neighbor_prioq_compare_func); if (r < 0) return r; @@ -636,34 +317,124 @@ int sd_lldp_new(int ifindex, sd_lldp **ret) { return 0; } -int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs) { - lldp_neighbour_port *p; - lldp_chassis *c; - Iterator iter; - unsigned count = 0, i; +static int neighbor_compare_func(const void *a, const void *b) { + const sd_lldp_neighbor * const*x = a, * const *y = b; - assert_return(lldp, -EINVAL); - assert_return(tlvs, -EINVAL); + return lldp_neighbor_id_hash_ops.compare(&(*x)->id, &(*y)->id); +} + +static int lldp_start_timer(sd_lldp *lldp); + +static int on_timer_event(sd_event_source *s, uint64_t usec, void *userdata) { + sd_lldp *lldp = userdata; + int r, q; + + r = lldp_make_space(lldp, 0); + if (r < 0) + return log_lldp_errno(r, "Failed to make space: %m"); + + q = lldp_start_timer(lldp); + if (q < 0) + return log_lldp_errno(q, "Failed to restart timer: %m"); + + log_lldp("LLDP timer event hit."); + if (r > 0 && lldp->callback) /* Invoke callback if we dropped an entry */ + lldp->callback(lldp, lldp->userdata); + + return 0; +} - HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { - LIST_FOREACH(port, p, c->ports) - count++; +static int lldp_start_timer(sd_lldp *lldp) { + sd_lldp_neighbor *n; + int r; + + assert(lldp); + + n = prioq_peek(lldp->neighbor_by_expiry); + if (!n) { + + if (lldp->timer_event_source) + return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_OFF); + + return 0; + } + + if (lldp->timer_event_source) { + r = sd_event_source_set_time(lldp->timer_event_source, n->until); + if (r < 0) + return r; + + return sd_event_source_set_enabled(lldp->timer_event_source, SD_EVENT_ONESHOT); } - if (!count) { - *tlvs = NULL; + if (!lldp->event) + return 0; + + r = sd_event_add_time(lldp->event, &lldp->timer_event_source, clock_boottime_or_monotonic(), n->until, 0, on_timer_event, lldp); + if (r < 0) + return r; + + r = sd_event_source_set_priority(lldp->timer_event_source, lldp->event_priority); + if (r < 0) + return r; + + (void) sd_event_source_set_description(lldp->timer_event_source, "lldp-timer"); + return 0; +} + +_public_ int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***ret) { + sd_lldp_neighbor **l = NULL, *n; + Iterator i; + int k = 0, r; + + assert_return(lldp, -EINVAL); + assert_return(ret, -EINVAL); + + /* Flush out old entries, before we return data */ + (void) lldp_make_space(lldp, 0); + + if (hashmap_isempty(lldp->neighbor_by_id)) { /* Special shortcut */ + *ret = NULL; return 0; } - *tlvs = new(sd_lldp_packet *, count); - if (!*tlvs) + l = new0(sd_lldp_neighbor*, hashmap_size(lldp->neighbor_by_id)); + if (!l) return -ENOMEM; - i = 0; - HASHMAP_FOREACH(c, lldp->neighbour_mib, iter) { - LIST_FOREACH(port, p, c->ports) - (*tlvs)[i++] = sd_lldp_packet_ref(p->packet); + r = lldp_start_timer(lldp); + if (r < 0) { + free(l); + return r; } - return count; + HASHMAP_FOREACH(n, lldp->neighbor_by_id, i) + l[k++] = sd_lldp_neighbor_ref(n); + + assert((size_t) k == hashmap_size(lldp->neighbor_by_id)); + + /* Return things in a stable order */ + qsort(l, k, sizeof(sd_lldp_neighbor*), neighbor_compare_func); + *ret = l; + + return k; +} + +_public_ int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t m) { + assert_return(lldp, -EINVAL); + assert_return(m <= 0, -EINVAL); + + lldp->neighbors_max = m; + lldp_make_space(lldp, 0); + + return 0; +} + +_public_ int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask) { + assert_return(lldp, -EINVAL); + assert_return(mask != 0, -EINVAL); + + lldp->capability_mask = mask; + + return 0; } diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 768211a315..589117f56e 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "sd-event.h" #include "sd-lldp.h" @@ -29,7 +30,6 @@ #include "alloc-util.h" #include "fd-util.h" #include "lldp-network.h" -#include "lldp-tlv.h" #include "lldp.h" #include "macro.h" #include "string-util.h" @@ -38,211 +38,8 @@ #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp" #define TEST_LLDP_TYPE_SYSTEM_DESC "systemd-lldp-desc" -static int test_fd[2]; - -static struct ether_addr mac_addr = { - .ether_addr_octet = {'A', 'B', 'C', '1', '2', '3'} -}; - -static int lldp_build_tlv_packet(tlv_packet **ret) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *m = NULL; - const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR; - struct ether_header ether = { - .ether_type = htons(ETHERTYPE_LLDP), - }; - - /* Append Ethernet header */ - memcpy(ðer.ether_dhost, lldp_dst, ETHER_ADDR_LEN); - memcpy(ðer.ether_shost, &mac_addr, ETHER_ADDR_LEN); - - assert_se(tlv_packet_new(&m) >= 0); - - assert_se(tlv_packet_append_bytes(m, ðer, sizeof(struct ether_header)) >= 0); - - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_CHASSIS_ID) >= 0); - - assert_se(tlv_packet_append_u8(m, LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS) >= 0); - assert_se(tlv_packet_append_bytes(m, &mac_addr, ETHER_ADDR_LEN) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* port name */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_PORT_ID) >= 0); - - assert_se(tlv_packet_append_u8(m, LLDP_PORT_SUBTYPE_INTERFACE_NAME) >= 0); - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_PORT, strlen(TEST_LLDP_PORT) + 1) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* ttl */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_TTL) >= 0); - - assert_se(tlv_packet_append_u16(m, 170) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* system name */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0); - - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_NAME, - strlen(TEST_LLDP_TYPE_SYSTEM_NAME)) >= 0); - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* system descrition */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0); - - assert_se(tlv_packet_append_bytes(m, TEST_LLDP_TYPE_SYSTEM_DESC, - strlen(TEST_LLDP_TYPE_SYSTEM_DESC)) >= 0); - - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - /* Mark end of packet */ - assert_se(lldp_tlv_packet_open_container(m, LLDP_TYPE_END) >= 0); - assert_se(lldp_tlv_packet_close_container(m) >= 0); - - *ret = m; - - m = NULL; - - return 0; -} - -static int lldp_parse_chassis_tlv(tlv_packet *m, uint8_t *type) { - uint8_t *p, subtype; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_CHASSIS_ID) >= 0); - assert_se(tlv_packet_read_u8(m, &subtype) >= 0); - - switch (subtype) { - case LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS: - - *type = LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS; - assert_se(tlv_packet_read_bytes(m, &p, &length) >= 0); - - assert_se(memcmp(p, &mac_addr.ether_addr_octet, ETHER_ADDR_LEN) == 0); - - break; - default: - assert_not_reached("Unhandled option"); - } - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_port_id_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - uint8_t subtype; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_PORT_ID) >= 0); - - assert_se(tlv_packet_read_u8(m, &subtype) >= 0); - - switch (subtype) { - case LLDP_PORT_SUBTYPE_INTERFACE_NAME: - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length-1); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_PORT) == 1); - break; - default: - assert_not_reached("Unhandled option"); - } - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_system_name_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_NAME) >= 0); - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_NAME) == 1); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 1; -} - -static int lldp_parse_system_desc_tlv(tlv_packet *m) { - _cleanup_free_ char *p = NULL; - char *str = NULL; - uint16_t length; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_SYSTEM_DESCRIPTION) >= 0); - assert_se(tlv_packet_read_string(m, &str, &length) >= 0); - - p = strndup(str, length); - assert_se(p); - - assert_se(streq(p, TEST_LLDP_TYPE_SYSTEM_DESC) == 1); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_parse_ttl_tlv(tlv_packet *m) { - uint16_t ttl; - - assert_se(lldp_tlv_packet_enter_container(m, LLDP_TYPE_TTL) >= 0); - assert_se(tlv_packet_read_u16(m, &ttl) >= 0); - - assert_se(ttl == 170); - - assert_se(lldp_tlv_packet_exit_container(m) >= 0); - - return 0; -} - -static int lldp_get_destination_type(tlv_packet *m) { - int dest; - - assert_se(sd_lldp_packet_get_destination_type(m, &dest) >= 0); - assert_se(dest == SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE); - - return 0; -} - -static int lldp_parse_tlv_packet(tlv_packet *m, int len) { - uint8_t subtype; - - assert_se(tlv_packet_parse_pdu(m, len) >= 0); - assert_se(lldp_parse_chassis_tlv(m, &subtype) >= 0); - assert_se(lldp_parse_port_id_tlv(m) >= 0); - assert_se(lldp_parse_system_name_tlv(m) >= 0); - assert_se(lldp_parse_ttl_tlv(m) >= 0); - assert_se(lldp_parse_system_desc_tlv(m) >= 0); - - assert_se(lldp_get_destination_type(m) >= 0); - - return 0; -} - -static void test_parser(void) { - _cleanup_(sd_lldp_packet_unrefp) tlv_packet *tlv = NULL; - - /* form a packet */ - lldp_build_tlv_packet(&tlv); - /* parse the packet */ - tlv_packet_parse_pdu(tlv, tlv->length); - /* verify */ - lldp_parse_tlv_packet(tlv, tlv->length); -} +static int test_fd[2] = { -1, -1 }; +static int lldp_handler_calls; int lldp_network_bind_raw_socket(int ifindex) { if (socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, test_fd) < 0) @@ -251,15 +48,14 @@ int lldp_network_bind_raw_socket(int ifindex) { return test_fd[0]; } -static int lldp_handler_calls; -static void lldp_handler (sd_lldp *lldp, int event, void *userdata) { +static void lldp_handler (sd_lldp *lldp, void *userdata) { lldp_handler_calls++; } static int start_lldp(sd_lldp **lldp, sd_event *e, sd_lldp_callback_t cb, void *cb_data) { int r; - r = sd_lldp_new(42, lldp); + r = sd_lldp_new(lldp, 42); if (r < 0) return r; @@ -296,13 +92,8 @@ static int stop_lldp(sd_lldp *lldp) { } static void test_receive_basic_packet(sd_event *e) { - sd_lldp *lldp; - sd_lldp_packet **packets; - uint8_t type, *data; - uint16_t length, ttl; - int dest_type; - char *str; - uint8_t frame[] = { + + static const uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, /* Source MAC */ @@ -319,51 +110,53 @@ static void test_receive_basic_packet(sd_event *e) { 0x00, 0x00 /* End Of LLDPDU */ }; + sd_lldp *lldp; + sd_lldp_neighbor **neighbors; + uint8_t type; + const void *data; + uint16_t ttl; + size_t length; + const char *str; + lldp_handler_calls = 0; assert_se(start_lldp(&lldp, e, lldp_handler, NULL) == 0); assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 1); - assert_se(sd_lldp_get_packets(lldp, &packets) == 1); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1); - assert_se(sd_lldp_packet_read_chassis_id(packets[0], &type, &data, &length) == 0); + assert_se(sd_lldp_neighbor_get_chassis_id(neighbors[0], &type, &data, &length) == 0); assert_se(type == LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS); assert_se(length == ETH_ALEN); assert_se(!memcmp(data, "\x00\x01\x02\x03\x04\x05", ETH_ALEN)); - assert_se(sd_lldp_packet_read_port_id(packets[0], &type, &data, &length) == 0); + assert_se(sd_lldp_neighbor_get_port_id(neighbors[0], &type, &data, &length) == 0); assert_se(type == LLDP_PORT_SUBTYPE_INTERFACE_NAME); assert_se(length == 3); assert_se(strneq((char *) data, "1/3", 3)); - assert_se(sd_lldp_packet_read_port_description(packets[0], &str, &length) == 0); - assert_se(length == 4); - assert_se(strneq(str, "Port", 4)); + assert_se(sd_lldp_neighbor_get_port_description(neighbors[0], &str) == 0); + assert_se(streq(str, "Port")); - assert_se(sd_lldp_packet_read_system_name(packets[0], &str, &length) == 0); - assert_se(length == 3); - assert_se(strneq(str, "SYS", 3)); + assert_se(sd_lldp_neighbor_get_system_name(neighbors[0], &str) == 0); + assert_se(streq(str, "SYS")); - assert_se(sd_lldp_packet_read_system_description(packets[0], &str, &length) == 0); - assert_se(length == 4); /* This is the real length in the TLV packet */ - assert_se(strneq(str, "foo", 3)); + assert_se(sd_lldp_neighbor_get_system_description(neighbors[0], &str) == 0); + assert_se(streq(str, "foo")); - assert_se(sd_lldp_packet_read_ttl(packets[0], &ttl) == 0); + assert_se(sd_lldp_neighbor_get_ttl(neighbors[0], &ttl) == 0); assert_se(ttl == 120); - assert_se(sd_lldp_packet_get_destination_type(packets[0], &dest_type) == 0); - assert_se(dest_type == SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE); - - sd_lldp_packet_unref(packets[0]); - free(packets); + sd_lldp_neighbor_unref(neighbors[0]); + free(neighbors); assert_se(stop_lldp(lldp) == 0); } static void test_receive_incomplete_packet(sd_event *e) { sd_lldp *lldp; - sd_lldp_packet **packets; + sd_lldp_neighbor **neighbors; uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ @@ -383,18 +176,14 @@ static void test_receive_incomplete_packet(sd_event *e) { assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 0); - assert_se(sd_lldp_get_packets(lldp, &packets) == 0); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 0); assert_se(stop_lldp(lldp) == 0); } static void test_receive_oui_packet(sd_event *e) { sd_lldp *lldp; - sd_lldp_packet **packets; - uint32_t id32; - uint16_t id16, len; - uint8_t flags; - char *str; + sd_lldp_neighbor **neighbors; uint8_t frame[] = { /* Ethernet header */ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03, /* Destination MAC*/ @@ -426,29 +215,30 @@ static void test_receive_oui_packet(sd_event *e) { assert_se(write(test_fd[1], frame, sizeof(frame)) == sizeof(frame)); sd_event_run(e, 0); assert_se(lldp_handler_calls == 1); - assert_se(sd_lldp_get_packets(lldp, &packets) == 1); - - assert_se(sd_lldp_packet_read_port_vlan_id(packets[0], &id16) == 0); - assert_se(id16 == 0x1234); - - assert_se(sd_lldp_packet_read_port_protocol_vlan_id(packets[0], &flags, &id16) == 0); - assert_se(flags == 1); - assert_se(id16 == 0x7788); - - assert_se(sd_lldp_packet_read_vlan_name(packets[0], &id16, &str, &len) == 0); - assert_se(id16 == 0x1234); - assert_se(len == 6); - assert_se(strneq(str, "Vlan51", 6)); - - assert_se(sd_lldp_packet_read_management_vid(packets[0], &id16) == 0); - assert_se(id16 == 0x0102); - - assert_se(sd_lldp_packet_read_link_aggregation(packets[0], &flags, &id32) == 0); - assert_se(flags == 1); - assert_se(id32 == 0x00140012); - - sd_lldp_packet_unref(packets[0]); - free(packets); + assert_se(sd_lldp_get_neighbors(lldp, &neighbors) == 1); + + assert_se(sd_lldp_neighbor_tlv_rewind(neighbors[0]) >= 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_CHASSIS_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_PORT_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_TTL) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_VLAN_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_PORT_PROTOCOL_VLAN_ID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_VLAN_NAME) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_oui(neighbors[0], LLDP_OUI_802_1, LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) > 0); + assert_se(sd_lldp_neighbor_tlv_is_type(neighbors[0], LLDP_TYPE_END) > 0); + assert_se(sd_lldp_neighbor_tlv_next(neighbors[0]) == 0); + + sd_lldp_neighbor_unref(neighbors[0]); + free(neighbors); assert_se(stop_lldp(lldp) == 0); } @@ -456,7 +246,7 @@ static void test_receive_oui_packet(sd_event *e) { int main(int argc, char *argv[]) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; - test_parser(); + log_set_max_level(LOG_DEBUG); /* LLDP reception tests */ assert_se(sd_event_new(&e) == 0); diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 62051992ef..26b283f60d 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -187,32 +187,7 @@ _public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char return network_link_get_strv(ifindex, "DNSSEC_NTA", nta); } -_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) { - _cleanup_free_ char *s = NULL, *p = NULL; - size_t size; - int r; - - assert_return(ifindex > 0, -EINVAL); - assert_return(lldp, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0) - return -ENOMEM; - - r = read_full_file(p, &s, &size); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (size <= 0) - return -ENODATA; - - *lldp = s; - s = NULL; - - return 0; -} - -int sd_network_link_get_timezone(int ifindex, char **ret) { +_public_ int sd_network_link_get_timezone(int ifindex, char **ret) { return network_link_get_string(ifindex, "TIMEZONE", ret); } diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 185bdaf293..eecdebd25d 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -23,6 +23,7 @@ #include "sd-device.h" #include "sd-hwdb.h" +#include "sd-lldp.h" #include "sd-netlink.h" #include "sd-network.h" @@ -30,6 +31,7 @@ #include "arphrd-list.h" #include "device-util.h" #include "ether-addr-util.h" +#include "fd-util.h" #include "hwdb-util.h" #include "lldp.h" #include "local-addresses.h" @@ -38,6 +40,7 @@ #include "pager.h" #include "parse-util.h" #include "socket-util.h" +#include "sparse-endian.h" #include "stdio-util.h" #include "string-table.h" #include "string-util.h" @@ -745,162 +748,29 @@ static int link_status(int argc, char *argv[], void *userdata) { return 0; } -const char *lldp_system_capability_to_string(LLDPSystemCapabilities d) _const_; -LLDPSystemCapabilities lldp_system_capability_from_string(const char *d) _pure_; - -static const char* const lldp_system_capability_table[_LLDP_SYSTEM_CAPABILITIES_MAX + 1] = { - [LLDP_SYSTEM_CAPABILITIES_OTHER] = "O", - [LLDP_SYSTEM_CAPABILITIES_REPEATER] = "P", - [LLDP_SYSTEM_CAPABILITIES_BRIDGE] = "B", - [LLDP_SYSTEM_CAPABILITIES_WLAN_AP] = "W", - [LLDP_SYSTEM_CAPABILITIES_ROUTER] = "R", - [LLDP_SYSTEM_CAPABILITIES_PHONE] = "T", - [LLDP_SYSTEM_CAPABILITIES_DOCSIS] = "D", - [LLDP_SYSTEM_CAPABILITIES_STATION] = "A", - [LLDP_SYSTEM_CAPABILITIES_CVLAN] = "C", - [LLDP_SYSTEM_CAPABILITIES_SVLAN] = "S", - [LLDP_SYSTEM_CAPABILITIES_TPMR] = "M", - [_LLDP_SYSTEM_CAPABILITIES_MAX] = "N/A", -}; - -DEFINE_STRING_TABLE_LOOKUP(lldp_system_capability, LLDPSystemCapabilities); - -static char *lldp_system_caps(uint16_t cap) { - _cleanup_free_ char *s = NULL, *t = NULL; - char *capability; - - t = strdup("[ "); - if (!t) - return NULL; - - if (cap & LLDP_SYSTEM_CAPABILITIES_OTHER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_OTHER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_REPEATER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_REPEATER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_BRIDGE) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_BRIDGE), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_WLAN_AP) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_WLAN_AP), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_ROUTER) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_ROUTER), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_PHONE) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_PHONE), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_DOCSIS) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_DOCSIS), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_STATION) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_STATION), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_CVLAN) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_CVLAN), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_SVLAN) { - s = strjoin(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_SVLAN), " ", NULL); - if (!s) - return NULL; - - free(t); - t = s; - } - - if (cap & LLDP_SYSTEM_CAPABILITIES_TPMR) { - s = strappend(t, lldp_system_capability_to_string(LLDP_SYSTEM_CAPABILITIES_TPMR)); - if (!s) - return NULL; - - free(t); - } - - if (!s) { - s = strappend(t, lldp_system_capability_to_string(_LLDP_SYSTEM_CAPABILITIES_MAX)); - if (!s) - return NULL; - - free(t); - } +static char *lldp_capabilities_to_string(uint16_t x) { + static const char characters[] = { + 'o', 'p', 'b', 'w', 'r', 't', 'd', 'a', 'c', 's', 'm', + }; + char *ret; + unsigned i; - t = strappend(s, "]"); - if (!t) + ret = new(char, ELEMENTSOF(characters) + 1); + if (!ret) return NULL; - free(s); - capability = t; + for (i = 0; i < ELEMENTSOF(characters); i++) + ret[i] = (x & (1U << i)) ? characters[i] : '.'; - s = NULL; - t = NULL; - - return capability; + ret[i] = 0; + return ret; } static int link_lldp_status(int argc, char *argv[], void *userdata) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; - double ttl = -1; - uint32_t capability; int i, r, c, j; - const char *p; - char **s; pager_open_if_enabled(); @@ -925,88 +795,85 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { return rtnl_log_parse_error(c); if (arg_legend) - printf("%s %16s %24s %16s %16s\n", "Local Intf", "Device ID", "Port ID", "TTL", "Capability"); + printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", + "LINK", + "CHASSIS ID", + "SYSTEM NAME", + "CAPS", + "PORT ID", + "PORT DESCRIPTION"); for (i = j = 0; i < c; i++) { - _cleanup_free_ char *chassis = NULL, *port = NULL, *cap = NULL, *lldp = NULL; - _cleanup_strv_free_ char **l = NULL; - - r = sd_network_link_get_lldp(links[i].ifindex, &lldp); - if (r < 0) - continue; - - l = strv_split_newlines(lldp); - if (!l) - return -ENOMEM; - - STRV_FOREACH(s, l) { - - p = *s; - for (;;) { - _cleanup_free_ char *a = NULL, *b = NULL, *word = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES); - if (r < 0) - return log_error_errno(r, "Failed to parse LLDP syntax \"%s\": %m", *s); - - if (r == 0) - break; + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; - r = split_pair(word, "=", &a, &b); - if (r < 0) - continue; + if (asprintf(&p, "/run/systemd/netif/lldp/%i", links[i].ifindex) < 0) + return log_oom(); - if (streq(a, "_Chassis")) { - r = free_and_strdup(&chassis, b); - if (r < 0) - return r; - - } else if (streq(a, "_Port")) { - r = free_and_strdup(&port, b); - if (r < 0) - return r; - - } else if (streq(a, "_TTL")) { - long long unsigned x = 0; - usec_t time; - - r = safe_atollu(b, &x); - if (r < 0 || (usec_t) x != x) - return log_warning_errno(r < 0 ? r : ERANGE, - "Failed to parse TTL \"%s\": %m", b); + f = fopen(p, "re"); + if (!f) { + if (errno == ENOENT) + continue; - time = now(clock_boottime_or_monotonic()); - if (x < time) - continue; + log_warning_errno(errno, "Failed to open %s, ignoring: %m", p); + continue; + } - ttl = (double) (x - time) / USEC_PER_SEC; + for (;;) { + const char *chassis_id = NULL, *port_id = NULL, *system_name = NULL, *port_description = NULL, *capabilities = NULL; + _cleanup_(sd_lldp_neighbor_unrefp) sd_lldp_neighbor *n = NULL; + _cleanup_free_ void *raw = NULL; + uint16_t cc; + le64_t u; + size_t l; - } else if (streq(a, "_CAP")) { - sscanf(b, "%x", &capability); + l = fread(&u, 1, sizeof(u), f); + if (l == 0 && feof(f)) /* EOF */ + break; + if (l != sizeof(u)) { + log_warning("Premature end of file, ignoring."); + break; + } - cap = lldp_system_caps(capability); - } + raw = new(uint8_t, le64toh(u)); + if (!raw) + return log_oom(); + if (fread(raw, 1, le64toh(u), f) != le64toh(u)) { + log_warning("Premature end of file, ignoring."); + break; } - if (ttl >= 0) { - printf("%10s %24s %16s %16f %16s\n", - links[i].name, - strna(chassis), strna(port), - ttl, cap); - j++; + r = sd_lldp_neighbor_from_raw(&n, raw, le64toh(u)); + if (r < 0) { + log_warning_errno(r, "Failed to parse LLDP data, ignoring: %m"); + break; } + + (void) sd_lldp_neighbor_get_chassis_id_as_string(n, &chassis_id); + (void) sd_lldp_neighbor_get_port_id_as_string(n, &port_id); + (void) sd_lldp_neighbor_get_system_name(n, &system_name); + (void) sd_lldp_neighbor_get_port_description(n, &port_description); + + if (sd_lldp_neighbor_get_enabled_capabilities(n, &cc) >= 0) + capabilities = lldp_capabilities_to_string(cc); + + printf("%-16s %-17s %-16s %-11s %-17s %-16s\n", + links[i].name, + strna(chassis_id), + strna(system_name), + strna(capabilities), + strna(port_id), + strna(port_description)); } } - if (arg_legend) { - printf("\nCapability Codes:\n" - "(O) - Other, (P) - Repeater, (B) - Bridge , (W) - WLAN Access Point, (R) = Router,\n" - "(T) - Telephone, (D) - Data Over Cable Service Interface Specifications, (A) - Station,\n" - "(C) - Customer VLAN, (S) - Service VLAN, (M) - Two-port MAC Relay (TPMR)\n\n"); - - printf("Total entries displayed: %d\n", j); - } + if (arg_legend) + printf("\nCapabilities:\n" + "o - Other; p - Repeater; b - Bridge; w - WLAN Access Point; r - Router;\n" + "t - Telephone; d - DOCSIS cable device; a - Station; c - Customer VLAN;\n" + "s - Service VLAN, m - Two-port MAC Relay (TPMR)\n\n" + "Total entries displayed: %i\n", j); return 0; } @@ -1022,7 +889,7 @@ static void help(void) { "Commands:\n" " list List links\n" " status [LINK...] Show link status\n" - " lldp Show lldp information\n" + " lldp Show lldp neighbors\n" , program_invocation_short_name); } diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index e63af3afdb..02fb04e0cb 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -26,6 +26,7 @@ #include "dhcp-lease-internal.h" #include "fd-util.h" #include "fileio.h" +#include "lldp.h" #include "netlink-util.h" #include "network-internal.h" #include "networkd-link.h" @@ -103,7 +104,7 @@ bool link_lldp_enabled(Link *link) { if (link->network->bridge) return false; - return link->network->lldp; + return link->network->lldp_mode != LLDP_MODE_NO; } static bool link_ipv4_forward_enabled(Link *link) { @@ -347,18 +348,15 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { r = sd_netlink_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac); if (r < 0) - log_link_debug(link, "MAC address not found for new device, continuing without"); + log_link_debug_errno(link, r, "MAC address not found for new device, continuing without"); - r = asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex); - if (r < 0) + if (asprintf(&link->state_file, "/run/systemd/netif/links/%d", link->ifindex) < 0) return -ENOMEM; - r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex); - if (r < 0) + if (asprintf(&link->lease_file, "/run/systemd/netif/leases/%d", link->ifindex) < 0) return -ENOMEM; - r = asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex); - if (r < 0) + if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0) return -ENOMEM; r = hashmap_ensure_allocated(&manager->links, NULL); @@ -409,7 +407,6 @@ static void link_free(Link *link) { free(link->lease_file); sd_lldp_unref(link->lldp); - free(link->lldp_file); sd_ipv4ll_unref(link->ipv4ll); @@ -1218,7 +1215,7 @@ static int link_set_bridge(Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m"); - if(link->network->cost != 0) { + if (link->network->cost != 0) { r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost); if (r < 0) return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_COST attribute: %m"); @@ -1237,24 +1234,83 @@ static int link_set_bridge(Link *link) { return r; } -static void lldp_handler(sd_lldp *lldp, int event, void *userdata) { - Link *link = userdata; - int r; +static int link_lldp_save(Link *link) { + _cleanup_free_ char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + sd_lldp_neighbor **l = NULL; + int n = 0, r, i; assert(link); - assert(link->network); - assert(link->manager); + assert(link->lldp_file); + + if (!link->lldp) { + (void) unlink(link->lldp_file); + return 0; + } + + r = sd_lldp_get_neighbors(link->lldp, &l); + if (r < 0) + goto finish; + if (r == 0) { + (void) unlink(link->lldp_file); + goto finish; + } + + n = r; + + r = fopen_temporary(link->lldp_file, &f, &temp_path); + if (r < 0) + goto finish; + + fchmod(fileno(f), 0644); - switch (event) { - case SD_LLDP_EVENT_UPDATE_INFO: - r = sd_lldp_save(link->lldp, link->lldp_file); + for (i = 0; i < n; i++) { + const void *p; + le64_t u; + size_t sz; + + r = sd_lldp_neighbor_get_raw(l[i], &p, &sz); if (r < 0) - log_link_warning_errno(link, r, "Could not save LLDP: %m"); + goto finish; + + u = htole64(sz); + (void) fwrite(&u, 1, sizeof(u), f); + (void) fwrite(p, 1, sz, f); + } - break; - default: - break; + r = fflush_and_check(f); + if (r < 0) + goto finish; + + if (rename(temp_path, link->lldp_file) < 0) { + r = -errno; + goto finish; } + +finish: + if (r < 0) { + (void) unlink(link->lldp_file); + if (temp_path) + (void) unlink(temp_path); + + log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file); + } + + if (l) { + for (i = 0; i < n; i++) + sd_lldp_neighbor_unref(l[i]); + free(l); + } + + return r; +} + +static void lldp_handler(sd_lldp *lldp, void *userdata) { + Link *link = userdata; + + assert(link); + + (void) link_lldp_save(link); } static int link_acquire_ipv6_conf(Link *link) { @@ -2116,7 +2172,14 @@ static int link_configure(Link *link) { } if (link_lldp_enabled(link)) { - r = sd_lldp_new(link->ifindex, &link->lldp); + r = sd_lldp_new(&link->lldp, link->ifindex); + if (r < 0) + return r; + + r = sd_lldp_match_capabilities(link->lldp, + link->network->lldp_mode == LLDP_MODE_ROUTERS_ONLY ? + _LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS : + _LLDP_SYSTEM_CAPABILITIES_ALL); if (r < 0) return r; @@ -2714,6 +2777,8 @@ int link_save(Link *link) { return 0; } + link_lldp_save(link); + admin_state = link_state_to_string(link->state); assert(admin_state); @@ -2953,19 +3018,6 @@ int link_save(Link *link) { } } - if (link->lldp) { - assert(link->network); - - r = sd_lldp_save(link->lldp, link->lldp_file); - if (r < 0) - goto fail; - - fprintf(f, - "LLDP_FILE=%s\n", - link->lldp_file); - } else - unlink(link->lldp_file); - r = fflush_and_check(f); if (r < 0) goto fail; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 409df1709f..d67da5d7b6 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -40,7 +40,7 @@ Network.DHCPServer, config_parse_bool, Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) Network.IPv4LLRoute, config_parse_bool, 0, offsetof(Network, ipv4ll_route) Network.IPv6Token, config_parse_ipv6token, 0, offsetof(Network, ipv6_token) -Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) +Network.LLDP, config_parse_lldp_mode, 0, offsetof(Network, lldp_mode) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 Network.Domains, config_parse_domains, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 4315790093..a6512d26e5 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -1013,3 +1013,13 @@ static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES); + +DEFINE_CONFIG_PARSE_ENUM(config_parse_lldp_mode, lldp_mode, LLDPMode, "Failed to parse LLDP= setting."); + +static const char* const lldp_mode_table[_LLDP_MODE_MAX] = { + [LLDP_MODE_NO] = "no", + [LLDP_MODE_YES] = "yes", + [LLDP_MODE_ROUTERS_ONLY] = "routers-only", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(lldp_mode, LLDPMode, LLDP_MODE_YES); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 03c3f206c3..9dcebfbf7b 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -58,6 +58,14 @@ typedef enum DHCPUseDomains { _DHCP_USE_DOMAINS_INVALID = -1, } DHCPUseDomains; +typedef enum LLDPMode { + LLDP_MODE_NO = 0, + LLDP_MODE_YES = 1, + LLDP_MODE_ROUTERS_ONLY = 2, + _LLDP_MODE_MAX, + _LLDP_MODE_INVALID = -1, +} LLDPMode; + struct Network { Manager *manager; @@ -137,7 +145,7 @@ struct Network { struct ether_addr *mac; unsigned mtu; - bool lldp; + LLDPMode lldp_mode; LIST_HEAD(Address, static_addresses); LIST_HEAD(Route, static_routes); @@ -181,6 +189,7 @@ int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigne int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_lldp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* Legacy IPv4LL support */ int config_parse_ipv4ll(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); @@ -197,3 +206,6 @@ IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_; DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_; + +const char* lldp_mode_to_string(LLDPMode m) _const_; +LLDPMode lldp_mode_from_string(const char *s) _pure_; diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 4c896e7fc0..11b89258ed 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -30,22 +30,12 @@ _SD_BEGIN_DECLARATIONS; -enum { - SD_LLDP_EVENT_UPDATE_INFO = 0, -}; - -enum { - SD_LLDP_DESTINATION_TYPE_NEAREST_BRIDGE, - SD_LLDP_DESTINATION_TYPE_NEAREST_NON_TPMR_BRIDGE, - SD_LLDP_DESTINATION_TYPE_NEAREST_CUSTOMER_BRIDGE, -}; - typedef struct sd_lldp sd_lldp; -typedef struct sd_lldp_packet sd_lldp_packet; +typedef struct sd_lldp_neighbor sd_lldp_neighbor; -typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, int event, void *userdata); +typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, void *userdata); -int sd_lldp_new(int ifindex, sd_lldp **ret); +int sd_lldp_new(sd_lldp **ret, int ifindex); sd_lldp* sd_lldp_unref(sd_lldp *lldp); int sd_lldp_start(sd_lldp *lldp); @@ -55,32 +45,46 @@ int sd_lldp_attach_event(sd_lldp *lldp, sd_event *event, int64_t priority); int sd_lldp_detach_event(sd_lldp *lldp); int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_callback_t cb, void *userdata); -int sd_lldp_save(sd_lldp *lldp, const char *file); - -int sd_lldp_packet_read_chassis_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -int sd_lldp_packet_read_port_id(sd_lldp_packet *tlv, uint8_t *type, uint8_t **data, uint16_t *length); -int sd_lldp_packet_read_ttl(sd_lldp_packet *tlv, uint16_t *ttl); -int sd_lldp_packet_read_system_name(sd_lldp_packet *tlv, char **data, uint16_t *length); -int sd_lldp_packet_read_system_description(sd_lldp_packet *tlv, char **data, uint16_t *length); -int sd_lldp_packet_read_system_capability(sd_lldp_packet *tlv, uint16_t *data); -int sd_lldp_packet_read_port_description(sd_lldp_packet *tlv, char **data, uint16_t *length); - -/* IEEE 802.1 organizationally specific TLVs */ -int sd_lldp_packet_read_port_vlan_id(sd_lldp_packet *tlv, uint16_t *id); -int sd_lldp_packet_read_port_protocol_vlan_id(sd_lldp_packet *tlv, uint8_t *flags, uint16_t *id); -int sd_lldp_packet_read_vlan_name(sd_lldp_packet *tlv, uint16_t *vlan_id, char **name, uint16_t *length); -int sd_lldp_packet_read_management_vid(sd_lldp_packet *tlv, uint16_t *id); -int sd_lldp_packet_read_link_aggregation(sd_lldp_packet *tlv, uint8_t *status, uint32_t *id); - -sd_lldp_packet *sd_lldp_packet_ref(sd_lldp_packet *tlv); -sd_lldp_packet *sd_lldp_packet_unref(sd_lldp_packet *tlv); - -int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); -int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); +/* Controls how much and what to store in the neighbors database */ +int sd_lldp_set_neighbors_max(sd_lldp *lldp, uint64_t n); +int sd_lldp_match_capabilities(sd_lldp *lldp, uint16_t mask); + +int sd_lldp_get_neighbors(sd_lldp *lldp, sd_lldp_neighbor ***neighbors); + +int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t raw_size); +sd_lldp_neighbor *sd_lldp_neighbor_ref(sd_lldp_neighbor *n); +sd_lldp_neighbor *sd_lldp_neighbor_unref(sd_lldp_neighbor *n); + +/* Access to LLDP frame metadata */ +int sd_lldp_neighbor_get_source_address(sd_lldp_neighbor *n, struct ether_addr* address); +int sd_lldp_neighbor_get_destination_address(sd_lldp_neighbor *n, struct ether_addr* address); +int sd_lldp_neighbor_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); + +/* High-level, direct, parsed out field access. These fields exist at most once, hence may be queried directly. */ +int sd_lldp_neighbor_get_chassis_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); +int sd_lldp_neighbor_get_chassis_id_as_string(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_port_id(sd_lldp_neighbor *n, uint8_t *type, const void **ret, size_t *size); +int sd_lldp_neighbor_get_port_id_as_string(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_ttl(sd_lldp_neighbor *n, uint16_t *ret); +int sd_lldp_neighbor_get_system_name(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_system_description(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_port_description(sd_lldp_neighbor *n, const char **ret); +int sd_lldp_neighbor_get_system_capabilities(sd_lldp_neighbor *n, uint16_t *ret); +int sd_lldp_neighbor_get_enabled_capabilities(sd_lldp_neighbor *n, uint16_t *ret); + +/* Low-level, iterative TLV access. This is for evertyhing else, it iteratively goes through all available TLVs + * (including the ones covered with the calls above), and allows multiple TLVs for the same fields. */ +int sd_lldp_neighbor_tlv_rewind(sd_lldp_neighbor *n); +int sd_lldp_neighbor_tlv_next(sd_lldp_neighbor *n); +int sd_lldp_neighbor_tlv_get_type(sd_lldp_neighbor *n, uint8_t *type); +int sd_lldp_neighbor_tlv_is_type(sd_lldp_neighbor *n, uint8_t type); +int sd_lldp_neighbor_tlv_get_oui(sd_lldp_neighbor *n, uint8_t oui[3], uint8_t *subtype); +int sd_lldp_neighbor_tlv_is_oui(sd_lldp_neighbor *n, const uint8_t oui[3], uint8_t subtype); +int sd_lldp_neighbor_tlv_get_raw(sd_lldp_neighbor *n, const void **ret, size_t *size); _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref); -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_packet, sd_lldp_packet_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_neighbor, sd_lldp_neighbor_unref); _SD_END_DECLARATIONS; diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index e20d12c44d..56986c984d 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -133,8 +133,6 @@ int sd_network_link_get_dnssec(int ifindex, char **dnssec); */ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta); -int sd_network_link_get_lldp(int ifindex, char **lldp); - /* Get the search DNS domain names for a given link. */ int sd_network_link_get_search_domains(int ifindex, char ***domains); -- cgit v1.2.3-54-g00ecf From b295beea88a7f2c48897b2887acbe99937335c8f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Fri, 19 Feb 2016 20:43:03 +0100 Subject: networkd: rework how carrier bindings are serialized Instead of serializing the interface name, expose the interface index, since that's the only stable identifier. --- src/libsystemd/sd-network/sd-network.c | 62 +++++++++++++++++++++++++++++++--- src/network/networkctl.c | 31 ++++++++++++++--- src/network/networkd-link.c | 52 ++++++++++++++-------------- src/systemd/sd-network.h | 10 +++--- 4 files changed, 117 insertions(+), 38 deletions(-) (limited to 'src/libsystemd') diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 26b283f60d..037ffb6e75 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -207,12 +207,66 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) { return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret); } -_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) { - return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret); +static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { + _cleanup_free_ char *p = NULL, *s = NULL; + _cleanup_strv_free_ char **a = NULL; + _cleanup_free_ int *ifis = NULL; + size_t allocated = 0, c = 0; + const char *x; + int r; + + assert_return(ifindex > 0, -EINVAL); + assert_return(ret, -EINVAL); + + if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) + return -ENOMEM; + + r = parse_env_file(p, NEWLINE, key, &s, NULL); + if (r == -ENOENT) + return -ENODATA; + if (r < 0) + return r; + if (isempty(s)) { + *ret = NULL; + return 0; + } + + x = s; + for (;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&x, &word, NULL, 0); + if (r < 0) + return r; + if (r == 0) + break; + + r = parse_ifindex(word, &ifindex); + if (r < 0) + return r; + + if (!GREEDY_REALLOC(ifis, allocated, c + 1)) + return -ENOMEM; + + ifis[c++] = ifindex; + } + + if (!GREEDY_REALLOC(ifis, allocated, c + 1)) + return -ENOMEM; + ifis[c] = 0; /* Let's add a 0 ifindex to the end, to be nice*/ + + *ret = ifis; + ifis = NULL; + + return c; +} + +_public_ int sd_network_link_get_carrier_bound_to(int ifindex, int **ret) { + return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_TO", ret); } -_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) { - return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret); +_public_ int sd_network_link_get_carrier_bound_by(int ifindex, int **ret) { + return network_link_get_ifindexes(ifindex, "CARRIER_BOUND_BY", ret); } static inline int MONITOR_TO_FD(sd_network_monitor *m) { diff --git a/src/network/networkctl.c b/src/network/networkctl.c index c5da24e75b..8abb1eff9a 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -662,6 +662,30 @@ static int dump_lldp_neighbors(const char *prefix, int ifindex) { return c; } +static void dump_ifindexes(const char *prefix, const int *ifindexes) { + unsigned c; + + assert(prefix); + + if (!ifindexes || ifindexes[0] <= 0) + return; + + for (c = 0; ifindexes[c] > 0; c++) { + char name[IF_NAMESIZE+1]; + + printf("%*s", + (int) strlen(prefix), + c == 0 ? prefix : ""); + + if (if_indextoname(ifindexes[c], name)) + fputs(name, stdout); + else + printf("%i", ifindexes[c]); + + fputc('\n', stdout); + } +} + static void dump_list(const char *prefix, char **l) { char **i; @@ -689,8 +713,7 @@ static int link_status_one( const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL; const char *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup; - _cleanup_strv_free_ char **carrier_bound_to = NULL; - _cleanup_strv_free_ char **carrier_bound_by = NULL; + _cleanup_free_ int *carrier_bound_to = NULL, *carrier_bound_by = NULL; int r; assert(rtnl); @@ -777,8 +800,8 @@ static int link_status_one( dump_list(" NTP: ", ntp); - dump_list("Carrier Bound To: ", carrier_bound_to); - dump_list("Carrier Bound By: ", carrier_bound_by); + dump_ifindexes("Carrier Bound To: ", carrier_bound_to); + dump_ifindexes("Carrier Bound By: ", carrier_bound_by); (void) sd_network_link_get_timezone(info->ifindex, &tz); if (tz) diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 02fb04e0cb..32437d2195 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1622,7 +1622,7 @@ static int link_new_bound_by_list(Link *link) { m = link->manager; - HASHMAP_FOREACH (carrier, m->links, i) { + HASHMAP_FOREACH(carrier, m->links, i) { if (!carrier->network) continue; @@ -1641,7 +1641,7 @@ static int link_new_bound_by_list(Link *link) { if (list_updated) link_dirty(link); - HASHMAP_FOREACH (carrier, link->bound_by_links, i) { + HASHMAP_FOREACH(carrier, link->bound_by_links, i) { r = link_put_carrier(carrier, link, &carrier->bound_to_links); if (r < 0) return r; @@ -2631,7 +2631,6 @@ int link_carrier_reset(Link *link) { return 0; } - int link_update(Link *link, sd_netlink_message *m) { struct ether_addr mac; const char *ifname; @@ -2752,12 +2751,34 @@ int link_update(Link *link, sd_netlink_message *m) { r = link_carrier_lost(link); if (r < 0) return r; - } return 0; } +static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { + bool space = false; + Iterator i; + Link *link; + + assert(f); + assert(prefix); + + if (hashmap_isempty(h)) + return; + + fputs(prefix, f); + HASHMAP_FOREACH(link, h, i) { + if (space) + fputc(' ', f); + + fprintf(f, "%i", link->ifindex); + space = true; + } + + fputc('\n', f); +} + int link_save(Link *link) { _cleanup_free_ char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -2958,27 +2979,8 @@ int link_save(Link *link) { fputc('\n', f); } - if (!hashmap_isempty(link->bound_to_links)) { - Link *carrier; - bool space = false; - - fputs("CARRIER_BOUND_TO=", f); - HASHMAP_FOREACH(carrier, link->bound_to_links, i) - fputs_with_space(f, carrier->ifname, NULL, &space); - - fputc('\n', f); - } - - if (!hashmap_isempty(link->bound_by_links)) { - Link *carrier; - bool space = false; - - fputs("CARRIER_BOUND_BY=", f); - HASHMAP_FOREACH(carrier, link->bound_by_links, i) - fputs_with_space(f, carrier->ifname, NULL, &space); - - fputc('\n', f); - } + print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links); + print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links); if (link->dhcp_lease) { struct in_addr address; diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 56986c984d..0f13e2bae7 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -99,11 +99,11 @@ int sd_network_link_get_network_file(int ifindex, char **filename); /* Get DNS entries for a given link. These are string representations of * IP addresses */ -int sd_network_link_get_dns(int ifindex, char ***addr); +int sd_network_link_get_dns(int ifindex, char ***ret); /* Get NTP entries for a given link. These are domain names or string * representations of IP addresses */ -int sd_network_link_get_ntp(int ifindex, char ***addr); +int sd_network_link_get_ntp(int ifindex, char ***ret); /* Indicates whether or not LLMNR should be enabled for the link * Possible levels of support: yes, no, resolve @@ -139,11 +139,11 @@ int sd_network_link_get_search_domains(int ifindex, char ***domains); /* Get the route DNS domain names for a given link. */ int sd_network_link_get_route_domains(int ifindex, char ***domains); -/* Get the CARRIERS to which current link is bound to. */ -int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers); +/* Get the carrier interface indexes to which current link is bound to. */ +int sd_network_link_get_carrier_bound_to(int ifindex, int **ifindexes); /* Get the CARRIERS that are bound to current link. */ -int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers); +int sd_network_link_get_carrier_bound_by(int ifindex, int **ifindexes); /* Get the timezone that was learnt on a specific link. */ int sd_network_link_get_timezone(int ifindex, char **timezone); -- cgit v1.2.3-54-g00ecf From 5f02f341c08c2a1cd05cc5066ca94bc6aa43243c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sat, 20 Feb 2016 22:06:12 +0100 Subject: sd-network: use xsprintf() instead of asprintf() where we can --- src/libsystemd/sd-network/sd-network.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) (limited to 'src/libsystemd') diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index 037ffb6e75..580047d3ab 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -31,6 +31,7 @@ #include "fs-util.h" #include "macro.h" #include "parse-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -102,16 +103,16 @@ _public_ int sd_network_get_route_domains(char ***ret) { } static int network_link_get_string(int ifindex, const char *field, char **ret) { - _cleanup_free_ char *s = NULL, *p = NULL; + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; + _cleanup_free_ char *s = NULL; int r; assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%i", ifindex) < 0) - return -ENOMEM; + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); - r = parse_env_file(p, NEWLINE, field, &s, NULL); + r = parse_env_file(path, NEWLINE, field, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -126,17 +127,16 @@ static int network_link_get_string(int ifindex, const char *field, char **ret) { } static int network_link_get_strv(int ifindex, const char *key, char ***ret) { - _cleanup_free_ char *p = NULL, *s = NULL; + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; _cleanup_strv_free_ char **a = NULL; + _cleanup_free_ char *s = NULL; int r; assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, key, &s, NULL); + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); + r = parse_env_file(path, NEWLINE, key, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -208,9 +208,10 @@ _public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) { } static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { - _cleanup_free_ char *p = NULL, *s = NULL; + char path[strlen("/run/systemd/netif/links/") + DECIMAL_STR_MAX(ifindex) + 1]; _cleanup_strv_free_ char **a = NULL; _cleanup_free_ int *ifis = NULL; + _cleanup_free_ char *s = NULL; size_t allocated = 0, c = 0; const char *x; int r; @@ -218,10 +219,8 @@ static int network_link_get_ifindexes(int ifindex, const char *key, int **ret) { assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, key, &s, NULL); + xsprintf(path, "/run/systemd/netif/links/%i", ifindex); + r = parse_env_file(path, NEWLINE, key, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) -- cgit v1.2.3-54-g00ecf