Only flood the ARP traffic to virtual network to avoid network loop

1. Purge unnecessary phyIntfPort method from openstacknode.
2. Update setUpstreamRulesForFlat method to reflect multi-br change

Change-Id: I6d70702d2aac2a067577635fada06c8eb21b56ae
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index 3b805e8..a4e817f 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -55,7 +55,9 @@
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.openstack4j.model.common.IdEntity;
 import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Subnet;
 import org.osgi.service.component.ComponentContext;
 import org.osgi.service.component.annotations.Activate;
@@ -72,6 +74,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
@@ -792,6 +795,35 @@
         }
     }
 
+    private void setBaseVnetArpRuleForBroadcastMode(OpenstackNode osNode,
+                                                    String segId,
+                                                    boolean isTunnel,
+                                                    boolean install) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
+                .matchEthType(EthType.EtherType.ARP.ethType().toShort())
+                .matchArpOp(ARP.OP_REQUEST);
+
+        if (isTunnel) {
+            sBuilder.matchTunnelId(Long.valueOf(segId));
+        } else {
+            sBuilder.matchVlanId(VlanId.vlanId(segId));
+        }
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.FLOOD)
+                .build();
+
+        osFlowRuleService.setRule(
+                appId,
+                osNode.intgBridge(),
+                sBuilder.build(),
+                treatment,
+                PRIORITY_ARP_FLOOD_RULE,
+                ARP_TABLE,
+                install
+        );
+    }
+
     /**
      * An internal network listener which listens to openstack network event,
      * manages the gateway collection and installs flow rule that handles
@@ -827,7 +859,11 @@
                     break;
                 case OPENSTACK_NETWORK_CREATED:
                 case OPENSTACK_NETWORK_UPDATED:
+                    eventExecutor.execute(() -> processNetworkCreation(event));
+                    break;
                 case OPENSTACK_NETWORK_REMOVED:
+                    eventExecutor.execute(() -> processNetworkRemoval(event));
+                    break;
                 case OPENSTACK_PORT_CREATED:
                 case OPENSTACK_PORT_UPDATED:
                 case OPENSTACK_PORT_REMOVED:
@@ -854,6 +890,41 @@
             setFakeGatewayArpRule(event.subnet(), event.subject(),
                     false, null);
         }
+
+        private void processNetworkCreation(OpenstackNetworkEvent event) {
+            if (!isRelevantHelper()) {
+                return;
+            }
+
+            setVnetArpRule(event.subject(), true);
+        }
+
+        private void processNetworkRemoval(OpenstackNetworkEvent event) {
+            if (!isRelevantHelper()) {
+                return;
+            }
+
+            setVnetArpRule(event.subject(), false);
+        }
+
+        private void setVnetArpRule(Network network, boolean install) {
+            String netId = network.getId();
+            NetworkType netType = network.getNetworkType();
+
+            if (netType != NetworkType.LOCAL && netType != NetworkType.FLAT
+                    && netType != NetworkType.VLAN) {
+                String segId = osNetworkService.segmentId(netId);
+                osNodeService.completeNodes(COMPUTE)
+                        .forEach(node -> setBaseVnetArpRuleForBroadcastMode(
+                                node, segId, true, install));
+            }
+            if (netType == NetworkType.VLAN) {
+                String segId = osNetworkService.segmentId(netId);
+                osNodeService.completeNodes(COMPUTE)
+                        .forEach(node -> setBaseVnetArpRuleForBroadcastMode(
+                                node, segId, false, install));
+            }
+        }
     }
 
     /**
@@ -926,7 +997,7 @@
 
         private void processDefaultArpRuleForBroadcastMode(OpenstackNode osNode,
                                                            boolean install) {
-            setDefaultArpRuleForBroadcastMode(osNode, install);
+            setVnetArpRuleForBroadcastMode(osNode, install);
 
             // we do not add fake gateway ARP rules for FLAT network
             // ARP packets generated by FLAT typed VM should not be
@@ -961,27 +1032,29 @@
             );
         }
 
-        private void setDefaultArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
-            TrafficSelector selector = DefaultTrafficSelector.builder()
-                    .matchEthType(EthType.EtherType.ARP.ethType().toShort())
-                    .matchArpOp(ARP.OP_REQUEST)
-                    .build();
+        private void setVnetArpRuleForBroadcastMode(OpenstackNode osNode, boolean install) {
+            Set<String> netIds = osNetworkService.networks().stream()
+                    .map(IdEntity::getId).collect(Collectors.toSet());
 
-            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                    .setOutput(PortNumber.FLOOD)
-                    .build();
+            netIds.stream()
+                    .filter(nid -> osNetworkService.networkType(nid) == VXLAN ||
+                                    osNetworkService.networkType(nid) == GRE ||
+                                    osNetworkService.networkType(nid) == GENEVE)
+                    .forEach(nid -> {
+                        String segId = osNetworkService.segmentId(nid);
+                        setBaseVnetArpRuleForBroadcastMode(osNode, segId, true, install);
+                    });
 
-            osFlowRuleService.setRule(
-                    appId,
-                    osNode.intgBridge(),
-                    selector,
-                    treatment,
-                    PRIORITY_ARP_FLOOD_RULE,
-                    ARP_TABLE,
-                    install
-            );
+            netIds.stream()
+                    .filter(nid -> osNetworkService.networkType(nid) == VLAN)
+                    .forEach(nid -> {
+                        String segId = osNetworkService.segmentId(nid);
+                        setBaseVnetArpRuleForBroadcastMode(osNode, segId, false, install);
+                    });
         }
 
+
+
         private void setAllArpRules(OpenstackNode osNode, boolean install) {
             if (ARP_BROADCAST_MODE.equals(getArpMode())) {
                 instancePortService.instancePorts().stream()
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
index b1d69bf..c406990 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
@@ -60,6 +60,7 @@
 
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 import static org.onosproject.openstacknetworking.api.Constants.ACL_EGRESS_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_BROADCAST_MODE;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
@@ -77,9 +78,11 @@
 import static org.onosproject.openstacknetworking.api.Constants.VTAG_TABLE;
 import static org.onosproject.openstacknetworking.api.InstancePortEvent.Type.OPENSTACK_INSTANCE_MIGRATION_STARTED;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.getPropertyValue;
+import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.structurePortName;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.swapStaleLocation;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetId;
 import static org.onosproject.openstacknetworking.util.RulePopulatorUtil.buildExtension;
+import static org.onosproject.openstacknode.api.Constants.INTEGRATION_TO_PHYSICAL_PREFIX;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -158,42 +161,37 @@
         log.info("Stopped");
     }
 
-    private void setFlatJumpRules(InstancePort port, boolean install) {
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        selector.matchInPort(port.portNumber());
+    private void setJumpRulesForFlat(InstancePort port, boolean install) {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchInPort(port.portNumber())
+                .build();
 
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-        treatment.transition(STAT_FLAT_OUTBOUND_TABLE);
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .transition(STAT_FLAT_OUTBOUND_TABLE)
+                .build();
 
         osFlowRuleService.setRule(
                 appId,
                 port.deviceId(),
-                selector.build(),
-                treatment.build(),
+                selector,
+                treatment,
                 PRIORITY_FLAT_JUMP_UPSTREAM_RULE,
                 DHCP_TABLE,
                 install);
-
-        Network network = osNetworkService.network(port.networkId());
-
-        if (network == null) {
-            log.warn("The network does not exist");
-            return;
-        }
-        PortNumber portNumber = osNodeService.node(port.deviceId())
-                .phyIntfPortNum(network.getProviderPhyNet());
-
-        if (portNumber == null) {
-            log.warn("The port number does not exist");
-            return;
-        }
     }
 
-    private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
-        TrafficSelector selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .matchIPDst(instPort.ipAddress().toIpPrefix())
-                .build();
+    private void setDownstreamRuleForFlat(InstancePort instPort,
+                                          short ethType, boolean install) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+
+        if (ethType == Ethernet.TYPE_IPV4) {
+            sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                    .matchIPDst(instPort.ipAddress().toIpPrefix());
+        } else if (ethType == Ethernet.TYPE_ARP) {
+            sBuilder.matchEthType(Ethernet.TYPE_ARP)
+                    .matchArpTpa(instPort.ipAddress().getIp4Address());
+        }
+
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                 .setOutput(instPort.portNumber())
                 .build();
@@ -201,25 +199,16 @@
         osFlowRuleService.setRule(
                 appId,
                 instPort.deviceId(),
-                selector,
+                sBuilder.build(),
                 treatment,
                 PRIORITY_FLAT_DOWNSTREAM_RULE,
                 FLAT_TABLE,
                 install);
+    }
 
-        selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_ARP)
-                .matchArpTpa(instPort.ipAddress().getIp4Address())
-                .build();
-
-        osFlowRuleService.setRule(
-                appId,
-                instPort.deviceId(),
-                selector,
-                treatment,
-                PRIORITY_FLAT_DOWNSTREAM_RULE,
-                FLAT_TABLE,
-                install);
+    private void setDownstreamRulesForFlat(InstancePort instPort, boolean install) {
+        setDownstreamRuleForFlat(instPort, Ethernet.TYPE_IPV4, install);
+        setDownstreamRuleForFlat(instPort, Ethernet.TYPE_ARP, install);
     }
 
     private void setUpstreamRulesForFlat(InstancePort instPort, boolean install) {
@@ -234,26 +223,27 @@
             return;
         }
 
-        PortNumber portNumber = osNodeService.node(instPort.deviceId())
-                .phyIntfPortNum(network.getProviderPhyNet());
+        deviceService.getPorts(instPort.deviceId()).stream()
+                .filter(port -> {
+                    String annotPortName = port.annotations().value(PORT_NAME);
+                    String portName = structurePortName(INTEGRATION_TO_PHYSICAL_PREFIX
+                            + network.getProviderPhyNet());
+                    return Objects.equals(annotPortName, portName);
+                })
+                .findAny().ifPresent(port -> {
+                    TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                            .setOutput(port.number())
+                            .build();
 
-        if (portNumber == null) {
-            log.warn("The port number does not exist");
-            return;
-        }
-
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(portNumber)
-                .build();
-
-        osFlowRuleService.setRule(
-                appId,
-                instPort.deviceId(),
-                selector,
-                treatment,
-                PRIORITY_FLAT_UPSTREAM_RULE,
-                FLAT_TABLE,
-                install);
+                    osFlowRuleService.setRule(
+                            appId,
+                            instPort.deviceId(),
+                            selector,
+                            treatment,
+                            PRIORITY_FLAT_UPSTREAM_RULE,
+                            FLAT_TABLE,
+                            install);
+        });
     }
 
     /**
@@ -750,7 +740,7 @@
         }
 
         private void setNetworkRulesForFlat(InstancePort instPort, boolean install) {
-            setFlatJumpRules(instPort, install);
+            setJumpRulesForFlat(instPort, install);
             setDownstreamRulesForFlat(instPort, install);
             setUpstreamRulesForFlat(instPort, install);
         }
@@ -798,7 +788,7 @@
         }
 
         private void removeVportRulesForFlat(InstancePort instPort) {
-            setFlatJumpRules(instPort, false);
+            setJumpRulesForFlat(instPort, false);
             setUpstreamRulesForFlat(instPort, false);
             setDownstreamRulesForFlat(instPort, false);
         }
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultOpenstackNode.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultOpenstackNode.java
index 5d79f7d..0d72a2b 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultOpenstackNode.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/DefaultOpenstackNode.java
@@ -30,15 +30,14 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Objects;
-import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static org.onosproject.net.AnnotationKeys.PORT_MAC;
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 import static org.onosproject.openstacknode.api.Constants.GENEVE_TUNNEL;
 import static org.onosproject.openstacknode.api.Constants.GRE_TUNNEL;
-import static org.onosproject.openstacknode.api.Constants.VXLAN_TUNNEL;
 import static org.onosproject.openstacknode.api.Constants.PATCH_INTG_BRIDGE;
+import static org.onosproject.openstacknode.api.Constants.VXLAN_TUNNEL;
 
 /**
  * Representation of a openstack node.
@@ -395,25 +394,6 @@
         return neutronConfig;
     }
 
-    @Override
-    public PortNumber phyIntfPortNum(String providerPhysnet) {
-        Optional<OpenstackPhyInterface> openstackPhyInterface =
-                phyIntfs.stream().filter(p -> p.network().equals(providerPhysnet)).findAny();
-
-        if (openstackPhyInterface.isPresent()) {
-            DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
-            Port port = deviceService.getPorts(intgBridge).stream()
-                    .filter(p -> p.isEnabled() &&
-                            Objects.equals(p.annotations().value(PORT_NAME), openstackPhyInterface.get().intf()))
-                    .findAny().orElse(null);
-
-            return port != null ? port.number() : null;
-        } else {
-            return null;
-        }
-
-    }
-
     /**
      * Returns new builder instance.
      *
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
index 2578eb8..8a0e1eb 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
@@ -188,14 +188,6 @@
     Collection<OpenstackPhyInterface> phyIntfs();
 
     /**
-     * Returns the port number of given physical interface.
-     *
-     * @param providerPhysnet provider physical network name
-     * @return port number
-     */
-    PortNumber phyIntfPortNum(String providerPhysnet);
-
-    /**
      * Returns a collection of customized controllers.
      *
      * @return customized controllers
diff --git a/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/OpenstackNodeAdapter.java b/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/OpenstackNodeAdapter.java
index 79a2048..5e6f703 100644
--- a/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/OpenstackNodeAdapter.java
+++ b/apps/openstacknode/api/src/test/java/org/onosproject/openstacknode/api/OpenstackNodeAdapter.java
@@ -134,11 +134,6 @@
     }
 
     @Override
-    public PortNumber phyIntfPortNum(String providerPhysnet) {
-        return null;
-    }
-
-    @Override
     public Collection<ControllerInfo> controllers() {
         return null;
     }