[APIC-mapping] Fix device_id of port when using VLAN network
When VLAN networks are used instead of OpFlex, additional networks and ports are created that mirror the usual networks and ports. The device_id of the VM's port is set to VM's UUID whereas the port that mirrors had its device_id set to the PT UUID. This latter value resulted in failure to lookup metadata information for the VM. This change ensures that the device_id for both the VM port and its mirror stay in sync. Closes-Bug: 1627915 Change-Id: Ibea325fbfa344acd9626d5e651297dd5e24297b6 Signed-off-by: Amit Bose <amitbose@gmail.com>
This commit is contained in:
		@@ -776,7 +776,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
            self._notify_head_chain_ports(pt['policy_target_group_id'])
 | 
					            self._notify_head_chain_ports(pt['policy_target_group_id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def process_port_added(self, context):
 | 
					    def process_port_added(self, context):
 | 
				
			||||||
        self._disable_port_on_shadow_subnet(context)
 | 
					        self._handle_shadow_port_change(context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def create_policy_action_precommit(self, context):
 | 
					    def create_policy_action_precommit(self, context):
 | 
				
			||||||
        pass
 | 
					        pass
 | 
				
			||||||
@@ -1567,7 +1567,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
            self._sync_shadow_subnets(context, l2p, subnet, None)
 | 
					            self._sync_shadow_subnets(context, l2p, subnet, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def process_port_changed(self, context):
 | 
					    def process_port_changed(self, context):
 | 
				
			||||||
        self._disable_port_on_shadow_subnet(context)
 | 
					        self._handle_shadow_port_change(context)
 | 
				
			||||||
        if (context.original_host != context.host or
 | 
					        if (context.original_host != context.host or
 | 
				
			||||||
                context.original_bottom_bound_segment !=
 | 
					                context.original_bottom_bound_segment !=
 | 
				
			||||||
                context.bottom_bound_segment):
 | 
					                context.bottom_bound_segment):
 | 
				
			||||||
@@ -2909,7 +2909,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
            if not es['subnet_id']:
 | 
					            if not es['subnet_id']:
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            router_id = sub_r_dict.get(es['subnet_id'])
 | 
					            router_id = sub_r_dict.get(es['subnet_id'])
 | 
				
			||||||
            if router_id:   # router connecting to ES's subnet exists
 | 
					            if router_id:  # router connecting to ES's subnet exists
 | 
				
			||||||
                router = self._get_router(context._plugin_context, router_id)
 | 
					                router = self._get_router(context._plugin_context, router_id)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                router_id = self._use_implicit_router(
 | 
					                router_id = self._use_implicit_router(
 | 
				
			||||||
@@ -2959,7 +2959,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
    def _attach_router_to_subnets(self, plugin_context, router_id, sn_ids):
 | 
					    def _attach_router_to_subnets(self, plugin_context, router_id, sn_ids):
 | 
				
			||||||
        rtr_sn = self._get_router_interface_subnets(plugin_context, router_id)
 | 
					        rtr_sn = self._get_router_interface_subnets(plugin_context, router_id)
 | 
				
			||||||
        for subnet_id in sn_ids:
 | 
					        for subnet_id in sn_ids:
 | 
				
			||||||
            if subnet_id in rtr_sn:     # already attached
 | 
					            if subnet_id in rtr_sn:  # already attached
 | 
				
			||||||
                continue
 | 
					                continue
 | 
				
			||||||
            self._plug_router_to_subnet(plugin_context, subnet_id, router_id)
 | 
					            self._plug_router_to_subnet(plugin_context, subnet_id, router_id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3618,15 +3618,35 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
                    grp['id'])
 | 
					                    grp['id'])
 | 
				
			||||||
                raise
 | 
					                raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _disable_port_on_shadow_subnet(self, context):
 | 
					    def _handle_shadow_port_change(self, context):
 | 
				
			||||||
        """Disable certain kinds of ports in shadow-network."""
 | 
					        """Special handling for changes to ports in shadow network.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        1. Disable certain kinds of ports like DHCP to avoid interference
 | 
				
			||||||
 | 
					        on the data path.
 | 
				
			||||||
 | 
					        2. Copy device_id from shadow port to corresponding port in
 | 
				
			||||||
 | 
					           L2P's network.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
        port = context.current
 | 
					        port = context.current
 | 
				
			||||||
        if (port['device_owner'] == n_constants.DEVICE_OWNER_DHCP and
 | 
					        ptg = self._shadow_network_id_to_ptg(context, port['network_id'])
 | 
				
			||||||
                port['admin_state_up'] is True and
 | 
					        admin_ctx = context._plugin_context.elevated()
 | 
				
			||||||
                self._shadow_network_id_to_ptg(context, port['network_id'])):
 | 
					        if ptg:
 | 
				
			||||||
            self._update_port(context._plugin_context.elevated(),
 | 
					            # Disable DHCP port
 | 
				
			||||||
                              port['id'],
 | 
					            if (port['device_owner'] == n_constants.DEVICE_OWNER_DHCP and
 | 
				
			||||||
                              {'admin_state_up': False})
 | 
					                    port['admin_state_up'] is True):
 | 
				
			||||||
 | 
					                self._update_port(admin_ctx, port['id'],
 | 
				
			||||||
 | 
					                                  {'admin_state_up': False})
 | 
				
			||||||
 | 
					            # Copy device_id
 | 
				
			||||||
 | 
					            l2p = self._get_l2_policy(admin_ctx, ptg['l2_policy_id'])
 | 
				
			||||||
 | 
					            l2p_port = self._get_ports(
 | 
				
			||||||
 | 
					                admin_ctx,
 | 
				
			||||||
 | 
					                filters={'mac_address': [port['mac_address']],
 | 
				
			||||||
 | 
					                         'network_id': [l2p['network_id']]})
 | 
				
			||||||
 | 
					            if l2p_port:
 | 
				
			||||||
 | 
					                l2p_port = l2p_port[0]
 | 
				
			||||||
 | 
					                if l2p_port['device_id'] != port['device_id']:
 | 
				
			||||||
 | 
					                    self._update_port(admin_ctx, l2p_port['id'],
 | 
				
			||||||
 | 
					                                      {'device_id': port['device_id']})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _delete_ptg_shadow_network(self, context, ptg):
 | 
					    def _delete_ptg_shadow_network(self, context, ptg):
 | 
				
			||||||
        shadow_net = self._get_ptg_shadow_network(context, ptg)
 | 
					        shadow_net = self._get_ptg_shadow_network(context, ptg)
 | 
				
			||||||
@@ -3672,12 +3692,13 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
        # a port originally, then treat that port as the "shadow" port,
 | 
					        # a port originally, then treat that port as the "shadow" port,
 | 
				
			||||||
        # else create the shadow port in the shadow network. In both cases,
 | 
					        # else create the shadow port in the shadow network. In both cases,
 | 
				
			||||||
        # associate the shadow port to the PT.
 | 
					        # associate the shadow port to the PT.
 | 
				
			||||||
        context.current['port_attributes'] = {'device_owner': 'apic',
 | 
					        context.current['port_attributes'] = {'device_owner':
 | 
				
			||||||
                                              'device_id': pt['id']}
 | 
					                                              'apic:%s' % pt['id']}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if pt_port_id:
 | 
					        if pt_port_id:
 | 
				
			||||||
            shadow_port = self._get_port(context._plugin_context, pt_port_id)
 | 
					            shadow_port = self._get_port(context._plugin_context, pt_port_id)
 | 
				
			||||||
            context.current['port_attributes'].update({
 | 
					            context.current['port_attributes'].update({
 | 
				
			||||||
 | 
					                'device_id': shadow_port['device_id'],
 | 
				
			||||||
                'fixed_ips': self._strip_subnet(shadow_port['fixed_ips']),
 | 
					                'fixed_ips': self._strip_subnet(shadow_port['fixed_ips']),
 | 
				
			||||||
                'mac_address': shadow_port['mac_address']})
 | 
					                'mac_address': shadow_port['mac_address']})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -3721,8 +3742,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
            l2p = self._get_l2_policy(context._plugin_context,
 | 
					            l2p = self._get_l2_policy(context._plugin_context,
 | 
				
			||||||
                                      ptg['l2_policy_id'])
 | 
					                                      ptg['l2_policy_id'])
 | 
				
			||||||
            implicit_ports = self._get_ports(context._plugin_context,
 | 
					            implicit_ports = self._get_ports(context._plugin_context,
 | 
				
			||||||
                filters={'device_owner': ['apic'],
 | 
					                filters={'device_owner': ['apic:%s' % pt['id']],
 | 
				
			||||||
                         'device_id': [pt['id']],
 | 
					 | 
				
			||||||
                         'network_id': [l2p['network_id']]})
 | 
					                         'network_id': [l2p['network_id']]})
 | 
				
			||||||
            for p in implicit_ports:
 | 
					            for p in implicit_ports:
 | 
				
			||||||
                self._cleanup_port(context._plugin_context, p['id'])
 | 
					                self._cleanup_port(context._plugin_context, p['id'])
 | 
				
			||||||
@@ -3813,8 +3833,8 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
    def _tenant_uses_specific_nat_epg(self, context, es, tenant_obj):
 | 
					    def _tenant_uses_specific_nat_epg(self, context, es, tenant_obj):
 | 
				
			||||||
        session = context._plugin_context.session
 | 
					        session = context._plugin_context.session
 | 
				
			||||||
        cnt = session.query(TenantSpecificNatEpg).filter_by(
 | 
					        cnt = session.query(TenantSpecificNatEpg).filter_by(
 | 
				
			||||||
            external_segment_id = es['id']).filter_by(
 | 
					            external_segment_id=es['id']).filter_by(
 | 
				
			||||||
                tenant_id = tenant_obj['tenant_id']).count()
 | 
					                tenant_id=tenant_obj['tenant_id']).count()
 | 
				
			||||||
        return bool(cnt)
 | 
					        return bool(cnt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _create_tenant_specific_nat_epg(self, context, es, l3_policy,
 | 
					    def _create_tenant_specific_nat_epg(self, context, es, l3_policy,
 | 
				
			||||||
@@ -3881,8 +3901,8 @@ class ApicMappingDriver(api.ResourceMappingDriver,
 | 
				
			|||||||
            session = context._plugin_context.session
 | 
					            session = context._plugin_context.session
 | 
				
			||||||
            with session.begin(subtransactions=True):
 | 
					            with session.begin(subtransactions=True):
 | 
				
			||||||
                db_obj = session.query(TenantSpecificNatEpg).filter_by(
 | 
					                db_obj = session.query(TenantSpecificNatEpg).filter_by(
 | 
				
			||||||
                    external_segment_id = es['id']).filter_by(
 | 
					                    external_segment_id=es['id']).filter_by(
 | 
				
			||||||
                        tenant_id = l3_policy['tenant_id']).first()
 | 
					                        tenant_id=l3_policy['tenant_id']).first()
 | 
				
			||||||
                if db_obj:
 | 
					                if db_obj:
 | 
				
			||||||
                    session.delete(db_obj)
 | 
					                    session.delete(db_obj)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -564,7 +564,7 @@ class TestPolicyTarget(ApicMappingTestCase):
 | 
				
			|||||||
        self._bind_port_to_host(pt2['port_id'], 'h1')
 | 
					        self._bind_port_to_host(pt2['port_id'], 'h1')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        details = self.driver.get_snat_ip_for_vrf(context.get_admin_context(),
 | 
					        details = self.driver.get_snat_ip_for_vrf(context.get_admin_context(),
 | 
				
			||||||
            TEST_VRF2, network, es_name = es['name'])
 | 
					            TEST_VRF2, network, es_name=es['name'])
 | 
				
			||||||
        self.assertEqual(es['name'],
 | 
					        self.assertEqual(es['name'],
 | 
				
			||||||
            details['external_segment_name'])
 | 
					            details['external_segment_name'])
 | 
				
			||||||
        self.assertEqual("192.168.200.1",
 | 
					        self.assertEqual("192.168.200.1",
 | 
				
			||||||
@@ -1229,6 +1229,15 @@ class TestPolicyTargetVlanNetwork(ApicMappingVlanTestCase,
 | 
				
			|||||||
                         len(ports[0]['fixed_ips']))
 | 
					                         len(ports[0]['fixed_ips']))
 | 
				
			||||||
        self.assertEqual(shadow_port['fixed_ips'][0]['ip_address'],
 | 
					        self.assertEqual(shadow_port['fixed_ips'][0]['ip_address'],
 | 
				
			||||||
                         ports[0]['fixed_ips'][0]['ip_address'])
 | 
					                         ports[0]['fixed_ips'][0]['ip_address'])
 | 
				
			||||||
 | 
					        self.assertEqual('apic:%s' % pt1['id'], ports[0]['device_owner'])
 | 
				
			||||||
 | 
					        self.assertEqual('', ports[0]['device_id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # update device_id of shadow port
 | 
				
			||||||
 | 
					        shadow_port = self._update('ports', shadow_port['id'],
 | 
				
			||||||
 | 
					                                   {'port': {'device_id': 'comp1'}})['port']
 | 
				
			||||||
 | 
					        l2p_port = self._get_object(
 | 
				
			||||||
 | 
					            'ports', ports[0]['id'], self.api)['port']
 | 
				
			||||||
 | 
					        self.assertEqual('comp1', l2p_port['device_id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.delete_policy_target(pt1['id'])
 | 
					        self.delete_policy_target(pt1['id'])
 | 
				
			||||||
        self._get_object('ports', pt1['port_id'], self.api,
 | 
					        self._get_object('ports', pt1['port_id'], self.api,
 | 
				
			||||||
@@ -1243,7 +1252,7 @@ class TestPolicyTargetVlanNetwork(ApicMappingVlanTestCase,
 | 
				
			|||||||
                                          self.api)
 | 
					                                          self.api)
 | 
				
			||||||
        subnet = self._get_object('subnets', ptg1['subnets'][0], self.api)
 | 
					        subnet = self._get_object('subnets', ptg1['subnets'][0], self.api)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        with self.port(subnet=shadow_subnet1) as p:
 | 
					        with self.port(subnet=shadow_subnet1, device_id='vm1') as p:
 | 
				
			||||||
            port1 = p['port']
 | 
					            port1 = p['port']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pt1 = self.create_policy_target(policy_target_group_id=ptg1['id'],
 | 
					        pt1 = self.create_policy_target(policy_target_group_id=ptg1['id'],
 | 
				
			||||||
@@ -1258,6 +1267,15 @@ class TestPolicyTargetVlanNetwork(ApicMappingVlanTestCase,
 | 
				
			|||||||
                         len(ports[0]['fixed_ips']))
 | 
					                         len(ports[0]['fixed_ips']))
 | 
				
			||||||
        self.assertEqual(port1['fixed_ips'][0]['ip_address'],
 | 
					        self.assertEqual(port1['fixed_ips'][0]['ip_address'],
 | 
				
			||||||
                         ports[0]['fixed_ips'][0]['ip_address'])
 | 
					                         ports[0]['fixed_ips'][0]['ip_address'])
 | 
				
			||||||
 | 
					        self.assertEqual('apic:%s' % pt1['id'], ports[0]['device_owner'])
 | 
				
			||||||
 | 
					        self.assertEqual('vm1', ports[0]['device_id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # update device_id of explicit port
 | 
				
			||||||
 | 
					        port1 = self._update('ports', port1['id'],
 | 
				
			||||||
 | 
					                             {'port': {'device_id': 'comp1'}})['port']
 | 
				
			||||||
 | 
					        l2p_port = self._get_object(
 | 
				
			||||||
 | 
					            'ports', ports[0]['id'], self.api)['port']
 | 
				
			||||||
 | 
					        self.assertEqual('comp1', l2p_port['device_id'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.delete_policy_target(pt1['id'])
 | 
					        self.delete_policy_target(pt1['id'])
 | 
				
			||||||
        self._get_object('ports', pt1['port_id'], self.api,
 | 
					        self._get_object('ports', pt1['port_id'], self.api,
 | 
				
			||||||
@@ -1265,6 +1283,25 @@ class TestPolicyTargetVlanNetwork(ApicMappingVlanTestCase,
 | 
				
			|||||||
        self._get_object('ports', ports[0]['id'], self.api,
 | 
					        self._get_object('ports', ports[0]['id'], self.api,
 | 
				
			||||||
                         expected_res_status=404)
 | 
					                         expected_res_status=404)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_dhcp_disable_in_shadow_network(self):
 | 
				
			||||||
 | 
					        ptg1 = self.create_policy_target_group(
 | 
				
			||||||
 | 
					            name="ptg1")['policy_target_group']
 | 
				
			||||||
 | 
					        self.create_policy_target(
 | 
				
			||||||
 | 
					            policy_target_group_id=ptg1['id'])['policy_target']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        subnet = self._get_object('subnets',
 | 
				
			||||||
 | 
					                                  self._get_ptg_shadow_subnet(ptg1),
 | 
				
			||||||
 | 
					                                  self.api)
 | 
				
			||||||
 | 
					        with self.port(subnet=subnet, device_owner='network:dhcp') as p:
 | 
				
			||||||
 | 
					            port1 = p['port']
 | 
				
			||||||
 | 
					            port1 = self._get_object('ports', port1['id'], self.api)['port']
 | 
				
			||||||
 | 
					            self.assertFalse(port1['admin_state_up'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            port1 = self._update('ports', port1['id'],
 | 
				
			||||||
 | 
					                                 {'port': {'admin_state_up': True}})['port']
 | 
				
			||||||
 | 
					            port1 = self._get_object('ports', port1['id'], self.api)['port']
 | 
				
			||||||
 | 
					            self.assertFalse(port1['admin_state_up'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def test_explicit_port_wrong_network(self):
 | 
					    def test_explicit_port_wrong_network(self):
 | 
				
			||||||
        ptg1 = self.create_policy_target_group()['policy_target_group']
 | 
					        ptg1 = self.create_policy_target_group()['policy_target_group']
 | 
				
			||||||
        subnet = self._get_object('subnets', ptg1['subnets'][0], self.api)
 | 
					        subnet = self._get_object('subnets', ptg1['subnets'][0], self.api)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user