aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Slagle <jslagle@redhat.com>2016-04-11 12:19:51 -0400
committerJames Slagle <jslagle@redhat.com>2016-04-13 12:32:22 -0400
commitd325a1a2f8d7c815cbaa016858db053412201b9d (patch)
tree35033588fa76d32c260076229a4f5f22907406ad
parent1134091ff1a6a0fc9f8dc6fe4d70bf0274728fdd (diff)
Add support for OVS tunnels
Adds support for configuring OVS Tunnels via os-net-config. Tunnels are configured as members of ovs_bridge's where the type is set to ovs_tunnel. The object also supports setting OVS extra and options so that additional tunnel data can be defined, such as remote_ip. Change-Id: I31ac1cbe8a13247a1529c0f99a0aea5807888844
-rw-r--r--os_net_config/__init__.py9
-rw-r--r--os_net_config/impl_ifcfg.py18
-rw-r--r--os_net_config/objects.py37
-rw-r--r--os_net_config/tests/test_impl_ifcfg.py38
-rw-r--r--os_net_config/tests/test_objects.py34
5 files changed, 135 insertions, 1 deletions
diff --git a/os_net_config/__init__.py b/os_net_config/__init__.py
index 745da18..700a09d 100644
--- a/os_net_config/__init__.py
+++ b/os_net_config/__init__.py
@@ -71,6 +71,8 @@ class NetConfig(object):
self.add_linux_bond(obj)
for member in obj.members:
self.add_object(member)
+ elif isinstance(obj, objects.OvsTunnel):
+ self.add_ovs_tunnel(obj)
def add_interface(self, interface):
"""Add an Interface object to the net config object.
@@ -121,6 +123,13 @@ class NetConfig(object):
"""
raise NotImplemented("add_linux_bond is not implemented.")
+ def add_ovs_tunnel(self, tunnel):
+ """Add a OvsTunnel object to the net config object.
+
+ :param tunnel: The OvsTunnel object to add.
+ """
+ raise NotImplemented("add_ovs_tunnel is not implemented.")
+
def apply(self, cleanup=False):
"""Apply the network configuration.
diff --git a/os_net_config/impl_ifcfg.py b/os_net_config/impl_ifcfg.py
index 6459bcc..f6b4617 100644
--- a/os_net_config/impl_ifcfg.py
+++ b/os_net_config/impl_ifcfg.py
@@ -177,6 +177,14 @@ class IfcfgNetConfig(os_net_config.NetConfig):
self.member_names[base_opt.name] = members
if base_opt.bonding_options:
data += "BONDING_OPTS=\"%s\"\n" % base_opt.bonding_options
+ elif isinstance(base_opt, objects.OvsTunnel):
+ ovs_extra.extend(base_opt.ovs_extra)
+ data += "DEVICETYPE=ovs\n"
+ data += "TYPE=OVSTunnel\n"
+ data += "OVS_BRIDGE=%s\n" % base_opt.bridge_name
+ data += "OVS_TUNNEL_TYPE=%s\n" % base_opt.tunnel_type
+ data += "OVS_TUNNEL_OPTIONS=\"%s\"\n" % \
+ ' '.join(base_opt.ovs_options)
else:
if base_opt.use_dhcp:
data += "BOOTPROTO=dhcp\n"
@@ -356,6 +364,16 @@ class IfcfgNetConfig(os_net_config.NetConfig):
if bond.routes:
self._add_routes(bond.name, bond.routes)
+ def add_ovs_tunnel(self, tunnel):
+ """Add a OvsTunnel object to the net config object.
+
+ :param tunnel: The OvsTunnel object to add.
+ """
+ logger.info('adding ovs tunnel: %s' % tunnel.name)
+ data = self._add_common(tunnel)
+ logger.debug('ovs tunnel data: %s' % data)
+ self.interface_data[tunnel.name] = data
+
def generate_ivs_config(self, ivs_uplinks, ivs_interfaces):
"""Generate configuration content for ivs."""
diff --git a/os_net_config/objects.py b/os_net_config/objects.py
index 4f3e0d5..2db7cf5 100644
--- a/os_net_config/objects.py
+++ b/os_net_config/objects.py
@@ -48,6 +48,8 @@ def object_from_json(json):
return IvsBridge.from_json(json)
elif obj_type == "ivs_interface":
return IvsInterface.from_json(json)
+ elif obj_type == "ovs_tunnel":
+ return OvsTunnel.from_json(json)
def _get_required_field(json, name, object_name):
@@ -343,7 +345,8 @@ class OvsBridge(_BaseOpts):
self.ovs_extra = ovs_extra
for member in self.members:
member.bridge_name = name
- member.ovs_port = True
+ if not isinstance(member, OvsTunnel):
+ member.ovs_port = True
if member.primary:
if self.primary_interface_name:
msg = 'Only one primary interface allowed per bridge.'
@@ -615,3 +618,35 @@ class OvsBond(_BaseOpts):
ovs_extra=ovs_extra, nic_mapping=nic_mapping,
persist_mapping=persist_mapping, defroute=defroute,
dhclient_args=dhclient_args, dns_servers=dns_servers)
+
+
+class OvsTunnel(_BaseOpts):
+ """Base class for OVS Tunnels."""
+
+ def __init__(self, name, use_dhcp=False, use_dhcpv6=False, addresses=None,
+ routes=None, mtu=None, primary=False, nic_mapping=None,
+ persist_mapping=False, defroute=True, dhclient_args=None,
+ dns_servers=None, tunnel_type=None, ovs_options=None,
+ ovs_extra=None):
+ addresses = addresses or []
+ routes = routes or []
+ ovs_extra = ovs_extra or []
+ dns_servers = dns_servers or []
+ super(OvsTunnel, self).__init__(name, use_dhcp, use_dhcpv6, addresses,
+ routes, mtu, primary, nic_mapping,
+ persist_mapping, defroute,
+ dhclient_args, dns_servers)
+ self.tunnel_type = tunnel_type
+ self.ovs_options = ovs_options or []
+ self.ovs_extra = ovs_extra or []
+
+ @staticmethod
+ def from_json(json):
+ name = _get_required_field(json, 'name', 'OvsTunnel')
+ tunnel_type = _get_required_field(json, 'tunnel_type', 'OvsTunnel')
+ ovs_options = json.get('ovs_options', [])
+ ovs_options = ['options:%s' % opt for opt in ovs_options]
+ ovs_extra = json.get('ovs_extra', [])
+ opts = _BaseOpts.base_opts_from_json(json)
+ return OvsTunnel(name, *opts, tunnel_type=tunnel_type,
+ ovs_options=ovs_options, ovs_extra=ovs_extra)
diff --git a/os_net_config/tests/test_impl_ifcfg.py b/os_net_config/tests/test_impl_ifcfg.py
index d68a96e..f4701a0 100644
--- a/os_net_config/tests/test_impl_ifcfg.py
+++ b/os_net_config/tests/test_impl_ifcfg.py
@@ -76,6 +76,19 @@ _V6_IFCFG_MULTIPLE = (_V6_IFCFG + "IPV6ADDR_SECONDARIES=\"2001:abc:b::1/64 " +
_OVS_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\nBOOTPROTO=none\n"
+_OVS_IFCFG_TUNNEL = """# This file is autogenerated by os-net-config
+DEVICE=tun0
+ONBOOT=yes
+HOTPLUG=no
+NM_CONTROLLED=no
+PEERDNS=no
+DEVICETYPE=ovs
+TYPE=OVSTunnel
+OVS_BRIDGE=br-ctlplane
+OVS_TUNNEL_TYPE=gre
+OVS_TUNNEL_OPTIONS="options:remote_ip=192.168.1.1"
+"""
+
_OVS_BRIDGE_IFCFG = _BASE_IFCFG + "DEVICETYPE=ovs\n"
@@ -287,6 +300,15 @@ class TestIfcfgNetConfig(base.TestCase):
self.provider.add_interface(interface)
self.assertEqual(_OVS_IFCFG, self.get_interface_config())
+ def test_add_ovs_tunnel(self):
+ interface = objects.OvsTunnel('tun0')
+ interface.type = 'ovs_tunnel'
+ interface.tunnel_type = 'gre'
+ interface.ovs_options = ['options:remote_ip=192.168.1.1']
+ interface.bridge_name = 'br-ctlplane'
+ self.provider.add_interface(interface)
+ self.assertEqual(_OVS_IFCFG_TUNNEL, self.get_interface_config('tun0'))
+
def test_add_interface_with_v4(self):
v4_addr = objects.Address('192.168.1.2/24')
interface = objects.Interface('em1', addresses=[v4_addr])
@@ -389,6 +411,22 @@ class TestIfcfgNetConfig(base.TestCase):
self.assertEqual(_OVS_BRIDGE_STATIC,
self.provider.bridge_data['br-ctlplane'])
+ def test_network_ovs_bridge_with_tunnel(self):
+ interface = objects.OvsTunnel('tun0')
+ interface.type = 'ovs_tunnel'
+ interface.tunnel_type = 'gre'
+ interface.ovs_options = ['options:remote_ip=192.168.1.1']
+ interface.bridge_name = 'br-ctlplane'
+ self.provider.add_interface(interface)
+ v4_addr = objects.Address('192.168.1.2/24')
+ bridge = objects.OvsBridge('br-ctlplane', members=[interface],
+ addresses=[v4_addr])
+ self.provider.add_bridge(bridge)
+ self.provider.add_interface(interface)
+ self.assertEqual(_OVS_IFCFG_TUNNEL, self.get_interface_config('tun0'))
+ self.assertEqual(_OVS_BRIDGE_STATIC,
+ self.provider.bridge_data['br-ctlplane'])
+
def test_network_linux_bridge_static(self):
v4_addr = objects.Address('192.168.1.2/24')
interface = objects.Interface('em1')
diff --git a/os_net_config/tests/test_objects.py b/os_net_config/tests/test_objects.py
index d3e41df..a7b4230 100644
--- a/os_net_config/tests/test_objects.py
+++ b/os_net_config/tests/test_objects.py
@@ -514,6 +514,40 @@ class TestLinuxBond(base.TestCase):
self.assertEqual("em2", interface2.name)
+class TestOvsTunnel(base.TestCase):
+
+ def test_from_json(self):
+ data = """{
+"type": "ovs_bridge",
+"name": "br-foo",
+"members": [{
+ "type": "ovs_tunnel",
+ "name": "tun0",
+ "tunnel_type": "gre",
+ "ovs_options": [
+ "remote_ip=192.168.1.1"
+ ],
+ "ovs_extra": [
+ "ovs extra"
+ ]
+}]
+}
+"""
+ bridge = objects.object_from_json(json.loads(data))
+ self.assertEqual("br-foo", bridge.name)
+ tun0 = bridge.members[0]
+ self.assertEqual("tun0", tun0.name)
+ self.assertFalse(tun0.ovs_port)
+ self.assertEqual("br-foo", tun0.bridge_name)
+ self.assertEqual("gre", tun0.tunnel_type)
+ self.assertEqual(
+ ["options:remote_ip=192.168.1.1"],
+ tun0.ovs_options)
+ self.assertEqual(
+ ["ovs extra"],
+ tun0.ovs_extra)
+
+
class TestNumberedNicsMapping(base.TestCase):
# We want to test the function, not the dummy..