Enable L2GW Update with existing connections

This patch implements the update when there are
  existing connections. It allows the user to add
  or remove interfaces and the existing connections
  will be propagated to the new interfaces.

Change-Id: Ic18e138cc1fb328258d6520250e4e47f9d566ca3
Signed-off-by: Ricardo Noriega <rnoriega@redhat.com>
Co-Authored-By: Peng Liu <pliu@redhat.com>
stable/queens
Ricardo Noriega 5 years ago committed by Peng Liu
parent 8df0ae4dde
commit 255bc40e58
  1. 64
      networking_l2gw/db/l2gateway/l2gateway_db.py
  2. 14
      networking_l2gw/services/l2gateway/exceptions.py
  3. 142
      networking_l2gw/services/l2gateway/service_drivers/rpc_l2gw.py
  4. 41
      networking_l2gw/tests/unit/db/test_l2gw_db.py

@ -290,24 +290,24 @@ class L2GatewayMixin(l2gateway.L2GatewayPluginBase,
with context.session.begin(subtransactions=True):
gw_db = self._get_l2_gateway(context, l2_gw_id)
tenant_id = self._get_tenant_id_for_create(context, gw_db)
if self._retrieve_gateway_connections(context,
l2_gw_id,
nw_map):
raise l2gw_exc.L2GatewayConnectionExists(mapping=nw_map,
gateway_id=l2_gw_id)
nw_map['tenant_id'] = tenant_id
connection_id = uuidutils.generate_uuid()
nw_map['id'] = connection_id
if not segmentation_id:
nw_map['segmentation_id'] = "0"
gw_db.network_connections.append(
models.L2GatewayConnection(**nw_map))
gw_db = models.L2GatewayConnection(id=connection_id,
tenant_id=tenant_id,
network_id=network_id,
l2_gateway_id=l2_gw_id,
segmentation_id=segmentation_id)
return self._make_l2gw_connections_dict(gw_db)
conn_db = self._retrieve_gateway_connections(context, l2_gw_id,
nw_map)
if not conn_db:
connection_id = uuidutils.generate_uuid()
nw_map['id'] = connection_id
gw_db.network_connections.append(
models.L2GatewayConnection(**nw_map))
gw_db = models.L2GatewayConnection(
id=connection_id,
tenant_id=tenant_id,
network_id=network_id,
l2_gateway_id=l2_gw_id,
segmentation_id=segmentation_id)
return self._make_l2gw_connections_dict(gw_db)
return self._make_l2gw_connections_dict(conn_db[0])
def get_l2_gateway_connections(self, context, filters=None,
fields=None,
@ -495,21 +495,41 @@ class L2GatewayMixin(l2gateway.L2GatewayPluginBase,
gw = l2_gateway[self.gateway_resource]
devices = None
dev_db = None
l2gw_db = None
if 'devices' in gw:
devices = gw['devices']
if not devices:
return
with context.session.begin(subtransactions=True):
l2gw_db = self._get_l2_gateway(context, id)
if l2gw_db.network_connections:
raise l2gw_exc.L2GatewayInUse(gateway_id=id)
# Attemp to retrieve l2gw
gw_db = self._get_l2_gateway(context, id)
if devices:
for device in devices:
dev_name = device['device_name']
dev_db = (self._get_l2gw_devices_by_name_andl2gwid(
context, dev_name, id))
dev_db = self._get_l2gw_devices_by_name_andl2gwid(
context, dev_name, id)
if not dev_db:
raise l2gw_exc.L2GatewayDeviceNotFound(device_id="")
raise l2gw_exc.L2GatewayDeviceNotFound(
device_id=dev_name)
self.validate_device_name(context, dev_name, id)
interface_list = device['interfaces']
if not interface_list:
raise l2gw_exc.L2GatewayInterfaceRequired()
if constants.SEG_ID in interface_list[0]:
for interfaces in interface_list:
if constants.SEG_ID not in interfaces:
raise l2gw_exc.L2GatewaySegmentationRequired()
if constants.SEG_ID not in interface_list[0]:
for interfaces in interface_list[1:]:
if constants.SEG_ID in interfaces:
raise l2gw_exc.L2GatewaySegmentationRequired()
if gw_db.devices:
if gw_db.devices[0].interfaces[0]['segmentation_id']:
if constants.SEG_ID not in interface_list[0]:
raise l2gw_exc.L2GatewaySegmentationIDExists()
else:
if constants.SEG_ID in interface_list[0]:
raise l2gw_exc.\
L2GatewaySegmentationIDNotExists()
def validate_l2_gateway_connection_for_create(self, context,
l2_gateway_connection):

@ -65,6 +65,11 @@ class L2GatewayInterfaceNotFound(exceptions.NeutronException):
message = _("L2 Gateway interface '%(interface_id)s' not found.")
class L2GatewayPhysicalPortNotFound(exceptions.NeutronException):
message = _("Physical Port '%(int_name)s' in Physical switch "
"'%(device_name)s' could not be found")
class L2GatewayPhysicalPortFaultStatus(exceptions.NeutronException):
message = _("Physical Port '%(int_name)s' in Physical switch "
"'%(device_name)s' port_fault_status is '%(fault_status)s'")
@ -98,9 +103,14 @@ class L2GatewayInterfaceRequired(exceptions.NeutronException):
message = _("L2 Gateway Interface required")
class L2GatewaySegmentationIDExists(exceptions.InUse):
class L2GatewaySegmentationIDExists(exceptions.NeutronException):
message = _("The segmentation id is already specified in "
"gateway interface '%(interface_id)s'.")
"existing gateway interfaces.")
class L2GatewaySegmentationIDNotExists(exceptions.NeutronException):
message = _("The segmentation id is not specified in "
"existing gateway interfaces.")
class L2GatewaySegmentationRequired(exceptions.NeutronException):

@ -347,6 +347,32 @@ class L2gwRpcDriver(service_drivers.L2gwDriver):
int_name=int_name, device_name=device_name,
fault_status=port_status)
def _validate_gateway_for_update(self, context, gw):
LOG.debug("L2gwRpcDriver._validate_gateway_for_update gw=%s",
gw)
devices = gw.get('l2_gateway').get('devices')
for device in devices:
interfaces = device.get('interfaces')
device_name = device.get("device_name")
for interface in interfaces:
interface_name = interface.get('name')
physical_switch = db.get_physical_switch_by_name(
context, device.get('device_name'))
if not physical_switch:
raise l2gw_exc.L2GatewayDeviceNotFound(
device_id=device_name)
ovsdb_identifier = physical_switch.get('ovsdb_identifier')
pp_dict = {'interface_name': interface_name,
'ovsdb_identifier': ovsdb_identifier,
'physical_switch_id': physical_switch.get('uuid')}
ps_port = db.get_physical_port_by_name_and_ps(context, pp_dict)
if not ps_port:
raise l2gw_exc.L2GatewayPhysicalPortNotFound(
int_name=interface_name,
device_name=device_name)
def _validate_connection(self, context, gw_connection):
seg_id = gw_connection.get('segmentation_id', None)
l2_gw_id = gw_connection.get('l2_gateway_id')
@ -388,8 +414,12 @@ class L2gwRpcDriver(service_drivers.L2gwDriver):
seg_id = gw_connection.get('segmentation_id', None)
interfaces = self.service_plugin.get_l2gateway_interfaces_by_device_id(
context, device['id'])
LOG.debug("L2gwRpcDriver._process_port_list: ints=%s",
interfaces)
for interface in interfaces:
interface_name = interface.get('interface_name')
LOG.debug("L2gwRpcDriver._process_port_list: int_name=%s",
interface_name)
physical_switch = db.get_physical_switch_by_name(
context, device.get('device_name'))
if not physical_switch:
@ -417,6 +447,8 @@ class L2gwRpcDriver(service_drivers.L2gwDriver):
raise Exception(msg)
pp_dict['uuid'] = ps_port.get('uuid')
pp_dict['name'] = ps_port.get('name')
LOG.debug("L2gwRpcDriver._process_port_list: pp_dict.name=%s",
pp_dict['name'])
port_dict = self._generate_port_list(
context, method, seg_id, interface, pp_dict,
logical_switch_uuid, gw_connection)
@ -606,11 +638,115 @@ class L2gwRpcDriver(service_drivers.L2gwDriver):
pass
def update_l2_gateway(self, context, l2_gateway_id, l2_gateway):
"""Update l2 gateway."""
pass
"""Check the port list for update"""
self.service_plugin._admin_check(context, 'UPDATE')
self._validate_gateway_for_update(context, l2_gateway)
self.port_dict_before_update = []
# get l2 gateway devices
l2gateway_devices = (
self.service_plugin.get_l2gateway_devices_by_gateway_id(
context, l2_gateway_id))
# get l2 gateway connections
gw_connections = self.service_plugin._get_l2_gateway_connections(
context)
for gw_connection in gw_connections:
for device in l2gateway_devices:
ovsdb_identifier, logical_switch, port_dict \
= (self._process_port_list(context, device,
gw_connection, "UPDATE"))
self.port_dict_before_update.extend(port_dict)
def update_l2_gateway_postcommit(self, context, l2_gateway):
pass
"""Process the call from the CLI and trigger the RPC,
to update the connection of the gateway.
"""
self.service_plugin._admin_check(context, 'UPDATE')
# get l2 gateway devices
l2gateway_devices = (
self.service_plugin.get_l2gateway_devices_by_gateway_id(
context, l2_gateway['id']))
# get l2 gateway connections
gw_connections = self.service_plugin._get_l2_gateway_connections(
context)
for gw_connection in gw_connections:
u_mac_dict = {}
mac_dict = {}
for device in l2gateway_devices:
locator_list = []
ovsdb_identifier, logical_switch, port_dict = (
self._process_port_list(context, device,
gw_connection, "UPDATE"))
ls_dict = self._get_logical_switch_dict(
context, logical_switch, gw_connection)
port_dict_before_update_con = \
[port for port in self.port_dict_before_update
if port['vlan_bindings'][0]['logical_switch_uuid'] ==
logical_switch['uuid']]
port_dict_add = \
[port for port in port_dict
if port not in port_dict_before_update_con]
port_dict_delete = \
[port for port in port_dict_before_update_con
if port not in port_dict]
if port_dict_add:
ports = self._get_port_details(
context, gw_connection.get('network_id'))
LOG.debug("L2gwRpcDriver.update_l2_gw: ports=%s", ports)
for port in ports:
mac_list = []
if port['device_owner']:
dst_ip, ip_address = self._get_ip_details(context,
port)
mac_ip_pairs = []
if isinstance(
port.get("allowed_address_pairs"), list):
for address_pair in \
port['allowed_address_pairs']:
mac = address_pair['mac_address']
mac_ip_pairs.append(
(mac, address_pair['ip_address']))
mac_ip_pairs.append((port.get('mac_address'),
ip_address))
for mac, ip in mac_ip_pairs:
mac_remote = self._get_dict(
ovsdb_schema.UcastMacsRemote(
uuid=None,
mac=mac,
logical_switch_id=None,
physical_locator_id=None,
ip_address=ip))
if logical_switch:
u_mac_dict['mac'] = mac
u_mac_dict['ovsdb_identifier'] = \
ovsdb_identifier
u_mac_dict['logical_switch_uuid'] = (
logical_switch.get('uuid'))
ucast_mac_remote = (
db.get_ucast_mac_remote_by_mac_and_ls(
context, u_mac_dict))
if not ucast_mac_remote:
mac_list.append(mac_remote)
else:
mac_list.append(mac_remote)
locator_list = self._get_locator_list(
context, dst_ip, ovsdb_identifier, mac_list,
locator_list)
for locator in locator_list:
mac_dict[locator.get('dst_ip')] = locator.pop('macs')
locator.pop('ovsdb_identifier')
self.agent_rpc.update_connection_to_gateway(
context, ovsdb_identifier, ls_dict, locator_list,
mac_dict, port_dict_add, 'CREATE')
if port_dict_delete:
self.agent_rpc.update_connection_to_gateway(
context, ovsdb_identifier, ls_dict, locator_list,
mac_dict, port_dict_delete, 'DELETE')
def delete_l2_gateway(self, context, id):
"""delete the l2 gateway by id."""

@ -92,6 +92,15 @@ class L2GWTestCase(testlib_api.SqlTestCase):
"device_name": device_name}]}}
return data
def _get_l2_gw_multiple_interface_without_seg_id_data(self, name,
device_name):
"""Get l2 gateway data helper method with partial seg id."""
return {"l2_gateway": {"name": name,
"devices":
[{"interfaces": [{"name": "port1"},
{"name": "port2"}],
"device_name": device_name}]}}
def _get_l2_gw_invalid_seg_id_data(self, name,
device_name):
"""Get l2 gateway data helper method with invalid seg id."""
@ -343,6 +352,38 @@ class L2GWTestCase(testlib_api.SqlTestCase):
self.assertRaises(exceptions.L2GatewaySegmentationRequired,
self._validate_l2_gateway_for_create, data)
def test_l2_gateway_update_with_mul_interfaces_inconsistent_seg_id(self):
"""Test l2 gateway update with multiple interfaces."""
name = "l2gw_1"
dev_name = "device1"
data_orig = self._get_l2_gateway_multiple_interface_data(name,
dev_name)
data = self._get_l2_gw_multiple_interface_partial_seg_id_data(name,
dev_name)
gw_org = self._create_l2gateway(data_orig)
l2gw_id = gw_org['id']
self.assertRaises(exceptions.L2GatewaySegmentationRequired,
self._validate_l2_gateway_for_update, l2gw_id, data)
def test_l2_gateway_update_with_mul_interfaces_without_seg_id(self):
"""Test l2 gateway update with multiple interfaces without seg_id."""
name = "l2gw_1"
dev_name = "device1"
data1 = self._get_l2_gateway_multiple_interface_data(
name, dev_name)
data2 = self._get_l2_gw_multiple_interface_without_seg_id_data(
name, dev_name)
gw_org1 = self._create_l2gateway(data1)
l2gw_id1 = gw_org1['id']
gw_org2 = self._create_l2gateway(data2)
l2gw_id2 = gw_org2['id']
self.assertRaises(exceptions.L2GatewaySegmentationIDExists,
self._validate_l2_gateway_for_update,
l2gw_id1, data2)
self.assertRaises(exceptions.L2GatewaySegmentationIDNotExists,
self._validate_l2_gateway_for_update,
l2gw_id2, data1)
def test_l2_gateway_create_with_invalid_seg_id(self):
"""Test l2 gateway create with invalid seg-id."""
name = "l2gw_1"

Loading…
Cancel
Save