From: Ondrej Lichtner <olichtne(a)redhat.com>
This adds support for configuring VXLAN devices. Included is an example
recipe in the recipes/examples/vxlan.xml file.
Signed-off-by: Ondrej Lichtner <olichtne(a)redhat.com>
---
lnst/Controller/Machine.py | 2 +-
lnst/Controller/RecipeParser.py | 20 ++++++++++++++
lnst/Slave/InterfaceManager.py | 2 ++
lnst/Slave/NetConfigDevice.py | 55 ++++++++++++++++++++++++++++++++++++-
lnst/Slave/NmConfigDevice.py | 9 ++++++-
recipes/examples/vxlan.xml | 60 +++++++++++++++++++++++++++++++++++++++++
schema-recipe.rng | 8 ++++++
7 files changed, 153 insertions(+), 3 deletions(-)
create mode 100644 recipes/examples/vxlan.xml
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py
index 7281203..f04710c 100644
--- a/lnst/Controller/Machine.py
+++ b/lnst/Controller/Machine.py
@@ -593,7 +593,7 @@ class Interface(object):
def add_slave(self, iface):
self._slaves[iface.get_id()] = iface
- if self._type in ["vlan"]:
+ if self._type in ["vlan", "vxlan"]:
iface.add_master(self, primary=False)
else:
iface.add_master(self)
diff --git a/lnst/Controller/RecipeParser.py b/lnst/Controller/RecipeParser.py
index 318b231..827279f 100644
--- a/lnst/Controller/RecipeParser.py
+++ b/lnst/Controller/RecipeParser.py
@@ -184,6 +184,26 @@ class RecipeParser(XmlParser):
opts = self._process_options(opts_tag)
if len(opts) > 0:
iface["options"] = opts
+ elif iface["type"] in ["vxlan"]:
+ # real_dev of the VXLAN interface
+ slaves_tag = iface_tag.find("slaves")
+ if slaves_tag is not None and len(slaves_tag) > 1:
+ msg = "VXLAN '%s' needs one or no slave definition."\
+ % iface["id"]
+ raise RecipeError(msg, iface_tag)
+
+ if slaves_tag:
+ iface["slaves"] = XmlCollection(slaves_tag)
+ slave_tag = slaves_tag[0]
+ slave = XmlData(slave_tag)
+ slave["id"] = self._get_attribute(slave_tag, "id")
+ iface["slaves"].append(slave)
+
+ # interface options
+ opts_tag = iface_tag.find("options")
+ opts = self._process_options(opts_tag)
+ if len(opts) > 0:
+ iface["options"] = opts
elif iface["type"] == "ovs_bridge":
slaves_tag = iface_tag.find("slaves")
iface["slaves"] = XmlCollection(slaves_tag)
diff --git a/lnst/Slave/InterfaceManager.py b/lnst/Slave/InterfaceManager.py
index a99c2ae..8bb3bae 100644
--- a/lnst/Slave/InterfaceManager.py
+++ b/lnst/Slave/InterfaceManager.py
@@ -266,6 +266,8 @@ class InterfaceManager(object):
return self._assign_name_generic("vti")
elif dev_type == "vti6":
return self._assign_name_generic("t_ip6vti")
+ elif dev_type == "vxlan":
+ return self._assign_name_generic("vxlan")
else:
return self._assign_name_generic("dev")
diff --git a/lnst/Slave/NetConfigDevice.py b/lnst/Slave/NetConfigDevice.py
index 809c0c5..eebcb35 100644
--- a/lnst/Slave/NetConfigDevice.py
+++ b/lnst/Slave/NetConfigDevice.py
@@ -281,6 +281,58 @@ class NetConfigDeviceVlan(NetConfigDeviceGeneric):
super(NetConfigDeviceVlan, self).up()
+class NetConfigDeviceVxlan(NetConfigDeviceGeneric):
+ _modulename = ""
+
+ def create(self):
+ config = self._dev_config
+
+ slaves = get_slaves(config)
+ if len(slaves) == 1:
+ realdev_id = slaves[0]
+ name = self._if_manager.get_mapped_device(realdev_id).get_name()
+ dev_param = "dev %s" % name
+ else:
+ dev_param = ""
+
+ dev_name = config["name"]
+ vxlan_id = int(get_option(config, "id"))
+ group_ip = get_option(config, "group_ip")
+ remote_ip = get_option(config, "remote_ip")
+
+ if group_ip:
+ group_or_remote = "group %s" % group_ip
+ elif remote_ip:
+ group_or_remote = "remote %s" % remote_ip
+ else:
+ raise Exception("group or remote must be specified for vxlan")
+
+ dstport = get_option(config, "dstport")
+ if not dstport:
+ dstport = 0
+ else:
+ dstport = int(dstport)
+
+ exec_cmd("ip link add %s type vxlan id %d %s %s dstport %d"
+ % (dev_name,
+ vxlan_id,
+ dev_param,
+ group_or_remote,
+ dstport))
+
+ def destroy(self):
+ dev_name = self._dev_config["name"]
+ exec_cmd("ip link del %s" % dev_name)
+
+ def up(self):
+ slaves = get_slaves(self._dev_config)
+ if len(slaves) == 1:
+ parent_id = get_slaves(self._dev_config)[0]
+ parent_dev = self._if_manager.get_mapped_device(parent_id)
+ parent_dev.up()
+
+ super(NetConfigDeviceVxlan, self).up()
+
def prepare_json_str(json_str):
if not json_str:
return "{}"
@@ -563,7 +615,8 @@ type_class_mapping = {
"veth": NetConfigDeviceVEth,
"vti": NetConfigDeviceVti,
"vti6": NetConfigDeviceVti6,
- "lo": NetConfigDeviceLoopback
+ "lo": NetConfigDeviceLoopback,
+ "vxlan": NetConfigDeviceVxlan
}
def NetConfigDevice(dev_config, if_manager):
diff --git a/lnst/Slave/NmConfigDevice.py b/lnst/Slave/NmConfigDevice.py
index 40c6923..cbd3420 100644
--- a/lnst/Slave/NmConfigDevice.py
+++ b/lnst/Slave/NmConfigDevice.py
@@ -850,6 +850,12 @@ class NmConfigDeviceLoopback(NmConfigDeviceGeneric):
def is_nm_managed(cls, dev_config, if_manager):
return False
+class NmConfigDeviceVxlan(NmConfigDeviceGeneric):
+ #Not supported by NetworkManager
+ @classmethod
+ def is_nm_managed(cls, dev_config, if_manager):
+ return False
+
type_class_mapping = {
"eth": NmConfigDeviceEth,
"bond": NmConfigDeviceBond,
@@ -861,7 +867,8 @@ type_class_mapping = {
"veth": NmConfigDeviceVEth,
"vti": NmConfigDeviceVti,
"vti6": NmConfigDeviceVti6,
- "lo": NmConfigDeviceLoopback
+ "lo": NmConfigDeviceLoopback,
+ "vxlan": NmConfigDeviceVxlan
}
def is_nm_managed(dev_config, if_manager):
diff --git a/recipes/examples/vxlan.xml b/recipes/examples/vxlan.xml
new file mode 100644
index 0000000..547f79b
--- /dev/null
+++ b/recipes/examples/vxlan.xml
@@ -0,0 +1,60 @@
+<lnstrecipe>
+ <network>
+ <host id="testmachine1">
+ <interfaces>
+ <eth id="1" label="tnet">
+ <addresses>
+ <address value="192.168.101.1/24"/>
+ </addresses>
+ </eth>
+ <vxlan id="testifc1">
+ <options>
+ <option name="id" value="1"/>
+ <option name="group_ip" value="239.1.1.1"/>
+ <!--<option name="remote_ip" value="192.168.101.2"/>-->
+ </options>
+ <slaves>
+ <slave id="1"/>
+ </slaves>
+ <addresses>
+ <address value="192.168.100.1/24"/>
+ </addresses>
+ </vxlan>
+ </interfaces>
+ </host>
+
+ <host id="testmachine2">
+ <interfaces>
+ <eth id="1" label="tnet">
+ <addresses>
+ <address value="192.168.101.2/24"/>
+ </addresses>
+ </eth>
+ <vxlan id="testifc2">
+ <options>
+ <option name="id" value="1"/>
+ <option name="group_ip" value="239.1.1.1"/>
+ <!--<option name="remote_ip" value="192.168.101.1"/>-->
+ </options>
+ <slaves>
+ <slave id="1"/>
+ </slaves>
+ <addresses>
+ <address value="192.168.100.2/24"/>
+ </addresses>
+ </vxlan>
+ </interfaces>
+ </host>
+ </network>
+
+ <task>
+ <run host="testmachine1" module="IcmpPing">
+ <options>
+ <option name="addr" value="{ip(testmachine2,testifc2)}"/>
+ <option name="count" value="40"/>
+ <option name="interval" value="0"/>
+ <option name="iface" value="{devname(testmachine1, testifc1)}"/>
+ </options>
+ </run>
+ </task>
+</lnstrecipe>
diff --git a/schema-recipe.rng b/schema-recipe.rng
index c1ffbed..ad841bb 100644
--- a/schema-recipe.rng
+++ b/schema-recipe.rng
@@ -139,6 +139,7 @@
<ref name="vti"/>
<ref name="vti6"/>
<ref name="lo"/>
+ <ref name="vxlan"/>
</choice>
</zeroOrMore>
</element>
@@ -292,6 +293,13 @@
</element>
</define>
+ <define name="vxlan">
+ <element name="vxlan">
+ <attribute name="id"/>
+ <ref name="softdevice"/>
+ </element>
+ </define>
+
<define name="softdevice">
<optional>
<attribute name="netns"/>
--
2.6.4