Merge "Create virtual tunnel port when specified"

This commit is contained in:
Jenkins 2016-11-29 05:27:11 +00:00 committed by Gerrit Code Review
commit 9c3fdc4060
8 changed files with 154 additions and 12 deletions

View File

@ -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,'

View File

@ -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:

View File

@ -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(

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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()

View File

@ -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)