Merge "Add support for OVS tunnels"
This commit is contained in:
commit
4d88e7f349
@ -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.
|
||||
|
||||
|
@ -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."""
|
||||
|
||||
|
@ -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):
|
||||
@ -345,7 +347,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.'
|
||||
@ -617,3 +620,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)
|
||||
|
@ -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')
|
||||
|
@ -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..
|
||||
|
Loading…
x
Reference in New Issue
Block a user