]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
priv: disable LLDP in firmware for Intel X7xx cards
authorVincent Bernat <vincent@bernat.ch>
Tue, 27 Apr 2021 20:57:54 +0000 (22:57 +0200)
committerVincent Bernat <vincent@bernat.ch>
Tue, 27 Apr 2021 21:20:15 +0000 (23:20 +0200)
This requires to configure systemd to not protect sysfs.

NEWS
README.md
src/daemon/lldpd.service.in
src/daemon/priv-linux.c

diff --git a/NEWS b/NEWS
index 4ae162e709d47e452661ea823b3b605f4593a086..88c67a653da47dab848a6f453af78c3737d0ae96 100644 (file)
--- 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.
 
index 9bd9f71d1212c91f96d186f760a38fd760b90fd6..59d04d82e5de5b1b63f91578367c2b0c9156d4e2 100644 (file)
--- 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
 -------
 
index ef13dad91e641777f79c9a7421d442a11ee4136f..80288a58832984d82350aef221a466769be246a4 100644 (file)
@@ -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
index 6840477b68cc3547d083e80196f1208cb90807f9..649b38b90b5a3220b6fa3d4f09d1081b8b17e645 100644 (file)
 #include <linux/filter.h>     /* For BPF filtering */
 #include <linux/sockios.h>
 #include <linux/if_ether.h>
+#include <linux/ethtool.h>
 #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)&ethc
+       };
+       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;
 }