1. Overview

In this tutorial, we’ll learn how to capture LLDP packets using the tcpdump command-line tools. Additionally, we’ll learn how to read the pcap files using the tshark command-line tool.

The Link Layer Discovery Protocol (LLDP) is a vendor-neutral link layer protocol. The LLDP allows network devices to advertise their information on a local area network and also gather information about their neighboring devices on the same network.

In the LLDP, the packet transfers the payload in the form of LLDP data unit (LLDPDU). The LLDPDU, in turn, packs the information in a list of data structures known as type-length-value (TLV). Each TLV consists of three fields: the type of information, the length of the value in bytes, and the actual information that’s being encoded.

For example, the TLV of type 2 contains the port ID information of the sending device. There are a lot of predefined TLVs for LLDP, and four of them are compulsory to be in all the compliant LLDP packets. The four compulsory TLVs are chassis ID (type = 1), port ID (type = 2), time to live (type = 3), and end of LLDPDU (type = 0). The TLV type 0 is a special TLV that acts as a null terminating character to indicate that there’s no more TLV after it.

There are some other optional TLVs that convey more information that can be in the packets. Specifically, the optional TLVs, if present, will be inserted between the time of to live TLV and the end of the LLDPDU TLV. These optional TLVs can convey even more useful information to the listener. One such example is the system capabilities with a type value 7, which indicates if a system can work as a repeater, router, or bridge.

The information in the LLDP packet has a variety of applications. For example, it can help administrators in troubleshooting a local area network. Besides that, through the LLDP packets, we can also monitor the status and changes in the network topology.

3. Capturing LLDP Packets Using tcpdump

The tcpdump is a network packet sniffing and analyzing tool in Linux. It listens to and captures the network packets going through the network interfaces. We can use the tcpdump command to capture and record LLDP packets that are passing through the network interface.

By default, the tcpdump captures all the network packets on a given interface. This is not desirable in our scenario as it produces a lot of noise. What we can do is to write a pcap filter expression so that we only capture the LLDP packets and discard the rest. This keeps our pcap file smaller and easier for analysis later.

The pcap filter expression supports filtering by a specific protocol encapsulated in the Ethernet frame. Specifically, on the Ethernet frame, there’s a field, EtherType, that indicates the protocol of the packet that is being encapsulated. For LLDP protocol, it has the EtherType value of 0x88cc. Therefore, we can construct our pcap filter to evaluate to true when the EtherType value of an Ethernet frame is 0x88cc:

ether proto 0x88cc

With this filter, we can now run the tcpdump command to capture the LLDP packets on our network interface:

$ tcpdump -c 1 -w lldp-packet-capture.pcap -i enp0s3 ether proto 0x88cc

The command above first specifies the -c 1 option to instruct the tcpdump to terminate after we’ve captured 1 packet fulfilling the filter. Without the -c 1 option, the tcpdump will capture packets until it’s manually terminated. Then, we write the captured packets into the lldp-packet-capture.pcap file using the -w option. Additionally, we restrict the sniffing process to only the enp0s3 network interface using the -i option. Finally, we place the LLDP packet filter we constructed earlier at the end of the command.

After we’ve captured an LLDP packet into the file, we’re ready to inspect the pcap file using the tshark command.

4. Viewing the pcap Files

The tshark command line tool is the CLI interface to the popular packet sniffer program, Wireshark. We can use the tshark tool to read the pcap file and print the content to a human-friendly output for easier inspection.

To obtain the tshark tool, we can install the tshark package using our system package managers:

$ sudo apt-get install -y tshark

Then, we can print the content of the pcap file using the tshark command. Specifically, we’ll pass the file to read using the -r option. Then, we request a JSON output of the content using the -T json option. Finally, we pipe the output to the jq command to pretty-print the content:

$ tshark -r lldp-packet-capture.pcap -T json | jq .
[
  {
    "_index": "packets-2023-08-31",
    "_source": {
      "layers": {
        "frame": {
          "frame.encap_type": "1",
          "frame.time": "Aug 31, 2023 07:46:32.271000000 CEST",
          "frame.offset_shift": "0.000000000",
          ...
          "frame.protocols": "eth:ethertype:lldp"
        },
        "eth": {
          "eth.dst": "01:80:c2:00:00:0e",
          "eth.dst_tree": {
            "eth.dst_resolved": "LLDP_Multicast",
            ...
          },
          "eth.src": "08:00:27:a9:1b:40",
          "eth.src_tree": {
            "eth.src_resolved": "PcsCompu_a9:1b:40",
            ...
          },
          "eth.type": "0x000088cc",
          "eth.trailer": "1e:00:00"
        },
        "lldp": {
          "Chassis Subtype = MAC address, Id: 08:00:27:a9:1b:40": {
            "lldp.tlv.type": "1",
            "lldp.tlv.len": "7",
            "lldp.chassis.subtype": "4",
            "lldp.chassis.id.mac": "08:00:27:a9:1b:40"
          },
          "Port Subtype = MAC address, Id: 08:00:27:a9:1b:40": {
            "lldp.tlv.type": "2",
            "lldp.tlv.len": "7",
            "lldp.port.subtype": "3",
            "lldp.port.id.mac": "08:00:27:a9:1b:40"
          },
          "Time To Live = 120 sec": {
            "lldp.tlv.type": "3",
            "lldp.tlv.len": "2",
            "lldp.time_to_live": "120"
          },
          ...
        }
      }
    }
  }
]

On a high level, we can see that the information in the packet is grouped into different layers. Firstly, there’s a frame layer that tells us general information information about the frame. For example, there’s a frame.encap_type field that tells us the type of frame this packet is. In our case, the value is 1 to indicate that this is an Ethernet frame.

Because this is an Ethernet frame, there’s a separate layer eth that contains the Ethernet-specific information of this frame. For example, it contains the source and destination address information of the frame. Additionally, there’s an eth.type field that tells us the protocol type of this Ethernet frame. For us, the value is 0x88c**c, which is exactly what we’ve written for our PCAP filter to capture the LLDP packets.

Finally, there’s the lldp object that shows a list of TLVs in the LLDP packet. As we’ve discussed in the previous section, these TLVs’ data structure contains information about the sending device. For example, the TLV type 1 tells us that the sending device is advertising its chassis number as the type of MAC and has an ID value of 08:00:27:a9:1b:40. Additionally, we can see that the advertised port of the system has a value of 08:00:27:a9:1b:40.

5. Conclusion

In this tutorial, we’ve learned that the link layer discovery protocol is a protocol for network devices to advertise their information on a local area network. Additionally, we’ve learned that the information they advertised can help administrators in troubleshooting and monitoring a network.

Then, we’ve demonstrated writing a pcap filter to capture the LLDP packets by filtering on Ethernet frames with an EtherType value of 0x88cc. With the filter, we then showed how we can record the filtered packets into a file for inspection later.

Finally, we use the tshark command-line tool to read the content of the captured LLDP packet and verify the information that is contained inside.