Bug 7606: Fix for missed tunnel flows, after VM live migration 96/51796/6
authorVinothB <vinothb@hcl.com>
Mon, 13 Feb 2017 04:22:04 +0000 (09:52 +0530)
committerSam Hague <shague@redhat.com>
Fri, 17 Feb 2017 01:30:28 +0000 (01:30 +0000)
   * Skip deleting the flows in table 110 and table 20 when processing an
    interface deletion event from OVSDB in the case that the interface
    deletion is due to VM migration.
   * Remove the Port Name from flowName so that, the same entry gets
    updated during the update notification processing while live migration.

Change-Id: I2b917e50e07af4ed840d811a9c3f0a131281bd12
Signed-off-by: VinothB <vinothb@hcl.com>
15 files changed:
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/OF13Provider.java
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/EgressAclService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/IngressAclService.java
openstack/net-virt-providers/src/main/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/services/L2ForwardingService.java
openstack/net-virt-providers/src/test/java/org/opendaylight/netvirt/openstack/netvirt/providers/openflow13/OF13ProviderTest.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/PortSecurityHandler.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundHandler.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/NetworkingProvider.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/api/SecurityGroupCacheManger.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/DistributedArpService.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/NeutronL3Adapter.java
openstack/net-virt/src/main/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityGroupCacheManagerImpl.java
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/SouthboundHandlerTest.java
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/DistributedArpServiceTest.java
openstack/net-virt/src/test/java/org/opendaylight/netvirt/openstack/netvirt/impl/SecurityGroupCacheManagerImplTest.java

index e41159453c2d3842efde3b8bb590126d1ef4d617..a4307c9df2d7e10254b5e28530707b28277acbc5 100644 (file)
@@ -286,7 +286,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
         handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
     }
 
-    private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
+    private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort, boolean isMigratedPort) {
         /*
          * Table(0) Rule #3
          * ----------------
@@ -313,7 +313,9 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
          * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
          */
 
-        handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
+        if(!isMigratedPort) {
+            handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
+        }
 
         /*
          * Table(2) Rule #2
@@ -767,7 +769,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
             }
             if ((isTunnel(networkType) || isVlan(networkType))) {
-                programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, true);
+                programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, false, true);
             }
             if (isTunnel(networkType)) {
                 LOG.debug("Program local bridge rules for interface {}, "
@@ -781,7 +783,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
     }
 
     private void removeLocalRules(String networkType, String segmentationId, Node node,
-                                   OvsdbTerminationPointAugmentation intf) {
+                                   OvsdbTerminationPointAugmentation intf, boolean isMigratedPort) {
         LOG.debug("removeLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
                 node.getNodeId(), intf.getName(), networkType, segmentationId);
         try {
@@ -809,10 +811,10 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
             } else if (isTunnel(networkType)) {
                 LOG.debug("Remove local bridge rules for interface {}", intf.getName());
-                removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
+                removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort, isMigratedPort);
             }
             if (isTunnel(networkType) || isVlan(networkType)) {
-                programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, false);
+                programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, isMigratedPort, false);
             }
         } catch (Exception e) {
             LOG.error("Exception in removing Local Rules for {} on {}", intf, node, e);
@@ -873,7 +875,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
 
     private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
                                     OvsdbTerminationPointAugmentation intf,
-                                    boolean local, boolean isLastInstanceOnNode) {
+                                    boolean local, boolean isLastInstanceOnNode, boolean isMigratedPort) {
         LOG.debug("removeTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
                         + "segmentationId: {}, dstAddr: {}, isLastinstanceOnNode: {}",
                 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst, isLastInstanceOnNode);
@@ -908,7 +910,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                     LOG.debug("Identified Tunnel port {} -> OF ({}) on {}",
                             tunIntf.getName(), tunnelOFPort, node);
 
-                    if (!local) {
+                    if (!local && !isMigratedPort) {
                         removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
                                 tunnelOFPort, localPort);
                     }
@@ -1000,7 +1002,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
     }
 
     private void programLocalSecurityGroupRules(String attachedMac, Node node, OvsdbTerminationPointAugmentation intf,
-                                                Long dpid,long localPort, String segmentationId,
+                                                Long dpid,long localPort, String segmentationId, boolean isMigratedPort,
                                                 boolean write) {
 
         LOG.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
@@ -1039,7 +1041,9 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                 if (write) {
                     securityGroupCacheManger.portAdded(securityGroupInPort.getSecurityGroupUUID(), neutronPortId);
                 } else {
-                    securityGroupCacheManger.portRemoved(securityGroupInPort.getSecurityGroupUUID(), neutronPortId);
+                    if(!isMigratedPort) {
+                        securityGroupCacheManger.portRemoved(securityGroupInPort.getSecurityGroupUUID(), neutronPortId);
+                    }
                 }
             }
         } else {
@@ -1228,7 +1232,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
 
     @Override
     public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
-                                         OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
+                                         OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode, boolean isMigratedPort) {
         Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
                 nodeCacheManager.getOvsdbNodes();
         nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
@@ -1254,7 +1258,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
         } else {
             // delete all other interfaces
             removeLocalRules(network.getProviderNetworkType(), segmentationId,
-                    srcNode, intf);
+                    srcNode, intf, isMigratedPort);
 
             if (isVlan(network.getProviderNetworkType())) {
                 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
@@ -1268,7 +1272,7 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                         LOG.info("Remove tunnel rules for interface "
                                 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
                         removeTunnelRules(tunnelType, segmentationId,
-                                dst, srcNode, intf, true, isLastInstanceOnNode);
+                                dst, srcNode, intf, true, isLastInstanceOnNode, isMigratedPort);
                         Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
                         //While removing last instance , check whether the network present in src node
                         //If network is not present in src node AND REMOTE MAC LEARNING IS not enabled,
@@ -1279,12 +1283,12 @@ public class OF13Provider implements ConfigInterface, NetworkingProvider {
                             //doesn't exist in a node, TunnelRules leaves it.
                             if (!isSrcinNw && !configurationService.isRemoteMacLearnEnabled()) {
                                 removeTunnelRules(tunnelType, segmentationId,
-                                    src, dstBridgeNode, intf, true, isLastInstanceOnNode);
+                                    src, dstBridgeNode, intf, true, isLastInstanceOnNode, isMigratedPort);
                             }
                             LOG.info("Remove tunnel rules for interface "
                                     + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
                             removeTunnelRules(tunnelType, segmentationId, src,
-                                    dstBridgeNode, intf, false, isLastInstanceOnNode);
+                                    dstBridgeNode, intf, false, isLastInstanceOnNode, isMigratedPort);
                         }
                     } else {
                         LOG.warn("Tunnel end-point configuration missing. Please configure it in "
index 34775d96f6f036529f001752c1f4f586ecb990a1..01f20670d5cf9a9bc7a450a120be54df5257c00a 100644 (file)
@@ -130,7 +130,7 @@ public class EgressAclService extends AbstractServiceInstance implements EgressA
                         securityGroupCacheManger.addToCache(remoteSgUuid, portUuid, nodeId);
                     } else {
                         securityGroupCacheManger.removeFromCache(remoteSgUuid,
-                                                                 portUuid);
+                                                                 portUuid, nodeId);
                     }
                 } else {
                     programPortSecurityRule(dpid, segmentationId, attachedMac, portSecurityRule, securityGroup, null, write);
index 6dce746d1e462c111f87ca3c9678d773a9620fd1..cc38b9b1ebe4525e6495af54d407c9e8012c43b7 100644 (file)
@@ -123,7 +123,7 @@ public class IngressAclService extends AbstractServiceInstance implements Ingres
                     if (write) {
                         securityGroupCacheManger.addToCache(remoteSgUuid, portUuid, nodeId);
                     } else {
-                        securityGroupCacheManger.removeFromCache(remoteSgUuid, portUuid);
+                        securityGroupCacheManger.removeFromCache(remoteSgUuid, portUuid, nodeId);
                     }
                 } else {
                     programPortSecurityRule(dpid, segmentationId, attachedMac, portSecurityRule, securityGroup, null, write);
index aea2d519e59323700c808268ab720b839246f35e..5e93b089a61ae87c821fe0e01f8e3b73ce3a52de 100644 (file)
@@ -82,7 +82,7 @@ public class L2ForwardingService extends AbstractServiceInstance implements Conf
         flowBuilder.setMatch(matchBuilder.build());
 
         // Add Flow Attributes
-        String flowName = "UcastOut_" + segmentationId + "_" + localPort + "_" + attachedMac;
+        String flowName = "UcastOut_" + segmentationId + "_" + attachedMac;
         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
 
         if (write) {
@@ -462,7 +462,7 @@ public class L2ForwardingService extends AbstractServiceInstance implements Conf
         flowBuilder.setMatch(matchBuilder.build());
 
         // Add Flow Attributes
-        String flowName = "TunnelOut_" + segmentationId + "_" + OFPortOut + "_" + attachedMac;
+        String flowName = "UcastOut_" + segmentationId + "_" + attachedMac;
         FlowUtils.initFlowBuilder(flowBuilder, flowName, getTable());
 
         if (write) {
index 305ff21b7fea0216b8e1be99e94ca9ddb28da0a9..05adbd298cfdbabe29f85c40062cf64a0c07cdbe 100644 (file)
@@ -230,7 +230,7 @@ public class OF13ProviderTest {
         MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "handleTunnelUnknownUcastFloodOut", Long.class, Short.class, Short.class, String.class, Long.class, boolean.class));
 
 
-        Whitebox.invokeMethod(of13Provider, "removeLocalBridgeRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT);
+        Whitebox.invokeMethod(of13Provider, "removeLocalBridgeRules", mock(Node.class), Long.valueOf("45"), SEG_ID, MAC_ADDRESS, LOCAL_PORT, false);
 
         PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleLocalInPort", anyLong(), anyShort(), anyShort(), anyString(), anyLong(), anyString(), anyBoolean());
         PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("handleDropSrcIface", anyLong(), anyLong(), anyBoolean());
@@ -422,22 +422,22 @@ public class OF13ProviderTest {
 
         MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "deleteTunnelPort", Node.class, String.class, InetAddress.class, InetAddress.class));
 
-        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false));
+        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false, false));
         PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("deleteTunnelPort", any(Node.class), anyString(), any(InetAddress.class), any(InetAddress.class));
 
         when(southbound.isTunnel(any(OvsdbTerminationPointAugmentation.class))).thenReturn(false);
         MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "deletePhysicalPort", Node.class, String.class));
 
-        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false));
+        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false, false));
         PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("deletePhysicalPort", any(Node.class), anyString());
 
         intfs.clear();
-        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "removeLocalRules", String.class, String.class, Node.class, OvsdbTerminationPointAugmentation.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "removeLocalRules", String.class, String.class, Node.class, OvsdbTerminationPointAugmentation.class, boolean.class));
         MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "removeVlanRules", NeutronNetwork.class, Node.class, OvsdbTerminationPointAugmentation.class, boolean.class));
         when(neutronNetwork.getProviderNetworkType()).thenReturn(NetworkHandler.NETWORK_TYPE_VLAN);
 
-        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false));
-        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("removeLocalRules",  anyString(), anyString(), any(Node.class), any(OvsdbTerminationPointAugmentation.class));
+        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, mock(Node.class), intf, false, false));
+        PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("removeLocalRules",  anyString(), anyString(), any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(boolean.class));
         PowerMockito.verifyPrivate(of13Provider, times(1)).invoke("removeVlanRules",  any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class), anyBoolean());
 
         TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
@@ -446,10 +446,10 @@ public class OF13ProviderTest {
 
         when(neutronNetwork.getProviderNetworkType()).thenReturn(NetworkHandler.NETWORK_TYPE_GRE);
         when(southbound.getBridgeNode(any(Node.class), anyString())).thenReturn(node);
-        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "removeTunnelRules", String.class, String.class, InetAddress.class, Node.class, OvsdbTerminationPointAugmentation.class, boolean.class, boolean.class));
+        MemberModifier.suppress(MemberMatcher.method(OF13Provider.class, "removeTunnelRules", String.class, String.class, InetAddress.class, Node.class, OvsdbTerminationPointAugmentation.class, boolean.class, boolean.class, boolean.class));
 
-        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, node, intf, false));
-        PowerMockito.verifyPrivate(of13Provider, times(3)).invoke("removeTunnelRules", anyString(), anyString(), any(InetAddress.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(boolean.class), any(boolean.class));
+        assertTrue("Error, did not delete the interface correclty", of13Provider.handleInterfaceDelete(TYPE,  neutronNetwork, node, intf, false, false));
+        PowerMockito.verifyPrivate(of13Provider, times(3)).invoke("removeTunnelRules", anyString(), anyString(), any(InetAddress.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(boolean.class), any(boolean.class), any(boolean.class));
     }
 
     // Problem with methods signatures: initializeFlowRules(Node) has the same signature than initializeFlowRules(Node, String)
index 0224e7140a9bf4f3c70b0a86b6ab2adbcbecb186..15826566b149b6fc4f0cf56d02b1b7214b6a5d8a 100644 (file)
@@ -195,7 +195,7 @@ public class PortSecurityHandler extends AbstractHandler
                 if (write) {
                     securityGroupCacheManger.addToCache(securityRule.getSecurityRemoteGroupID(), port.getPortUUID(), nodeId);
                 } else {
-                    securityGroupCacheManger.removeFromCache(securityRule.getSecurityRemoteGroupID(), port.getPortUUID());
+                    securityGroupCacheManger.removeFromCache(securityRule.getSecurityRemoteGroupID(), port.getPortUUID(), nodeId);
                 }
             } else {
                 for (Neutron_IPs vmIp : vmIpList) {
index 2b33230f514dbf2d184673c47e3d7e564dcbce1d..971378839056bab44261e0197a9b6f9aab2e0e10 100644 (file)
@@ -13,7 +13,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
-
+import org.apache.commons.lang3.tuple.Pair;
 import org.opendaylight.netvirt.openstack.netvirt.api.Action;
 import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
 import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
@@ -33,6 +33,7 @@ import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetwor
 import org.opendaylight.netvirt.openstack.netvirt.impl.DistributedArpService;
 import org.opendaylight.netvirt.openstack.netvirt.impl.NeutronL3Adapter;
 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.InterfaceTypeVxlan;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
@@ -114,25 +115,57 @@ public class SouthboundHandler extends AbstractHandler
             LOG.debug("No tenant network found on node : {} for interface: {}", node, tp);
         }
         if (action.equals(Action.UPDATE)) {
-            distributedArpService.processInterfaceEvent(node, tp, network, action);
+            distributedArpService.processInterfaceEvent(node, tp, network, false, action);
         }
         neutronL3Adapter.handleInterfaceEvent(node, tp, network, Action.UPDATE);
     }
+    /**
+     * Get dpid from node.
+     *
+     * @param node the {@link Node Node} of interest in the notification
+     * @return dpid value
+     */
+    private Long getDpidForIntegrationBridge(Node node) {
+        // Check if node is integration bridge; and only then return its dpid
+        if (southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null) {
+            return southbound.getDataPathId(node);
+        }
+        return null;
+    }
+
+    /**
+     * Returns true, if the port is migrated else false.
+     *
+     * @param node the node associated with Neutron Port.
+     * @param neutronPort the port details.
+     * @return boolean true, if the port is migrated else false.
+     */
+    private boolean isMigratedPort(Node node, NeutronPort neutronPort) {
+        boolean isMigratedPort = false;
+        final Long dpId = getDpidForIntegrationBridge(node);
+        final Pair<Long, Uuid> nodeDpIdPair = neutronL3Adapter.getDpIdOfNeutronPort(neutronPort.getPortUUID());
+        Long dpIdNeutronPort = (nodeDpIdPair == null ? null : nodeDpIdPair.getLeft());
+        if(dpIdNeutronPort != null && !dpIdNeutronPort.equals(dpId)) {
+            isMigratedPort = true;
+        }
+        return isMigratedPort;
+    }
 
     private void handleInterfaceDelete (Node node, OvsdbTerminationPointAugmentation intf,
                                         boolean isLastInstanceOnNode, NeutronNetwork network) {
         LOG.debug("handleInterfaceDelete: node: <{}>, isLastInstanceOnNode: {}, interface: <{}>",
                 node, isLastInstanceOnNode, intf);
 
-        distributedArpService.processInterfaceEvent(node, intf, network, Action.DELETE);
-        neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
         final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
+        boolean isMigratedPort = isMigratedPort(node, neutronPort);
+        distributedArpService.processInterfaceEvent(node, intf, network, isMigratedPort, Action.DELETE);
+        neutronL3Adapter.handleInterfaceEvent(node, intf, network, Action.DELETE);
         programVLANNetworkFlowProvider(node, intf, network, neutronPort, false);
         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
         if (isInterfaceOfInterest(intf, phyIfName)) {
             // delete tunnel or physical interfaces
             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
-                    network, node, intf, isLastInstanceOnNode);
+                    network, node, intf, isLastInstanceOnNode, isMigratedPort);
         } else if (network != null) {
             // vlan doesn't need a tunnel endpoint
             if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN) &&
@@ -141,8 +174,9 @@ public class SouthboundHandler extends AbstractHandler
                 return;
             }
             networkingProviderManager.getProvider(node).handleInterfaceDelete(network.getProviderNetworkType(),
-                    network, node, intf, isLastInstanceOnNode);
+                    network, node, intf, isLastInstanceOnNode, isMigratedPort);
         }
+
     }
 
     @Override
index 791925a4f722c60d09029468b3e2a060864f8f59..babf8bd0d2e7504ee4546d4aedff4fc7afb79200 100644 (file)
@@ -48,10 +48,11 @@ public interface NetworkingProvider {
      * @param source Source node where interface was attached
      * @param intf Termination point associated to the deleted interface
      * @param isLastInstanceOnNode is last interface attached to the node ?
+     * @param isMigratedPort is the Neutron Port associated with the removed interface is being migrated to a new node?
      * @return true if interface delete handled successfully
      */
     boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node source,
-                                  OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode);
+                                  OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode, boolean isMigratedPort);
 
     /**
      * Initialize the Flow rules given the OVSDB node.
index d14a63e20d13f05cb7c52145bfffd379e622734c..4122dba7a3b6d823c07e68003625d3ac18acb425 100644 (file)
@@ -45,6 +45,7 @@ public interface SecurityGroupCacheManger {
      * from the cache maintained.
      * @param remoteSgUuid the remote security group uuid.
      * @param portUuid portUUID the uuid of the port.
+     * @param nodeId the NodeId of the node.
      */
-    void removeFromCache(String remoteSgUuid, String portUuid);
+    void removeFromCache(String remoteSgUuid, String portUuid, NodeId nodeId);
 }
index 22439e6cae5bdd65e0df3b4754bd33e3703ec31b..1ca5d7e34582be06cfbf199a90514b5703069070 100644 (file)
@@ -85,11 +85,13 @@ public class DistributedArpService implements ConfigInterface {
      * Process the port event to write Arp rules for neutron ports.
      *
      * @param action the {@link Action} action to be handled.
+     * @param isMigratedPort true, if the port is migrated else false.
+     * @param bridgeNode the node for the port.
      * @param neutronPort An instance of NeutronPort object.
      */
-    public void handlePortEvent(NeutronPort neutronPort, Action action) {
+    public void handlePortEvent(NeutronPort neutronPort, Node bridgeNode, boolean isMigratedPort, Action action) {
         LOG.debug("neutronPort Event {} action event {} ", neutronPort, action);
-        this.handleNeutronPortForArp(neutronPort, action);
+        this.handleNeutronPortForArp(neutronPort, bridgeNode, isMigratedPort, action);
     }
 
      /**
@@ -147,9 +149,11 @@ public class DistributedArpService implements ConfigInterface {
      * Write Arp rules based on event for neutron port.
      *
      * @param action the {@link Action} action to be handled.
+     * @param isMigratedPort true, if the port is migrated else false.
+     * @param bridgeNode the node for the port.
      * @param neutronPort An instance of NeutronPort object.
      */
-    private void handleNeutronPortForArp(NeutronPort neutronPort, Action action) {
+    private void handleNeutronPortForArp(NeutronPort neutronPort, Node bridgeNode, boolean isMigratedPort, Action action) {
         if (!flgDistributedARPEnabled) {
             return;
         }
@@ -173,13 +177,19 @@ public class DistributedArpService implements ConfigInterface {
         if (nodes.isEmpty()) {
             LOG.trace("updateL3ForNeutronPort has no nodes to work with");
         }
+        String owner = neutronPort.getDeviceOwner();
+        boolean isDhcpPort = owner != null && owner.equals(DHCP_DEVICE_OWNER);
         for (Node node : nodes) {
-            handleArpRule(node, neutronPort, providerSegmentationId, actionToPerform);
+            if(actionToPerform == Action.DELETE && !isDhcpPort &&
+                    (isMigratedPort && !bridgeNode.getNodeId().equals(node.getNodeId()))) {
+                continue;
+            }
+            handleArpRule(node, neutronPort, providerSegmentationId, isMigratedPort, actionToPerform);
         }
     }
 
     private void handleArpRule(Node node, NeutronPort neutronPort,
-                String providerSegmentationId, Action actionToPerform) {
+                String providerSegmentationId, boolean isMigratedPort, Action actionToPerform) {
         String owner = neutronPort.getDeviceOwner();
         boolean isRouterInterface = owner != null && owner.equals(ROUTER_INTERFACE_DEVICE_OWNER);
         boolean isDhcpPort = owner != null && owner.equals(DHCP_DEVICE_OWNER);
@@ -230,16 +240,18 @@ public class DistributedArpService implements ConfigInterface {
                     }
                 }
             } else {
-                for (Neutron_IPs neutronIPAddr : neutronPort.getFixedIPs()) {
-                    final String ipAddress = neutronIPAddr.getIpAddress();
-                    try {
-                        executor.submit(() ->
-                                programStaticRuleStage1(dpid, providerSegmentationId, macAddress,
-                                        ipAddress, actionForNode));
-                    } catch (RejectedExecutionException ex) {
-                        LOG.error("handleArpRule : unable to accept execution.", ex);
-                        programStaticRuleStage1(dpid, providerSegmentationId, macAddress,
-                                ipAddress, actionForNode);
+                if(!isMigratedPort) {
+                    for (Neutron_IPs neutronIPAddr : neutronPort.getFixedIPs()) {
+                        final String ipAddress = neutronIPAddr.getIpAddress();
+                        try {
+                            executor.submit(() ->
+                            programStaticRuleStage1(dpid, providerSegmentationId, macAddress,
+                                    ipAddress, actionForNode));
+                        } catch (RejectedExecutionException ex) {
+                            LOG.error("handleArpRule : unable to accept execution.", ex);
+                            programStaticRuleStage1(dpid, providerSegmentationId, macAddress,
+                                    ipAddress, actionForNode);
+                        }
                     }
                 }
             }
@@ -315,15 +327,16 @@ public class DistributedArpService implements ConfigInterface {
      * .OvsdbTerminationPointAugmentation} instance of OvsdbTerminationPointAugmentation object.
      * @param neutronNetwork An {@link NeutronNetwork} instance of NeutronNetwork
      * object.
+     * @param isMigratedPort true, if the port is migrated else false.
      * @param action the {@link Action} action to be handled.
      */
     public void processInterfaceEvent(final Node bridgeNode, final OvsdbTerminationPointAugmentation intf,
-                                     final NeutronNetwork neutronNetwork, Action action) {
+                                     final NeutronNetwork neutronNetwork, boolean isMigratedPort, Action action) {
         LOG.debug("southbound interface {} node:{} interface:{}, neutronNetwork:{}",
                      action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork);
         final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
         if (neutronPort != null) {
-            this.handlePortEvent(neutronPort, action);
+            this.handlePortEvent(neutronPort, bridgeNode, isMigratedPort, action);
         }
     }
 
index e39ae8bd667adb7e974f77759109fd99ccbe8293..88565f1e0bc3e79692fd0fa11baf15ac209a870e 100644 (file)
@@ -165,7 +165,6 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
             this.networkIdToRouterMacCache = new HashMap<>();
             this.networkIdToRouterIpListCache = new HashMap<>();
             this.subnetIdToRouterInterfaceCache = new HashMap<>();
-            this.neutronPortToDpIdCache = new HashMap<>();
             this.floatIpDataMapCache = new HashMap<>();
 
             this.externalRouterMac = configurationService.getDefaultGatewayMacAddress(null);
@@ -177,6 +176,7 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
         } else {
             LOG.debug("OVSDB L3 forwarding is disabled");
         }
+        this.neutronPortToDpIdCache = new HashMap<>();
         this.portCleanupCache = new ConcurrentHashMap<>();
         this.networkCleanupCache = new ConcurrentHashMap<>();
     }
@@ -281,7 +281,7 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
         LOG.debug("NetVirt L3 caches population is done");
     }
 
-    private Pair<Long, Uuid> getDpIdOfNeutronPort(String neutronTenantPortUuid) {
+    public Pair<Long, Uuid> getDpIdOfNeutronPort(String neutronTenantPortUuid) {
         if(neutronPortToDpIdCache.get(neutronTenantPortUuid) == null) {
             List<Node> bridges = this.southbound.readOvsdbTopologyBridgeNodes();
             LOG.debug("getDpIdOfNeutronPort : {} bridges present in ovsdb topology",bridges.size());
@@ -807,10 +807,6 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
             storePortInCleanupCache(neutronPort);
         }
 
-        if (!this.enabled) {
-            return;
-        }
-
         final Long dpId = getDpidForIntegrationBridge(bridgeNode);
         final Uuid interfaceUuid = intf.getInterfaceUuid();
 
@@ -824,7 +820,9 @@ public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResol
                 handleInterfaceEventAdd(neutronPortUuid, dpId, interfaceUuid);
             }
 
-            handleNeutronPortEvent(neutronPort, action);
+            if (this.enabled) {
+                handleNeutronPortEvent(neutronPort, action);
+            }
         }
 
         if (action == DELETE && interfaceUuid != null) {
index 4c02be45546f46db2e16544f03397850a2ed6dd4..dd24bc29c72402b295db2f72de03711ec1584d52 100644 (file)
@@ -84,7 +84,7 @@ public class SecurityGroupCacheManagerImpl implements ConfigInterface, SecurityG
     }
 
     @Override
-    public void removeFromCache(String remoteSgUuid, String portUuid) {
+    public void removeFromCache(String remoteSgUuid, String portUuid, NodeId nodeId) {
         LOG.debug("In removeFromCache remoteSgUuid:" + remoteSgUuid + " portUuid:" + portUuid);
         Map<String, NodeId> remoteSgPorts = securityGroupCache.get(remoteSgUuid);
         if (null == remoteSgPorts) {
@@ -95,8 +95,11 @@ public class SecurityGroupCacheManagerImpl implements ConfigInterface, SecurityG
         for (Iterator<String> iterator = portSet.iterator(); iterator.hasNext();) {
             String cachedPort = iterator.next();
             if (cachedPort.equals(portUuid)) {
-                iterator.remove();
-                break;
+                NodeId cachedNodeId = remoteSgPorts.get(cachedPort);
+                if(cachedNodeId.equals(nodeId)) {
+                    iterator.remove();
+                    break;
+                }
             }
         }
         if (portSet.isEmpty()) {
index ee1146715553cbd34dcbc63031bcd386d8c8c453..86929520f8d3b3a21c5e8fdda34baea9cb24c3b7 100644 (file)
@@ -195,7 +195,7 @@ public class SouthboundHandlerTest {
 
         when(ev.getAction()).thenReturn(Action.UPDATE);
         southboundHandler.processEvent(ev);
-        verify(distributedArpService, times(1)).processInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
+        verify(distributedArpService, times(1)).processInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Boolean.class), any(Action.class));
         verify(neutronL3Adapter, times(1)).handleInterfaceEvent(any(Node.class), any(OvsdbTerminationPointAugmentation.class), any(NeutronNetwork.class), any(Action.class));
         verify(networkingProvider, times(1)).handleInterfaceUpdate(any(NeutronNetwork.class), any(Node.class), any(OvsdbTerminationPointAugmentation.class));
         Mockito.reset(neutronL3Adapter);
index a9b3b55c003029bab82504a9c01e3804b7654211..ef0703d8ef4b78647c7aaa0e9337db5a32363016 100644 (file)
@@ -113,16 +113,17 @@ public class DistributedArpServiceTest {
     @Test
     public void testHandlePortEvent() throws Exception {
         NeutronPort neutronPort = PowerMockito.mock(NeutronPort.class);
+        Node node = PowerMockito.mock(Node.class);
 
         // Suppress the called to these functions.
-        MemberModifier.suppress(MemberMatcher.method(DistributedArpService.class, "handleNeutronPortForArp", NeutronPort.class, Action.class));
+        MemberModifier.suppress(MemberMatcher.method(DistributedArpService.class, "handleNeutronPortForArp", NeutronPort.class, Node.class, boolean.class, Action.class));
+
+        Whitebox.invokeMethod(distributedArpService, "handlePortEvent", neutronPort, node, false, Action.ADD);
+        PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("handleNeutronPortForArp", any(NeutronPort.class), any(Node.class), any(boolean.class), eq(Action.ADD));
 
-        Whitebox.invokeMethod(distributedArpService, "handlePortEvent", neutronPort, Action.ADD);
-        PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("handleNeutronPortForArp", any(NeutronPort.class), eq(Action.ADD));
-        
       //Case 1: Delete Action.
-        Whitebox.invokeMethod(distributedArpService, "handlePortEvent", neutronPort, Action.DELETE);
-        PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("handleNeutronPortForArp", any(NeutronPort.class), eq(Action.DELETE));
+        Whitebox.invokeMethod(distributedArpService, "handlePortEvent", neutronPort, node, false, Action.DELETE);
+        PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("handleNeutronPortForArp", any(NeutronPort.class), any(Node.class), any(boolean.class), eq(Action.DELETE));
     }
 
     /**
@@ -201,11 +202,11 @@ public class DistributedArpServiceTest {
         PowerMockito.when(southbound.readTerminationPointAugmentations(any(Node.class))).thenReturn(ports);
 
         PowerMockito.doReturn(true).when(distributedArpService, "getNeutronPortsForNode", any(Node.class), any(List.class), anyString());
-        Whitebox.invokeMethod(distributedArpService, "handleNeutronPortForArp", neutronPort, Action.ADD);
+        Whitebox.invokeMethod(distributedArpService, "handleNeutronPortForArp", neutronPort, mock(Node.class), false, Action.ADD);
         PowerMockito.verifyPrivate(distributedArpService, times(1)).invoke("getDatapathIdIntegrationBridge", any(Node.class));
 
         // Case 2: Delete Action.
-        Whitebox.invokeMethod(distributedArpService, "handleNeutronPortForArp", neutronPort, Action.DELETE);
+        Whitebox.invokeMethod(distributedArpService, "handleNeutronPortForArp", neutronPort, mock(Node.class), false, Action.DELETE);
         PowerMockito.verifyPrivate(distributedArpService, times(2)).invoke("getDatapathIdIntegrationBridge", any(Node.class));
     }
 
@@ -237,7 +238,7 @@ public class DistributedArpServiceTest {
     public void testProcessInterfaceEvent() throws Exception {
         NeutronPort neutronPort = mock(NeutronPort.class);
         NeutronNetwork neutronNetwork = mock(NeutronNetwork.class);
-        PowerMockito.doNothing().when(distributedArpService).handlePortEvent(any(NeutronPort.class), any(Action.class));
+        PowerMockito.doNothing().when(distributedArpService).handlePortEvent(any(NeutronPort.class), any(Node.class), any(boolean.class), any(Action.class));
         // init instance variables.
         TenantNetworkManager tenantNetworkManager = mock(TenantNetworkManager.class);
         MemberModifier.field(DistributedArpService.class, "tenantNetworkManager").set(distributedArpService , tenantNetworkManager);
@@ -254,12 +255,12 @@ public class DistributedArpServiceTest {
         when(tenantNetworkManager.getTenantPort(intf)).thenReturn(neutronPort);
 
         //Case 1: Add Action.
-        distributedArpService.processInterfaceEvent(node, intf, neutronNetwork, Action.ADD);
-        Mockito.verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.ADD);
+        distributedArpService.processInterfaceEvent(node, intf, neutronNetwork, false, Action.ADD);
+        Mockito.verify(distributedArpService, times(1)).handlePortEvent(neutronPort, node, false, Action.ADD);
 
         //Case 2: Delete Action.
-        distributedArpService.processInterfaceEvent(node, intf, neutronNetwork, Action.DELETE);
-        Mockito.verify(distributedArpService, times(1)).handlePortEvent(neutronPort, Action.DELETE);
+        distributedArpService.processInterfaceEvent(node, intf, neutronNetwork, false, Action.DELETE);
+        Mockito.verify(distributedArpService, times(1)).handlePortEvent(neutronPort, node, false, Action.DELETE);
     }
 
     /**
index f60c8f788c07f51bb000690b30995d5b00581212..6d80ef5ee84cbd31599b0e2d968f14261c34a8d9 100644 (file)
@@ -209,7 +209,7 @@ public class SecurityGroupCacheManagerImplTest {
     @Test
     public void testPortRemovedFromCache() {
         securityGroupCacheManagerImpl.addToCache(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_3, nodeId_1);
-        securityGroupCacheManagerImpl.removeFromCache(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_3);
+        securityGroupCacheManagerImpl.removeFromCache(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_3, nodeId_1);
         securityGroupCacheManagerImpl.portRemoved(SECURITY_GROUP_ID_2, NEUTRON_PORT_ID_VM_2);
         verify(securityServicesManager, times(0)).syncSecurityRule(any(NeutronPort.class), any(NeutronSecurityRule.class), any(Neutron_IPs.class),any(NodeId.class), any(NeutronSecurityGroup.class), anyBoolean());
     }