From: Vincent Bernat Date: Tue, 27 Apr 2021 20:57:54 +0000 (+0200) Subject: priv: disable LLDP in firmware for Intel X7xx cards X-Git-Tag: 1.0.11~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a74fd8ca9c02fc0eb81f7a219b2bb657cac25ca2;p=thirdparty%2Flldpd.git priv: disable LLDP in firmware for Intel X7xx cards This requires to configure systemd to not protect sysfs. --- diff --git a/NEWS b/NEWS index 4ae162e7..88c67a65 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ lldpd (1.0.11) + * Changes: + + Disable LLDP in firmware for Intel X7xx cards. * Fix: + Ensure Intel E8xx cards can transmit LLDP packets. diff --git a/README.md b/README.md index 9bd9f71d..59d04d82 100644 --- a/README.md +++ b/README.md @@ -320,16 +320,6 @@ You can use `tcpdump` to look after the packets received and send by tcpdump -s0 -vv -pni eth0 ether dst 01:80:c2:00:00:0e -Intel X710 cards may handle LLDP themselves, intercepting any incoming -packets. If you don't see anything through `tcpdump`, check if you -have such a card (with `lspci`) and stop the embedded LLDP daemon: - - for f in /sys/kernel/debug/i40e/*/command; do - echo lldp stop > $f - done - -This may also apply to the `ice` (Intel E8xx cards) driver. - License ------- diff --git a/src/daemon/lldpd.service.in b/src/daemon/lldpd.service.in index ef13dad9..80288a58 100644 --- a/src/daemon/lldpd.service.in +++ b/src/daemon/lldpd.service.in @@ -13,7 +13,7 @@ ExecStart=@sbindir@/lldpd $DAEMON_ARGS $LLDPD_OPTIONS Restart=on-failure PrivateTmp=yes ProtectHome=yes -ProtectKernelTunables=yes +ProtectKernelTunables=no ProtectControlGroups=yes ProtectKernelModules=yes #ProtectSystem=full diff --git a/src/daemon/priv-linux.c b/src/daemon/priv-linux.c index 6840477b..649b38b9 100644 --- a/src/daemon/priv-linux.c +++ b/src/daemon/priv-linux.c @@ -34,12 +34,15 @@ #include /* For BPF filtering */ #include #include +#include #if defined(__clang__) #pragma clang diagnostic pop #endif /* Defined in linux/pkt_sched.h */ #define TC_PRIO_CONTROL 7 +/* Defined in sysfs/libsysfs.h */ +#define SYSFS_PATH_MAX 256 /* Proxy for open */ int @@ -121,6 +124,71 @@ asroot_open() close(fd); } +/* Quirks needed by some additional interfaces. Currently, this is limited to + * disabling LLDP firmware for i40e. */ +static void +asroot_iface_init_quirks(int ifindex, char *name) +{ + int s = -1; + int fd = -1; + + /* Check driver. */ + struct ethtool_drvinfo ethc = { + .cmd = ETHTOOL_GDRVINFO + }; + struct ifreq ifr = { + .ifr_data = (caddr_t)ðc + }; + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + log_warn("privsep", "unable to open a socket"); + goto end; + } + strlcpy(ifr.ifr_name, name, IFNAMSIZ); + if (ioctl(s, SIOCETHTOOL, &ifr) != 0 || + strncmp("i40e", ethc.driver, sizeof(ethc.driver))) { + /* Not i40e */ + goto end; + } + log_info("interfaces", + "i40e driver detected for %s, disabling LLDP in firmware", + name); + + /* We assume debugfs is mounted. Otherwise, we would need to check if it + * is mounted, then unshare a new mount namespace, mount it, issues the + * command, leave the namespace. Let's see if there is such a need. */ + + char command[] = "lldp stop"; + char sysfs_path[SYSFS_PATH_MAX+1]; + if (snprintf(sysfs_path, SYSFS_PATH_MAX, + "/sys/kernel/debug/i40e/%.*s/command", + (int)sizeof(ethc.bus_info), ethc.bus_info) >= SYSFS_PATH_MAX) { + log_warnx("interfaces", "path truncated"); + goto end; + } + if ((fd = open(sysfs_path, O_WRONLY)) == -1) { + if (errno == ENOENT) { + log_info("interfaces", + "%s does not exist, " + "cannot disable LLDP in firmware for %s", + sysfs_path, name); + goto end; + } + log_warn("interfaces", + "cannot open %s to disable LLDP in firmware for %s", + sysfs_path, name); + goto end; + } + if (write(fd, command, sizeof(command) - 1) == -1) { + log_warn("interfaces", + "cannot disable LLDP in firmware for %s", + name); + goto end; + } +end: + if (s != -1) close(s); + if (fd != -1) close(fd); +} + int asroot_iface_init_os(int ifindex, char *name, int *fd) { @@ -193,6 +261,7 @@ asroot_iface_init_os(int ifindex, char *name, int *fd) } #endif + asroot_iface_init_quirks(ifindex, name); return 0; }