Analyzing VxLAN packets using Wireshark

4 minute read

This post was originally published in Nov 2011 at Love My Tool (rebranded as Network Data Pedia recently), but is no longer available there; so reposting it here. Since the original post, Wireshark has introduced a built-in VxLAN dissector - but this post is still instructive for how to create a Lua dissector

As virtualization and cloud computing platforms are getting more and more deployed, the L2 network that the VMs are deployed in is exploding in size and VM migration from one host to another becoming problematic. To solve this problem VMware and Cisco have introduced a new protocol - VxLAN.

To stay on topic, we will not concern ourselves about the protocol details but only about the protocol frame format. For more information on how the protocol works and what it does see Denton Gentry’s 3-part VxLAN article or go straight to the VxLAN IETF Draft

Being a new protocol, Wireshark doesn’t yet have a built-in dissector for the VxLAN protocol. Anticipating such scenarios, Wireshark exports a Lua interface for creating quick-and-dirty dissectors. We will use this interface to write a Wireshark Lua dissector for VxLAN.

The VxLAN frame is a Ethernet-in-UDP encapsulated frame i.e. Ethernet-IP-UDP-VxLAN-Ethernet-IP. If you open vxlan.pcap in Wireshark, you will see that Wireshark stops dissecting as soon as it encounters the VxLAN header and shows all remaining bytes after UDP as just data bytes. The reason why Wireshark stops there is it does not understand how to decode the VxLAN header. That is what we will fix with our Lua script

Wireshark without VxLAN

Before we look at the Lua code itself, let’s look at the VxLAN header format -

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|R|R|R|R|I|R|R|R|            Reserved                           |
|                VXLAN Network Identifier (VNI) |   Reserved    |

It’s a simple 8 byte header - a 8-bit flags field starting at offset 0 with only one bit currently defined while the remaining 7 are reserved, and a 24-bit VNI Tag starting at offset 4. All the remaining bytes in the header are reserved.

Without further ado, here’s the VxLAN Lua dissector code -

    local p_vxlan = Proto("vxlan","Virtual eXtended LAN");

    local f_flags = ProtoField.uint8("vxlan.flags", "Flags", base.HEX)
    local f_flag_i = ProtoField.bool("vxlan.flags.i", "I Flag", 8,
             {"Valid VNI Tag present", "Valid VNI Tag NOT present"}, 0x08)
    local f_rsvd1 = ProtoField.uint24("vxlan.rsvd1", "Reserved", base.HEX)
    local f_vni = ProtoField.uint24("vxlan.vni", "VNI", base.HEX)
    local f_rsvd2 = ProtoField.uint8("vxlan.rsvd2", "Reserved", base.HEX)

    p_vxlan.fields = {f_flags, f_flag_i, f_rsvd1, f_vni, f_rsvd2}

    function p_vxlan.dissector(buf, pinfo, root)

        local t = root:add(p_vxlan, buf(0,8))

        local f = t:add(f_flags, buf(0,1))
        f:add(f_flag_i, buf(0,1))

        t:add(f_rsvd1, buf(1,3))
        t:add(f_vni, buf(4,3))
        t:add(f_rsvd2, buf(7,1))

        t:append_text(", VNI: 0x" .. string.format("%x", buf(4, 3):uint()))

        local eth_dis = Dissector.get("eth")
        eth_dis:call(buf(8):tvb(), pinfo, root)

    local udp_encap_table = DissectorTable.get("udp.port")
    udp_encap_table:add(9029, p_vxlan)

Let’s examine the code closely.

We start by putting the entire dissector in a do-end code block to restrict the scope of the local variables we use.

We call Proto() to create our protocol p_vxlan. Then we create one ProtoField for each field in the header. Notice that we use the appropriate ProtoField.<type> for each field based on the VxLAN header format above. Once all fields are defined, we set p_vxlan.fields to a table containing all the fields.

Next we define our p_vxlan dissector function. This function takes 3 input parameters - the packet buffer that we need to dissect, packet information containing meta data like length of the frame, captured time etc. and the root of the dissected tree to which we will add the dissected information.

The first thing that we add to the root of the tree is the p_vxlan protocol specifying that it starts at offset 0 and spans 8 bytes.

Next we add each field, in the order in which they are defined in the header, as subitems of our protocol. Note that we add the I Flag field as a subitem of the Flag field instead of adding it as a subitem of our protocol.

After adding all the fields, we append our Protocol Name with the most important field of the protocol - VNI so that the value is visible even without expanding the protocol tree.

Before we end the function, recall that VxLAN is an encapsulated packet format and there’s another packet starting with the Ethernet MAC addresses following the VxLAN header. So we call the ethernet dissector and pass it the buffer from offset 8 (after the VxLAN header).

The final step in our script is to register the p_vxlan protocol as a UDP encapsulated dissector. In this script, we are using 9029 as an example UDP port number since IANA hasn’t assigned an official port number yet.

That’s all there is to writing our VxLAN Lua dissector.

Now we need to make Wireshark use this dissector. Open Wireshark, go to Help|About|Folders and look for Personal Plugins and Global Plugins - create a file named vxlan.lua in either of those two locations and then restart Wireshark. Go to Help|About|Plugins and verify vxlan.lua is listed.

Now open vxlan.pcap in Wireshark to see vxlan.lua in action!

Wireshark with VxLAN

For a Lua primer and language reference see Programming in Lua . For Wireshark specific Lua information, see Lua support in Wireshark

To create your own VxLAN packets, see Crafting VxLAN packets using Ostinato.

Leave a Comment