]> git.ipfire.org Git - thirdparty/lldpd.git/blobdiff - README.md
ci: try to run make check even with clang
[thirdparty/lldpd.git] / README.md
index f2656e3e97e1c5cd8ff29ddb8418b9fad26940da..6f350b16234d7f77c519de73406786b985b2528a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,12 +1,10 @@
-lldpd: implementation of IEEE 802.1ab (LLDP)
-============================================
+# lldpd: implementation of IEEE 802.1ab (LLDP)
 
-[![Build Status](https://secure.travis-ci.org/vincentbernat/lldpd.png?branch=master)](http://travis-ci.org/vincentbernat/lldpd)
+![Build Status](https://github.com/lldpd/lldpd/workflows/CI/badge.svg)
 
-  http://vincentbernat.github.com/lldpd/
+  https://lldpd.github.io/
 
-Features
---------
+## Features
 
 LLDP (Link Layer Discovery Protocol) is an industry standard protocol
 designed to supplant proprietary Link-Layer protocols such as
@@ -17,93 +15,235 @@ devices.
 
 lldpd implements both reception and sending. It also implements an
 SNMP subagent for net-snmp to get local and remote LLDP
-information. The LLDP MIB is partially implemented but the most useful
+information. The LLDP-MIB is partially implemented but the most useful
 tables are here. lldpd also partially implements LLDP-MED.
 
-lldpd supports bridge, vlan and bonding. bonding need to be done on
-real physical devices, not on bridges, vlans, etc. However, vlans can
-be mapped on the bonding device. You can bridge vlan but not add vlans
-on bridges. More complex setups may give false results.
+lldpd supports bridge, vlan and bonding.
 
 The following OS are supported:
 
  * FreeBSD
  * GNU/Linux
+ * macOS
  * NetBSD
  * OpenBSD
- * Mac OS X
+ * Solaris
 
-Installation
-------------
+Windows is not supported but you can use
+[WinLLDPService](https://github.com/raspi/WinLLDPService/) as a
+transmit-only agent.
 
-To compile lldpd, use the following:
+## Installation
 
+For general instructions [prefer the
+website](https://lldpd.github.io/installation.html),
+including building from released tarballs.
+
+To compile lldpd from Git, use the following commands:
+
+    ./autogen.sh
     ./configure
     make
     sudo make install
 
-You need libevent that you can grab from http://libevent.org or
-install from your package system (libevent-dev for Debian/Ubuntu and
-libevent-devel for Redhat/Fedora/CentOS/SuSE).
-
-If your system does not have libevent, ./configure will use the
-shipped copy and compile it statically.
-
-If it complains about a missing agent/struct.h, your installation of
-Net-SNMP is incomplete. The easiest way to fix this is to provide an
-empty struct.h:
-
-    touch src/struct.h
-
 lldpd uses privilege separation to increase its security. Two
 processes, one running as root and doing minimal stuff and the other
 running as an unprivileged user into a chroot doing most of the stuff,
 are cooperating. You need to create a user called `_lldpd` in a group
 `_lldpd` (this can be change with `./configure`). You also need to
-create an empty directory `/var/run/lldpd` (it needs to be owned by
-root, not `_lldpd`!). If you get fuzzy timestamps from syslog, copy
-`/etc/locatime` into the chroot.
+create an empty directory `/usr/local/var/run/lldpd` (it needs to be
+owned by root, not `_lldpd`!). If you get fuzzy timestamps from
+syslog, copy `/etc/locatime` into the chroot.
 
 `lldpcli` lets one query information collected through the command
 line. If you don't want to run it as root, just install it setuid or
 setgid `_lldpd`.
 
-Installation (Mac OS X)
------------------------
+## Installation (Docker)
+
+You can use Docker to run `lldpd`:
+
+    docker run --rm --net=host --uts=host \
+               -v /etc/os-release:/etc/os-release \
+               --cap-add=NET_RAW --cap-add=NET_ADMIN \
+               --name lldpd \
+               ghcr.io/lldpd/lldpd:latest
+
+In place of `latest` which provides you with the latest stable
+version, you may use `1`, `1.0`, `1.0.12` to match specific versions,
+or `master` to get the development version.
+
+To execute `lldpcli`, use:
+
+    docker exec lldpd lldpcli show neighbors
 
-The same procedure as above applies for Mac OS X. However, there are
+Or to get the command-line:
+
+    docker exec -it lldpd lldpcli
+
+## Installation (macOS)
+
+The same procedure as above applies for macOS. However, there are
 simpler alternatives:
 
- 1. Use [Homebrew](http://mxcl.github.io/homebrew/):
+ 1. Use [Homebrew](https://brew.sh):
 
         brew install lldpd
         # Or, for the latest version:
-        brew install https://raw.github.com/vincentbernat/lldpd/master/osx/lldpd.rb
+        brew install https://raw.github.com/lldpd/lldpd/master/osx/lldpd.rb
 
- 2. Build an OSX installer package which should work on the same
-    version of OS X (it is important to use a separate build
-    directory):
+ 2. Build an macOS installer package which should work on the same
+    version of macOS:
  
         mkdir build && cd build
-        ../configure --prefix=/usr --sysconfdir=/etc --with-embedded-libevent
-        make -C osx pkg ARCHS="i386 x86_64"
+        ../configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/private/etc --with-embedded-libevent \
+            --without-snmp
+        make -C osx pkg
 
-    If you want to compile for an older version of Mac OS X, you need
+    If you want to compile for an older version of macOS, you need
     to find the right SDK and issues commands like those:
 
         SDK=/Developer/SDKs/MacOSX10.6.sdk
         mkdir build && cd build
-        ../configure --prefix=/usr --sysconfdir=/etc --with-embedded-libevent \
+        ../configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/private/etc --with-embedded-libevent \
+           --without-snmp \
            CFLAGS="-mmacosx-version-min=10.6 -isysroot $SDK" \
            LDFLAGS="-mmacosx-version-min=10.6 -isysroot $SDK"
-        make -C osx pkg ARCHS="i386 x86_64"
+        make -C osx pkg
+
+    With recent SDK, you don't need to specify an alternate SDK. They
+    are organized in a way that should enable compatibility with older
+    versions of OSX:
+
+        mkdir build && cd build
+        ../configure --prefix=/usr/local --localstatedir=/var --sysconfdir=/private/etc --with-embedded-libevent \
+           --without-snmp \
+           CFLAGS="-mmacosx-version-min=10.9" \
+           LDFLAGS="-mmacosx-version-min=10.9"
+        make -C osx pkg
+
+    You can check with `otool -l` that you got what you expected in
+    term of supported versions.
 
 If you don't follow the above procedures, you will have to create the
 user/group `_lldpd`. Have a look at how this is done in
 `osx/scripts/postinstall`.
 
-Usage
------
+## Installation (Android)
+
+1. Don't clone the repo or download the master branch from GitHub. Instead, download the official release from the website [https://lldpd.github.io/](https://lldpd.github.io/installation.html#install-from-source). Unpack into a working directory.
+
+2. Download the [Android NDK](https://developer.android.com/ndk/downloads#stable-downloads) (version 22 or later). Unpack into a working directory next to the `lldpd` directory.
+
+3. Install `automake`, `libtool`, and `pkg-config`. (`sudo apt-get install automake libtool pkg-config`)
+
+4. In the root of the `lldpd` directory, make a `compile.sh` file containing this script:
+```sh
+export TOOLCHAIN=$PWD/android-ndk/toolchains/llvm/prebuilt/linux-x86_64
+export TARGET=armv7a-linux-androideabi
+export API=30
+# DO NOT TOUCH BELOW
+export AR=$TOOLCHAIN/bin/llvm-ar
+export CC=$TOOLCHAIN/bin/$TARGET$API-clang
+export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++
+export LD=$TOOLCHAIN/bin/ld
+export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
+export STRIP=$TOOLCHAIN/bin/llvm-strip
+export AS=$CC
+./autogen.sh
+mkdir -p build && cd build
+../configure \
+    --host=$TARGET \
+    --with-sysroot=$TOOLCHAIN/sysroot \
+    --prefix=/system \
+    --sbindir=/system/bin \
+    --runstatedir=/data/data/lldpd \
+    --with-privsep-user=root \
+    --with-privsep-group=root \
+    PKG_CONFIG=/bin/false
+make
+make install DESTDIR=$PWD/install
+```
+
+5. In the **Android NDK** directory, locate the `toolchains/llvm/prebuilt/linux-x86_64` directory and change the `TOOLCHAIN` variable of the above script to match the path where the `linux-x86_64` directory resides.
+
+```sh
+export TOOLCHAIN=$PWD/android-ndk-r22b-linux-x86_64/android-ndk-r22b/toolchains/llvm/prebuilt/linux-x86_64
+```
+
+6. Determine the CPU architecture target (`adb shell getprop ro.product.cpu.abi`). Change the `TARGET` variable in the above script to match the target architecture. The target name will not exactly match the output of the `adb` command as there will be a trailing suffix to the target name, so look in the `linux-x86_64/bin` directory for the `clang` file that starts with the CPU architecture target. Don't include the API version in the target name.
+```sh
+$ adb shell getprop ro.product.cpu.abi
+armeabi-v7a
+```
+```sh
+linux-x86_64/bin$ ls *-clang
+aarch64-linux-android21-clang     armv7a-linux-androideabi23-clang  i686-linux-android26-clang
+aarch64-linux-android22-clang     armv7a-linux-androideabi24-clang  i686-linux-android27-clang
+aarch64-linux-android23-clang     armv7a-linux-androideabi26-clang  i686-linux-android28-clang
+aarch64-linux-android24-clang     armv7a-linux-androideabi27-clang  i686-linux-android29-clang
+aarch64-linux-android26-clang     armv7a-linux-androideabi28-clang  i686-linux-android30-clang
+aarch64-linux-android27-clang     armv7a-linux-androideabi29-clang  x86_64-linux-android21-clang
+aarch64-linux-android28-clang     armv7a-linux-androideabi30-clang  x86_64-linux-android22-clang
+aarch64-linux-android29-clang     i686-linux-android16-clang        x86_64-linux-android23-clang
+aarch64-linux-android30-clang     i686-linux-android17-clang        x86_64-linux-android24-clang
+armv7a-linux-androideabi16-clang  i686-linux-android18-clang        x86_64-linux-android26-clang
+armv7a-linux-androideabi17-clang  i686-linux-android19-clang        x86_64-linux-android27-clang
+armv7a-linux-androideabi18-clang  i686-linux-android21-clang        x86_64-linux-android28-clang
+armv7a-linux-androideabi19-clang  i686-linux-android22-clang        x86_64-linux-android29-clang
+armv7a-linux-androideabi21-clang  i686-linux-android23-clang        x86_64-linux-android30-clang
+armv7a-linux-androideabi22-clang  i686-linux-android24-clang
+```
+```sh
+export TARGET=armv7a-linux-androideabi
+```
+
+7. Set the `API` variable in the script above to your target API version. Check in the same `linux-x86_64/bin` to ensure the API you are targeting has a supported `clang` file for that CPU architecture and version. As of this writing, there is support for API `21-30` included for all architectures and some CPU architectures supported back to version `16`.
+```sh
+export API=30
+```
+
+8. Run the compile script (`./compile.sh`).
+
+9. Copy the `./bin/*` and `./lib/*.so` files from `lldpd/build/install/system` to the target system (`./bin/*` to `/system/bin`, `./lib/*.so` to `/system/lib64`):
+```sh
+# Push files to target
+cd build/install/system
+adb shell mkdir -p /sdcard/Download/lldpd/bin
+adb push bin/lldpcli /sdcard/Download/lldpd/bin/lldpcli
+adb push bin/lldpd /sdcard/Download/lldpd/bin/lldpd
+adb shell mkdir -p /sdcard/Download/lldpd/lib64
+adb push lib/liblldpctl.so /sdcard/Download/lldpd/lib64/liblldpctl.so
+
+# Enter target shell and move files
+adb shell
+# Run as root for all commands
+$ su
+# Make /system writeable
+$ mount -o rw,remount /system
+$ mv /sdcard/Download/lldpd/bin/lldpcli /system/bin/lldpcli
+$ chmod 755 /system/bin/lldpcli
+$ chown root:shell /system/bin/lldpcli
+$ mv /sdcard/Download/lldpd/bin/lldpd /system/bin/lldpd
+$ chmod 755 /system/bin/lldpd
+$ chown root:shell /system/bin/lldpd
+# $ touch /system/bin/lldpctl
+# $ chmod 755 /system/bin/lldpctl
+# $ chown root:shell /system/bin/lldpctl
+$ mv /sdcard/Download/lldpd/lib64/liblldpctl.so /system/lib64/liblldpctl.so
+$ chmod 644 /system/lib64/liblldpctl.so
+$ chown root:root /system/lib64/liblldpctl.so
+# Make /system readonly again
+$ mount -o ro,remount /system
+# Might not be necessary on some systems
+$ mkdir /data/data/lldpd
+$ chmod 700 /data/data/lldpd
+$ chown shell:shell /data/data/lldpd
+# Clean up
+$ rm -rf /sdcard/Download/lldpd
+```
+
+## Usage
 
 lldpd also implements CDP (Cisco Discovery Protocol), FDP (Foundry
 Discovery Protocol), SONMP (Nortel Discovery Protocol) and EDP
@@ -114,6 +254,18 @@ EDP, CDP, FDP or SONMP frame on this interface. Informations collected
 through EDP/CDP/FDP/SONMP are integrated with other informations and
 can be queried with `lldpcli` or through SNMP.
 
+More information:
+ * http://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol
+ * http://standards.ieee.org/getieee802/download/802.1AB-2005.pdf
+ * https://gitlab.com/wireshark/wireshark/-/wikis/LinkLayerDiscoveryProtocol
+
+## Compatibility with older kernels
+
+If you have a kernel older than Linux 2.6.39, you need to compile
+lldpd with `--enable-oldies` to enable some compatibility functions:
+otherwise, lldpd will only rely on Netlink to receive bridge, bond and
+VLAN information.
+
 For bonding, you need 2.6.24 (in previous version, PACKET_ORIGDEV
 affected only non multicast packets). See:
 
@@ -121,9 +273,11 @@ affected only non multicast packets). See:
  * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=8032b46489e50ef8f3992159abd0349b5b8e476c
 
 Otherwise, a packet received on a bond will be affected to all
-interfaces of the bond.
+interfaces of the bond. In this case, lldpd will affect a received
+randomly to one of the interface (so a neighbor may be affected to the
+wrong interface).
 
-On 2.6.27, we are able to receive packets on real interface for bonded
+On 2.6.27, we are able to receive packets on real interface for enslaved
 devices. This allows one to get neighbor information on active/backup
 bonds. Without the 2.6.27, lldpd won't receive any information on
 inactive slaves. Here are the patchs (thanks to Joe Eykholt):
@@ -138,26 +292,55 @@ information:
 
  * http://www.freebsd.org/cgi/query-pr.cgi?pr=138620
 
-Some devices (notably Cisco IOS) send frames on the native VLAN while
-they should send them untagged. If your network card does not support
-accelerated VLAN, you will receive those frames as well. However, if
-your network card handles VLAN encapsulation/decapsulation, you need a
-recent kernel to be able to receive those frames without listening on
-all available VLAN. Starting from Linux 2.6.27, lldpd is able to
-capture VLAN frames when VLAN acceleration is supported by the network
-card. Here is the patch:
- http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=bc1d0411b804ad190cdadabac48a10067f17b9e6
+Some devices (notably Cisco IOS) send frames tagged with the native
+VLAN while they should send them untagged. If your network card does
+not support accelerated VLAN, you will receive those frames as long as
+the corresponding interface exists (see below). However, if your
+network card handles VLAN encapsulation/decapsulation (check with
+`ethtool -k`), you need a recent kernel to be able to receive those
+frames without listening on all available VLAN. Starting from Linux
+2.6.27, lldpd is able to capture VLAN frames when VLAN acceleration is
+supported by the network card. Here is the patch:
 
-More information:
- * http://en.wikipedia.org/wiki/Link_Layer_Discovery_Protocol
- * http://standards.ieee.org/getieee802/download/802.1AB-2005.pdf
- * http://wiki.wireshark.org/LinkLayerDiscoveryProtocol
+ * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=bc1d0411b804ad190cdadabac48a10067f17b9e6
+
+On some other versions, frames are sent on VLAN 1. If this is not the
+native VLAN and if your network card support accelerated VLAN, you
+need to subscribe to this VLAN as well. The Linux kernel does not
+provide any interface for this. The easiest way is to create the VLAN
+for each port:
+
+    ip link add link eth0 name eth0.1 type vlan id 1
+    ip link set up dev eth0.1
+
+You can check both cases using tcpdump:
+
+    tcpdump -epni eth0 ether host 01:80:c2:00:00:0e
+    tcpdump -eni eth0 ether host 01:80:c2:00:00:0e
+
+If the first command does not display received LLDP packets but the
+second one does, LLDP packets are likely encapsulated into a VLAN:
+
+    10:54:06.431154 f0:29:29:1d:7c:01 > 01:80:c2:00:00:0e, ethertype 802.1Q (0x8100), length 363: vlan 1, p 7, ethertype LLDP, LLDP, name SW-APP-D07.VTY, length 345
 
-Development
------------
+In this case, just create VLAN 1 will fix the situation. There are
+other solutions:
+
+ 1. Disable VLAN acceleration on the receive side (`ethtool -K eth0
+    rxvlan off`) but this may or may not work. Check if there are
+    similar properties that could apply with `ethtool -k eth0`.
+ 2. Put the interface in promiscuous mode with `ip link set
+    promisc on dev eth0`.
+
+The last solution can be done directly by `lldpd` (on Linux only) by
+using the option `configure system interface promiscuous`.
+
+On modern networks, the performance impact should be nonexistent.
+
+## Development
 
 During development, you may want to execute lldpd at its current
-location inside of doing `make install`. The correct way to do this is
+location instead of doing `make install`. The correct way to do this is
 to issue the following command:
 
     sudo libtool execute src/daemon/lldpd -L $PWD/src/client/lldpcli -d
@@ -166,8 +349,35 @@ You can append any further arguments. If lldpd is unable to find
 `lldpcli` it will start in an unconfigured mode and won't send or
 accept LLDP frames.
 
-Embedding
----------
+You can use [afl](http://lcamtuf.coredump.cx/afl/) to test some
+aspects of lldpd. To test frame decoding, you can do something like
+that:
+
+    export AFL_USE_ASAN=1 # only on 32bit arch
+    ./configure CC=afl-gcc
+    make clean check
+    cd tests
+    mkdir inputs
+    mv *.pcap inputs
+    afl-fuzz -i inputs -o outputs ./decode @@
+
+There is a general test suite with `make check`. It's also possible to
+run integration tests. They need [pytest](http://pytest.org/latest/)
+and rely on Linux containers to be executed.
+
+To enable code coverage, use:
+
+    ../configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var \
+                 --enable-sanitizers --enable-gcov --with-snmp \
+                 CFLAGS="-O0 -g"
+    make
+    make check
+    # maybe, run integration tests
+    lcov --base-directory $PWD/src/lib \
+         --directory src --capture --output-file gcov.info
+    genhtml gcov.info --output-directory coverage
+
+## Embedding
 
 To embed lldpd into an existing system, there are two point of entries:
 
@@ -188,16 +398,14 @@ To embed lldpd into an existing system, there are two point of entries:
     should always be shipped with `lldpd`. On the other hand, programs
     using `liblldpctl.so` can rely on the classic ABI rules.
 
-Troubleshooting
----------------
+## Troubleshooting
 
 You can use `tcpdump` to look after the packets received and send by
 `lldpd`. To look after LLDPU, use:
 
     tcpdump -s0 -vv -pni eth0 ether dst 01:80:c2:00:00:0e
 
-License
--------
+## License
 
 lldpd is distributed under the ISC license: