In this post I’m going to talk about how to create a point to point VXLAN tunnel between two linux hosts with Python. To follow along I have created a vagrant environment and example python script in github.

Here’s our environment and we’re going to form a VXLAN tunnel between the site1router and site2router.

Environment

This will allow the hosts connected to eth2 talk to each other as if they are directly connected. In order to form the VXLAN tunnel overlay the underlay needs to be setup and routing needs to be operational. The interfaces that will be used as the VXLAN Tunnel Endpoint (VTEP) between the two linux hosts need to be able to reach each other. Our site routers are eBGP peering with an isp router and directly connected interfaces are being redistributed into the underlay.

Prerequisites

On the linux host that will be forming the VXLAN tunnel you need to make sure you have the following installed.

Pyroute2 is the python package that is going to allow for the creation of the VXLAN tunnels. It’s very useful for interacting with the linux network stack with python.

On the interface that you are going to bridge with the VXLAN interface you need to ensure that promiscuous mode is enabled within the hypervisor. In our vagrant environment this is enabled for you.

VXLAN Tunnel CLI Commands

Before we show how to set this up within python lets review the CLI commands that you would enter if you wanted to manually configure. We’re going to be using our vagrant environment as the example for the commands to use.

site1router

Create

sudo ip link set eth2 up
sudo ip link add vxlan100 type vxlan id 100 local 192.168.0.2 remote 192.168.0.5 nolearning
sudo ip link set vxlan100 up
sudo brctl addbr br100
sudo brctl addif br100 vxlan100
sudo brctl addif br100 eth2
sudo brctl stp br100 off
sudo ip link set br100 up

Delete

sudo ip link delete vxlan100
sudo ip link delete br100

site2router

Create

sudo ip link set eth2 up
sudo ip link add vxlan100 type vxlan id 100 local 192.168.0.5 remote 192.168.0.2 nolearning
sudo ip link set vxlan100 up
sudo brctl addbr br100
sudo brctl addif br100 vxlan100
sudo brctl addif br100 eth2
sudo brctl stp br100 off
sudo ip link set br100 up

Delete

sudo ip link delete vxlan100
sudo ip link delete br100

VXLAN Tunnel in Python

When working with the IPDB module within pyroute2 you need to commit your changes. You can leverage a context manager to automatically commit the code at the end. In this example we are going to manually commit our changes after each change. This code is essentially the equivalent of the CLI commands referenced above.

site1router

Create

from pyroute2 import IPDB

ipdb = IPDB()
ipdb.interfaces["eth2"].up()
ipdb.interfaces["eth2"].commit()
ipdb.create(
    kind="vxlan",
    ifname=f"vxlan100",
    vxlan_id=100,
    vxlan_learning=False,
    vxlan_local="192.168.0.2",
    vxlan_group="192.168.0.5"
)
ipdb.interfaces["vxlan100"].commit()
ipdb.interfaces["vxlan100"].up()
ipdb.interfaces["vxlan100"].commit()
ipdb.create(kind="bridge", ifname="br100")
ipdb.interfaces["br100"].add_port(ipdb.interfaces["vxlan100"].index)
ipdb.interfaces["br100"].add_port(ipdb.interfaces["eth2"].index)
ipdb.interfaces["br100"].up()
ipdb.interfaces["br100"].commit()

Delete

from pyroute2 import IPDB

ipdb = IPDB()
ipdb.interfaces["vlan100"].remove()
ipdb.interfaces["br100"].remove()
ipdb.commit()

site2router

Create

from pyroute2 import IPDB

ipdb = IPDB()
ipdb.interfaces["eth2"].up()
ipdb.interfaces["eth2"].commit()
ipdb.create(
    kind="vxlan",
    ifname=f"vxlan100",
    vxlan_id=100,
    vxlan_learning=False,
    vxlan_local="192.168.0.5",
    vxlan_group="192.168.0.2"
)
ipdb.interfaces["vxlan100"].commit()
ipdb.interfaces["vxlan100"].up()
ipdb.interfaces["vxlan100"].commit()
ipdb.create(kind="bridge", ifname="br100")
ipdb.interfaces["br100"].add_port(ipdb.interfaces["vxlan100"].index)
ipdb.interfaces["br100"].add_port(ipdb.interfaces["eth2"].index)
ipdb.interfaces["br100"].up()
ipdb.interfaces["br100"].commit()

Delete

from pyroute2 import IPDB

ipdb = IPDB()
ipdb.interfaces["vlan100"].remove()
ipdb.interfaces["br100"].remove()
ipdb.commit()

Validating VXLAN Tunnel

Ping

site1server to site2server

vagrant@site1server:~$ ping 172.16.0.11
PING 172.16.0.11 (172.16.0.11) 56(84) bytes of data.
64 bytes from 172.16.0.11: icmp_seq=1 ttl=64 time=1.24 ms
^C
--- 172.16.0.11 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.246/1.246/1.246/0.000 ms
vagrant@site1server:~$

PCAP

site1router eth2 interface eth2

site1router vxlan100 interface vxlan100

site1router br100 interface br100

site1router eth1 interface eth1

Helpful References

I couldn’t have created this post without the following helpful sites.