From 5aee410131ea8d71d73cad72cb8421f580aa4a3d Mon Sep 17 00:00:00 2001 From: Sridar Kandaswamy Date: Tue, 7 Jan 2020 11:16:50 -0800 Subject: [PATCH] Enable SVI networks with hosts running opflex agent - Allow port binding on SVI networks with hosts running opflex agent - Supported with vlan type networks (not opflex networks) - Provides a flag indicating SVI network, the vlan id and the epg is set to a unique id (SVI network id) in response to get_gbp_details. This enables the opflex agent on the host to set up the data path appropriately. Change-Id: Ia0a3e4354141b04693fda8c1079acbbc76f371d9 --- .../drivers/apic_aim/mechanism_driver.py | 3 +- .../plugins/ml2plus/drivers/apic_aim/rpc.py | 13 +++- .../unit/plugins/ml2plus/test_apic_aim.py | 61 ++++++++++++++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py index 46496bc8e..4102467f5 100644 --- a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py +++ b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/mechanism_driver.py @@ -2736,7 +2736,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver, def _opflex_bind_port(self, context, segment, agent): network_type = segment[api.NETWORK_TYPE] - if self._is_opflex_type(network_type): + if (self._is_opflex_type(network_type) or + network_type == n_constants.TYPE_VLAN): opflex_mappings = agent['configurations'].get('opflex_networks') LOG.debug("Checking segment: %(segment)s " "for physical network: %(mappings)s ", diff --git a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/rpc.py b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/rpc.py index 229172fb5..a8a581e09 100644 --- a/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/rpc.py +++ b/gbpservice/neutron/plugins/ml2plus/drivers/apic_aim/rpc.py @@ -72,6 +72,7 @@ EndpointPortInfo = namedtuple( 'nested_domain_infra_vlan', 'nested_domain_service_vlan', 'nested_domain_node_network_vlan', + 'svi', 'epg_name', 'epg_app_profile_name', 'epg_tenant_name', @@ -96,7 +97,8 @@ EndpointBindingInfo = namedtuple( ['host', 'level', 'network_type', - 'physical_network']) + 'physical_network', + 'segmentation_id']) EndpointSecurityGroupInfo = namedtuple( 'EndpointSecurityGroupInfo', @@ -485,6 +487,7 @@ class ApicRpcHandlerMixin(object): extension_db.NetworkExtensionDb.nested_domain_service_vlan, extension_db.NetworkExtensionDb. nested_domain_node_network_vlan, + extension_db.NetworkExtensionDb.svi, db.NetworkMapping.epg_name, db.NetworkMapping.epg_app_profile_name, db.NetworkMapping.epg_tenant_name, @@ -575,6 +578,7 @@ class ApicRpcHandlerMixin(object): ml2_models.PortBindingLevel.level, segment_models.NetworkSegment.network_type, segment_models.NetworkSegment.physical_network, + segment_models.NetworkSegment.segmentation_id, )) query += lambda q: q.join( segment_models.NetworkSegment, @@ -862,6 +866,7 @@ class ApicRpcHandlerMixin(object): details['network_id'] = port_info.network_id details['network_type'] = binding_info[-1].network_type details['physical_network'] = binding_info[-1].physical_network + details['segmentation_id'] = binding_info[-1].segmentation_id details['port_id'] = port_info.port_id return details @@ -896,7 +901,11 @@ class ApicRpcHandlerMixin(object): details['dns_domain'] = port_info.net_dns_domain or '' details['enable_dhcp_optimization'] = self.enable_dhcp_opt details['enable_metadata_optimization'] = self.enable_metadata_opt - details['endpoint_group_name'] = port_info.epg_name + if port_info.svi: + details['endpoint_group_name'] = port_info.network_id + details['svi'] = True + else: + details['endpoint_group_name'] = port_info.epg_name details['floating_ip'] = self._build_fips(info) details['host'] = port_info.host details['host_snat_ips'] = self._build_host_snat_ips(info) diff --git a/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py index 796a5d6d9..b32b7d6eb 100644 --- a/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py +++ b/gbpservice/neutron/tests/unit/plugins/ml2plus/test_apic_aim.py @@ -342,7 +342,8 @@ class ApicAimTestCase(test_address_scope.AddressScopeTestCase, 'apic:nat_type', SNAT_POOL, ACTIVE_ACTIVE_AAP, CIDR, PROV, CONS, SVI, - BGP, BGP_TYPE, ASN + BGP, BGP_TYPE, ASN, + 'provider:network_type' ) self.name_mapper = apic_mapper.APICNameMapper() self.t1_aname = self.name_mapper.project(None, 't1') @@ -4723,6 +4724,28 @@ class TestPortBinding(ApicAimTestCase): self.assertEqual({'port_filter': False, 'ovs_hybrid_plug': False}, port['binding:vif_details']) + def test_bind_opflex_agent_svi(self): + self._register_agent('host1', AGENT_CONF_OPFLEX) + aim_ctx = aim_context.AimContext(self.db_session) + hlink_1 = aim_infra.HostLink( + host_name='host1', + interface_name='eth1', + path='topology/pod-1/paths-102/pathep-[eth1/8]') + self.aim_mgr.create(aim_ctx, hlink_1) + + net = self._make_network(self.fmt, 'net1', True, + arg_list=self.extension_attributes, + **{'apic:svi': 'True', 'provider:network_type': u'vlan'}) + + self._make_subnet(self.fmt, net, '10.0.1.1', '10.0.1.0/24') + port = self._make_port(self.fmt, net['network']['id'])['port'] + port_id = port['id'] + port = self._bind_port_to_host(port_id, 'host1')['port'] + + self.assertEqual('ovs', port['binding:vif_type']) + self.assertEqual({'port_filter': False, 'ovs_hybrid_plug': False}, + port['binding:vif_details']) + def test_bind_opflex_agent_with_firewall_enabled(self): self.driver.enable_iptables_firewall = True self._register_agent('host1', AGENT_CONF_OPFLEX) @@ -9193,6 +9216,42 @@ class TestOpflexRpc(ApicAimTestCase): def test_endpoint_details_bound_active_active_aap(self): self._test_endpoint_details_bound(active_active_aap=True) + def test_endpoint_details_bound_svi(self): + self._register_agent('h1', AGENT_CONF_OPFLEX) + + aim_ctx = aim_context.AimContext(self.db_session) + hlink_1 = aim_infra.HostLink( + host_name='h1', + interface_name='eth1', + path='topology/pod-1/paths-102/pathep-[eth1/8]') + self.aim_mgr.create(aim_ctx, hlink_1) + + network = self._make_network(self.fmt, 'net1', True, + arg_list=self.extension_attributes, + **{'apic:svi': 'True', + 'provider:network_type': u'vlan'}) + net1 = network['network'] + gw1_ip = '10.0.1.1' + self._make_subnet(self.fmt, network, gw1_ip, cidr='10.0.1.0/24') + + # Make a VM port. + p1 = self._make_port(self.fmt, net1['id'], + device_owner='compute:')['port'] + self._bind_port_to_host(p1['id'], 'h1') + + request = { + 'device': 'tap' + p1['id'], + 'timestamp': 12345, + 'request_id': 'a_request' + } + response = self.driver.request_endpoint_details( + n_context.get_admin_context(), request=request, host='h1') + gbp_details = response['gbp_details'] + self.assertEqual(True, gbp_details.get('svi')) + neutron_details = response['neutron_details'] + self.assertEqual(net1['provider:segmentation_id'], + neutron_details.get('segmentation_id')) + def test_endpoint_details_unbound(self): host = 'host1' net = self._make_network(self.fmt, 'net1', True)