-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
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
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:
* 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):
* 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
`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:
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: