Merge "Create virtual tunnel port when specified"
This commit is contained in:
commit
9c3fdc4060
|
@ -34,6 +34,12 @@ DF_OPTS = [
|
|||
cfg.StrOpt('tunnel_type',
|
||||
default='geneve',
|
||||
help=_('The encapsulation type for the tunnel')),
|
||||
cfg.BoolOpt('enable_virtual_tunnel_port',
|
||||
default=False,
|
||||
help=_("Enable virtual tunnel port")),
|
||||
cfg.ListOpt('tunnel_types',
|
||||
default=['geneve', 'vxlan', 'gre'],
|
||||
help=_("The encapsulation types for the tunnels")),
|
||||
cfg.StrOpt('apps_list',
|
||||
default='l2_app.L2App,'
|
||||
'l3_proactive_app.L3ProactiveApp,'
|
||||
|
|
|
@ -59,7 +59,13 @@ class DfLocalController(object):
|
|||
self.db_store = db_store.DbStore()
|
||||
self.chassis_name = chassis_name
|
||||
self.ip = cfg.CONF.df.local_ip
|
||||
self.tunnel_type = cfg.CONF.df.tunnel_type
|
||||
if cfg.CONF.df.enable_virtual_tunnel_port:
|
||||
# Virtual tunnel port support multiple tunnel types together
|
||||
self.tunnel_types = cfg.CONF.df.tunnel_types
|
||||
else:
|
||||
# TODO(xiaohhui): This should be removed once virtual tunnel port
|
||||
# is implemented.
|
||||
self.tunnel_types = cfg.CONF.df.tunnel_type
|
||||
self.sync_finished = False
|
||||
self.port_status_notifier = None
|
||||
nb_driver = df_utils.load_driver(
|
||||
|
@ -329,7 +335,7 @@ class DfLocalController(object):
|
|||
chassis_lports = self.db_store.get_lports_by_remote_chassis(chassis)
|
||||
if not chassis_lports:
|
||||
chassis_value = {'id': chassis, 'ip': chassis,
|
||||
'tunnel_type': self.tunnel_type}
|
||||
'tunnel_type': self.tunnel_types}
|
||||
chassis_inst = models.Chassis(jsonutils.dumps(chassis_value))
|
||||
self.chassis_created(chassis_inst)
|
||||
self.db_store.add_remote_chassis_lport(chassis, lport.get_id())
|
||||
|
@ -441,13 +447,36 @@ class DfLocalController(object):
|
|||
def register_chassis(self):
|
||||
chassis = self.nb_api.get_chassis(self.chassis_name)
|
||||
# TODO(gsagie) Support tunnel type change here ?
|
||||
|
||||
if chassis is None:
|
||||
self.nb_api.add_chassis(self.chassis_name,
|
||||
self.ip,
|
||||
self.tunnel_type)
|
||||
self.tunnel_types)
|
||||
else:
|
||||
if cfg.CONF.df.enable_virtual_tunnel_port:
|
||||
old_tunnel_types = chassis.get_encap_type()
|
||||
if (not isinstance(old_tunnel_types, list) or
|
||||
set(self.tunnel_types) != set(old_tunnel_types)):
|
||||
# There are 2 cases that needs update tunnel type in
|
||||
# chassis. 1) User changes tunnel types in conf file
|
||||
# 2) An old controller support only one type tunnel switch
|
||||
# to support virtual tunnel port.
|
||||
self.nb_api.update_chassis(self.chassis_name,
|
||||
tunnel_type=self.tunnel_types)
|
||||
|
||||
def create_tunnels(self):
|
||||
if cfg.CONF.df.enable_virtual_tunnel_port:
|
||||
tunnel_ports = self.vswitch_api.get_virtual_tunnel_ports()
|
||||
for tunnel_port in tunnel_ports:
|
||||
if tunnel_port.get_tunnel_type() not in self.tunnel_types:
|
||||
self.vswitch_api.delete_port(tunnel_port)
|
||||
|
||||
for t in self.tunnel_types:
|
||||
# The customized ovs idl will ingore the command if the port
|
||||
# already exists.
|
||||
self.vswitch_api.add_virtual_tunnel_port(t)
|
||||
|
||||
return
|
||||
|
||||
tunnel_ports = {}
|
||||
t_ports = self.vswitch_api.get_tunnel_ports()
|
||||
for t_port in t_ports:
|
||||
|
|
|
@ -390,6 +390,15 @@ class NbApi(object):
|
|||
self.driver.create_key(db_models.Chassis.table_name,
|
||||
id, chassis_json, None)
|
||||
|
||||
def update_chassis(self, id, **columns):
|
||||
chassis_json = self.driver.get_key('chassis', id)
|
||||
chassis = jsonutils.loads(chassis_json)
|
||||
for col, val in columns.items():
|
||||
chassis[col] = val
|
||||
|
||||
chassis_json = jsonutils.dumps(chassis)
|
||||
self.driver.set_key('chassis', id, chassis_json, None)
|
||||
|
||||
def get_lswitch(self, id, topic=None):
|
||||
try:
|
||||
lswitch_value = self.driver.get_key(
|
||||
|
|
|
@ -86,3 +86,41 @@ class AddTunnelPort(commands.BaseCommand):
|
|||
ports = getattr(bridge, 'ports', [])
|
||||
ports.append(port)
|
||||
bridge.ports = ports
|
||||
|
||||
|
||||
class AddVirtualTunnelPort(commands.BaseCommand):
|
||||
def __init__(self, api, tunnel_type):
|
||||
super(AddVirtualTunnelPort, self).__init__(api)
|
||||
self.tunnel_type = tunnel_type
|
||||
self.integration_bridge = cfg.CONF.df.integration_bridge
|
||||
self.port = tunnel_type + "-vtp"
|
||||
|
||||
def run_idl(self, txn):
|
||||
port = idlutils.row_by_value(self.api.idl, 'Port', 'name',
|
||||
self.port, None)
|
||||
if port:
|
||||
return
|
||||
|
||||
bridge = idlutils.row_by_value(self.api.idl, 'Bridge',
|
||||
'name', self.integration_bridge)
|
||||
|
||||
port = txn.insert(self.api._tables['Port'])
|
||||
port.name = self.port
|
||||
bridge.verify('ports')
|
||||
ports = getattr(bridge, 'ports', [])
|
||||
ports.append(port)
|
||||
bridge.ports = ports
|
||||
|
||||
iface = txn.insert(self.api._tables['Interface'])
|
||||
txn.expected_ifaces.add(iface.uuid)
|
||||
iface.name = self.port
|
||||
iface.type = self.tunnel_type
|
||||
options_dict = getattr(iface, 'options', {})
|
||||
options_dict['remote_ip'] = 'flow'
|
||||
options_dict['key'] = 'flow'
|
||||
options_dict['local_ip'] = cfg.CONF.df.local_ip
|
||||
iface.options = options_dict
|
||||
port.verify('interfaces')
|
||||
ifaces = getattr(port, 'interfaces', [])
|
||||
ifaces.append(iface)
|
||||
port.interfaces = ifaces
|
||||
|
|
|
@ -174,3 +174,6 @@ class DFOvsdbApi(impl_idl.OvsdbIdl):
|
|||
|
||||
def add_patch_port(self, bridge, port, remote_name):
|
||||
return commands.AddPatchPort(self, bridge, port, remote_name)
|
||||
|
||||
def add_virtual_tunnel_port(self, tunnel_type):
|
||||
return commands.AddVirtualTunnelPort(self, tunnel_type)
|
||||
|
|
|
@ -130,15 +130,31 @@ class LocalInterface(object):
|
|||
self.remote_chassis_id))
|
||||
|
||||
|
||||
class OvsdbTunnelPort(object):
|
||||
class OvsdbPort(object):
|
||||
|
||||
def __init__(self, name):
|
||||
super(OvsdbPort, self).__init__()
|
||||
self.name = name
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
|
||||
class OvsdbTunnelPort(OvsdbPort):
|
||||
|
||||
def __init__(self, name, chassis_id):
|
||||
super(OvsdbTunnelPort, self).__init__()
|
||||
self.name = name
|
||||
super(OvsdbTunnelPort, self).__init__(name)
|
||||
self.chassis_id = chassis_id
|
||||
|
||||
def get_chassis_id(self):
|
||||
return self.chassis_id
|
||||
|
||||
def get_name(self):
|
||||
return self.name
|
||||
|
||||
class OvsdbVirtuaTunnelPort(OvsdbPort):
|
||||
|
||||
def __init__(self, name, tunnel_type):
|
||||
super(OvsdbVirtuaTunnelPort, self).__init__(name)
|
||||
self.tunnel_type = tunnel_type
|
||||
|
||||
def get_tunnel_type(self):
|
||||
return self.tunnel_type
|
||||
|
|
|
@ -98,9 +98,27 @@ class OvsApi(object):
|
|||
res.append(objects.OvsdbTunnelPort(port.name, chassis_id))
|
||||
return res
|
||||
|
||||
def get_virtual_tunnel_ports(self):
|
||||
ifaces = self.ovsdb.db_find(
|
||||
'Interface', ('options', '=', {'remote_ip': 'flow'}),
|
||||
columns=['name', 'type']).execute()
|
||||
tunnel_ports = []
|
||||
for iface in ifaces:
|
||||
if (self.integration_bridge !=
|
||||
self._get_bridge_for_iface(iface['name'])):
|
||||
continue
|
||||
|
||||
tunnel_ports.append(objects.OvsdbVirtuaTunnelPort(iface['name'],
|
||||
iface['type']))
|
||||
|
||||
return tunnel_ports
|
||||
|
||||
def add_tunnel_port(self, chassis):
|
||||
self.ovsdb.add_tunnel_port(chassis).execute()
|
||||
|
||||
def add_virtual_tunnel_port(self, tunnel_type):
|
||||
self.ovsdb.add_virtual_tunnel_port(tunnel_type).execute()
|
||||
|
||||
def delete_port(self, switch_port):
|
||||
self.ovsdb.del_port(switch_port.get_name(),
|
||||
self.integration_bridge).execute()
|
||||
|
|
|
@ -24,9 +24,6 @@ class TestOvsdbMonitor(test_base.DFTestBase):
|
|||
self.vswitch_api = vswitch_impl.OvsApi(self.local_ip)
|
||||
self.vswitch_api.initialize(self.nb_api)
|
||||
|
||||
def tearDown(self):
|
||||
super(TestOvsdbMonitor, self).tearDown()
|
||||
|
||||
def _check_wanted_vm_online(self, update, mac):
|
||||
if update.table != "ovsinterface":
|
||||
return False
|
||||
|
@ -187,3 +184,29 @@ class TestOvsdbMonitor(test_base.DFTestBase):
|
|||
timeout=const.DEFAULT_RESOURCE_READY_TIMEOUT, sleep=1,
|
||||
exception=Exception('Port was not deleted')
|
||||
)
|
||||
|
||||
def test_virtual_tunnel_port(self):
|
||||
def _clear_vtp():
|
||||
for tunnel_port in self.vswitch_api.get_virtual_tunnel_ports():
|
||||
self.vswitch_api.delete_port(tunnel_port)
|
||||
|
||||
self.addCleanup(_clear_vtp)
|
||||
|
||||
self.vswitch_api.add_virtual_tunnel_port('vxlan')
|
||||
self.vswitch_api.add_virtual_tunnel_port('geneve')
|
||||
|
||||
tunnel_ports = self.vswitch_api.get_virtual_tunnel_ports()
|
||||
self.assertEqual(2, len(tunnel_ports))
|
||||
tunnel_types = set()
|
||||
for t in tunnel_ports:
|
||||
self.assertEqual(t.get_tunnel_type() + "-vtp",
|
||||
t.get_name())
|
||||
tunnel_types.add(t.get_tunnel_type())
|
||||
|
||||
self.assertEqual({'vxlan', 'geneve'}, tunnel_types)
|
||||
|
||||
for t in tunnel_ports:
|
||||
self.vswitch_api.delete_port(t)
|
||||
|
||||
tunnel_ports = self.vswitch_api.get_virtual_tunnel_ports()
|
||||
self.assertFalse(tunnel_ports)
|
||||
|
|
Loading…
Reference in New Issue