Fix: enforce packet to go through ingress pipeline inside a node

Change-Id: I04ad1c919a9c82f5526b91d43ba788163da041dd
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
index 1be5b35..6352bb2 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
@@ -75,6 +75,7 @@
     public static final int PRIORITY_DHCP_RULE = 42000;
     public static final int PRIORITY_ADMIN_RULE = 32000;
     public static final int PRIORITY_ACL_RULE = 31000;
+    public static final int PRIORITY_ACL_INGRESS_RULE = 30000;
     public static final int PRIORITY_CT_HOOK_RULE = 30500;
     public static final int PRIORITY_CT_RULE = 32000;
     public static final int PRIORITY_CT_DROP_RULE = 32500;
@@ -98,8 +99,10 @@
     public static final int FLAT_TABLE = 20;
     public static final int VTAG_TABLE = 30;
     public static final int ARP_TABLE = 35;
-    public static final int ACL_TABLE = 40;
-    public static final int CT_TABLE = 41;
+    public static final int ACL_EGRESS_TABLE = 40;
+    public static final int ACL_INGRESS_TABLE = 44;
+    public static final int CT_TABLE = 45;
+    public static final int ACL_RECIRC_TABLE = 43;
     public static final int JUMP_TABLE = 50;
     public static final int ROUTING_TABLE = 60;
     public static final int STAT_OUTBOUND_TABLE = 70;
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManager.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManager.java
index 0dc4db7..19e52fc 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManager.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManager.java
@@ -207,10 +207,10 @@
         connectTables(deviceId, Constants.VTAG_TABLE, Constants.ARP_TABLE);
 
         // for ARP and ACL table transition
-        connectTables(deviceId, Constants.ARP_TABLE, Constants.ACL_TABLE);
+        connectTables(deviceId, Constants.ARP_TABLE, Constants.ACL_INGRESS_TABLE);
 
         // for ACL and JUMP table transition
-        connectTables(deviceId, Constants.ACL_TABLE, Constants.JUMP_TABLE);
+        connectTables(deviceId, Constants.ACL_EGRESS_TABLE, Constants.JUMP_TABLE);
 
         // for JUMP table transition
         // we need JUMP table for bypassing routing table which contains large
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
index 52eb1ae..3a28831 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
@@ -62,6 +62,8 @@
 import org.onosproject.store.service.ConsistentMap;
 import org.onosproject.store.service.Serializer;
 import org.onosproject.store.service.StorageService;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.SecurityGroup;
 import org.openstack4j.model.network.SecurityGroupRule;
@@ -92,11 +94,14 @@
 
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
+import static org.onosproject.openstacknetworking.api.Constants.ACL_EGRESS_TABLE;
+import static org.onosproject.openstacknetworking.api.Constants.ACL_INGRESS_TABLE;
+import static org.onosproject.openstacknetworking.api.Constants.ACL_RECIRC_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.CT_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.ERROR_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.JUMP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
+import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_INGRESS_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ACL_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_DROP_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
@@ -288,6 +293,37 @@
                 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
     }
 
+    private void initializeAclTable(DeviceId deviceId, boolean install) {
+
+        ExtensionTreatment ctTreatment =
+                niciraConnTrackTreatmentBuilder(driverService, deviceId)
+                        .commit(true)
+                        .build();
+
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4);
+
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+        tBuilder.extension(ctTreatment, deviceId)
+                .transition(JUMP_TABLE);
+
+        osFlowRuleService.setRule(appId,
+                deviceId,
+                sBuilder.build(),
+                tBuilder.build(),
+                PRIORITY_ACL_INGRESS_RULE,
+                ACL_RECIRC_TABLE,
+                install);
+    }
+
+    private void initializeIngressTable(DeviceId deviceId, boolean install) {
+        if (install) {
+            osFlowRuleService.setUpTableMissEntry(deviceId, ACL_INGRESS_TABLE);
+        } else {
+            osFlowRuleService.connectTables(deviceId, ACL_INGRESS_TABLE, JUMP_TABLE);
+        }
+    }
+
     private void setSecurityGroupRules(InstancePort instPort,
                                        Port port, boolean install) {
 
@@ -327,9 +363,9 @@
         if (sgRule.getRemoteGroupId() != null && !sgRule.getRemoteGroupId().isEmpty()) {
             getRemoteInstPorts(port, sgRule.getRemoteGroupId(), install)
                     .forEach(rInstPort -> {
-                        populateSecurityGroupRule(sgRule, instPort, port,
+                        populateSecurityGroupRule(sgRule, instPort,
                                 rInstPort.ipAddress().toIpPrefix(), install);
-                        populateSecurityGroupRule(sgRule, rInstPort, port,
+                        populateSecurityGroupRule(sgRule, rInstPort,
                                 instPort.ipAddress().toIpPrefix(), install);
 
                         SecurityGroupRule rSgRule =
@@ -339,13 +375,13 @@
                                         .direction(sgRule.getDirection().toUpperCase()
                                                 .equals(EGRESS) ? INGRESS : EGRESS)
                                         .build();
-                        populateSecurityGroupRule(rSgRule, instPort, port,
+                        populateSecurityGroupRule(rSgRule, instPort,
                                 rInstPort.ipAddress().toIpPrefix(), install);
-                        populateSecurityGroupRule(rSgRule, rInstPort, port,
+                        populateSecurityGroupRule(rSgRule, rInstPort,
                                 instPort.ipAddress().toIpPrefix(), install);
                     });
         } else {
-            populateSecurityGroupRule(sgRule, instPort, port,
+            populateSecurityGroupRule(sgRule, instPort,
                     sgRule.getRemoteIpPrefix() == null ? IP_PREFIX_ANY :
                             IpPrefix.valueOf(sgRule.getRemoteIpPrefix()), install);
         }
@@ -353,11 +389,11 @@
 
     private void populateSecurityGroupRule(SecurityGroupRule sgRule,
                                            InstancePort instPort,
-                                           Port port,
                                            IpPrefix remoteIp,
                                            boolean install) {
         Set<TrafficSelector> selectors = buildSelectors(sgRule,
-                Ip4Address.valueOf(instPort.ipAddress().toInetAddress()), remoteIp, port);
+                        Ip4Address.valueOf(instPort.ipAddress().toInetAddress()),
+                                    remoteIp, instPort.networkId());
         if (selectors == null || selectors.isEmpty()) {
             return;
         }
@@ -369,18 +405,27 @@
                         .commit(true)
                         .build();
 
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .extension(ctTreatment, instPort.deviceId())
-                .transition(JUMP_TABLE)
-                .build();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
 
-        selectors.forEach(selector ->
-                osFlowRuleService.setRule(appId,
-                        instPort.deviceId(),
-                        selector, treatment,
-                        PRIORITY_ACL_RULE,
-                        ACL_TABLE,
-                        install));
+        int aclTable;
+        if (sgRule.getDirection().toUpperCase().equals(EGRESS)) {
+            aclTable = ACL_EGRESS_TABLE;
+            tBuilder.transition(ACL_RECIRC_TABLE);
+        } else {
+            aclTable = ACL_INGRESS_TABLE;
+            tBuilder.extension(ctTreatment, instPort.deviceId())
+                    .transition(JUMP_TABLE);
+        }
+
+        int finalAclTable = aclTable;
+        selectors.forEach(selector -> {
+            osFlowRuleService.setRule(appId,
+                    instPort.deviceId(),
+                    selector, tBuilder.build(),
+                    PRIORITY_ACL_RULE,
+                    finalAclTable,
+                    install);
+        });
     }
 
     /**
@@ -440,7 +485,7 @@
         if (priority == PRIORITY_CT_RULE || priority == PRIORITY_CT_DROP_RULE) {
             tableType = CT_TABLE;
         } else if (priority == PRIORITY_CT_HOOK_RULE) {
-            tableType = ACL_TABLE;
+            tableType = ACL_INGRESS_TABLE;
         } else {
             log.error("Cannot an appropriate table for the conn track rule.");
         }
@@ -488,7 +533,7 @@
     private Set<TrafficSelector> buildSelectors(SecurityGroupRule sgRule,
                                                 Ip4Address vmIp,
                                                 IpPrefix remoteIp,
-                                                Port port) {
+                                                String netId) {
         if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
             // do nothing if the remote IP is my IP
             return null;
@@ -497,7 +542,7 @@
         Set<TrafficSelector> selectorSet = Sets.newHashSet();
 
         TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-        buildMatches(sBuilder, sgRule, vmIp, remoteIp, port);
+        buildMatches(sBuilder, sgRule, vmIp, remoteIp, netId);
 
         if (sgRule.getPortRangeMax() != null && sgRule.getPortRangeMin() != null &&
                 sgRule.getPortRangeMin() < sgRule.getPortRangeMax()) {
@@ -530,9 +575,9 @@
     }
 
     private void buildMatches(TrafficSelector.Builder sBuilder,
-                              SecurityGroupRule sgRule,
-                              Ip4Address vmIp, IpPrefix remoteIp, Port port) {
-        buildTunnelId(sBuilder, port);
+                              SecurityGroupRule sgRule, Ip4Address vmIp,
+                              IpPrefix remoteIp, String netId) {
+        buildTunnelId(sBuilder, netId);
         buildMatchEthType(sBuilder, sgRule.getEtherType());
         buildMatchDirection(sBuilder, sgRule.getDirection(), vmIp);
         buildMatchProto(sBuilder, sgRule.getProtocol());
@@ -542,9 +587,9 @@
         buildMatchRemoteIp(sBuilder, remoteIp, sgRule.getDirection());
     }
 
-    private void buildTunnelId(TrafficSelector.Builder sBuilder, Port port) {
-        String segId = osNetService.segmentId(port.getNetworkId());
-        String netType = osNetService.networkType(port.getNetworkId());
+    private void buildTunnelId(TrafficSelector.Builder sBuilder, String netId) {
+        String segId = osNetService.segmentId(netId);
+        String netType = osNetService.networkType(netId);
 
         if (VLAN.equals(netType)) {
             sBuilder.matchVlanId(VlanId.vlanId(segId));
@@ -627,16 +672,20 @@
 
         if (useSecurityGroup) {
             osNodeService.completeNodes(COMPUTE).forEach(node -> {
-                osFlowRuleService.setUpTableMissEntry(node.intgBridge(), ACL_TABLE);
+                osFlowRuleService.setUpTableMissEntry(node.intgBridge(), ACL_EGRESS_TABLE);
                 initializeConnTrackTable(node.intgBridge(), true);
+                initializeAclTable(node.intgBridge(), true);
+                initializeIngressTable(node.intgBridge(), true);
             });
 
             securityGroupService.securityGroups().forEach(securityGroup ->
                     securityGroup.getRules().forEach(this::securityGroupRuleAdded));
         } else {
             osNodeService.completeNodes(COMPUTE).forEach(node -> {
-                osFlowRuleService.connectTables(node.intgBridge(), ACL_TABLE, JUMP_TABLE);
+                osFlowRuleService.connectTables(node.intgBridge(), ACL_EGRESS_TABLE, JUMP_TABLE);
                 initializeConnTrackTable(node.intgBridge(), false);
+                initializeAclTable(node.intgBridge(), false);
+                initializeIngressTable(node.intgBridge(), false);
             });
 
             securityGroupService.securityGroups().forEach(securityGroup ->
@@ -780,6 +829,7 @@
                         }
 
                         installSecurityGroupRules(event, instPort);
+                        setAclRecircRules(instPort, true);
                     });
                     break;
                 case OPENSTACK_INSTANCE_PORT_VANISHED:
@@ -792,6 +842,7 @@
                         Port osPort = removedOsPortStore.asJavaMap().get(instPort.portId());
                         setSecurityGroupRules(instPort, osPort, false);
                         removedOsPortStore.remove(instPort.portId());
+                        setAclRecircRules(instPort, false);
                     });
                     break;
                 case OPENSTACK_INSTANCE_MIGRATION_ENDED:
@@ -804,6 +855,7 @@
                         InstancePort revisedInstPort = swapStaleLocation(instPort);
                         Port port = osNetService.port(instPort.portId());
                         setSecurityGroupRules(revisedInstPort, port, false);
+                        setAclRecircRules(revisedInstPort, false);
                     });
                     break;
                 default:
@@ -820,6 +872,40 @@
                     setSecurityGroupRules(instPort,
                             osNetService.port(event.subject().portId()), true));
         }
+
+        private void setAclRecircRules(InstancePort instPort, boolean install) {
+            TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+
+            Network net = osNetService.network(instPort.networkId());
+            NetworkType netType = net.getNetworkType();
+            String segId = net.getProviderSegID();
+
+            switch (netType) {
+                case VXLAN:
+                    sBuilder.matchTunnelId(Long.valueOf(segId));
+                    break;
+                case VLAN:
+                    sBuilder.matchVlanId(VlanId.vlanId(segId));
+                    break;
+                default:
+                    break;
+            }
+
+            sBuilder.matchEthType(Ethernet.TYPE_IPV4);
+            sBuilder.matchIPDst(IpPrefix.valueOf(instPort.ipAddress(), VM_IP_PREFIX));
+
+            TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+            tBuilder.transition(ACL_INGRESS_TABLE);
+
+            osFlowRuleService.setRule(
+                    appId,
+                    instPort.deviceId(),
+                    sBuilder.build(),
+                    tBuilder.build(),
+                    PRIORITY_ACL_RULE,
+                    ACL_RECIRC_TABLE,
+                    install);
+        }
     }
 
     private class InternalOpenstackPortListener implements OpenstackNetworkListener {
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 196c07d..9bd06ef 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,7 +60,7 @@
 
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
+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;
 import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
@@ -503,7 +503,7 @@
         if (ethType == Ethernet.TYPE_ARP) {
             tBuilder.transition(ARP_TABLE);
         } else if (ethType == Ethernet.TYPE_IPV4) {
-            tBuilder.transition(ACL_TABLE);
+            tBuilder.transition(ACL_EGRESS_TABLE);
         }
 
         osFlowRuleService.setRule(
@@ -547,7 +547,7 @@
         if (ethType == Ethernet.TYPE_ARP) {
             tBuilder.transition(ARP_TABLE);
         } else if (ethType == Ethernet.TYPE_IPV4) {
-            tBuilder.transition(ACL_TABLE);
+            tBuilder.transition(ACL_EGRESS_TABLE);
         }
 
         osFlowRuleService.setRule(
@@ -599,7 +599,7 @@
                         selector,
                         treatment,
                         PRIORITY_ADMIN_RULE,
-                        ACL_TABLE,
+                        ACL_EGRESS_TABLE,
                         install)
                 );
     }
@@ -621,7 +621,7 @@
                         selector,
                         treatment,
                         PRIORITY_ADMIN_RULE,
-                        ACL_TABLE,
+                        ACL_EGRESS_TABLE,
                         install)
                 );
     }
diff --git a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManagerTest.java b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManagerTest.java
index d1410b2..ed73636 100644
--- a/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManagerTest.java
+++ b/apps/openstacknetworking/app/src/test/java/org/onosproject/openstacknetworking/impl/OpenstackFlowRuleManagerTest.java
@@ -44,7 +44,8 @@
 import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
-import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
+import static org.onosproject.openstacknetworking.api.Constants.ACL_EGRESS_TABLE;
+import static org.onosproject.openstacknetworking.api.Constants.ACL_INGRESS_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.ARP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.DHCP_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.FLAT_TABLE;
@@ -195,8 +196,8 @@
         fromToTableMap.put(VTAP_INBOUND_TABLE, DHCP_TABLE);
         fromToTableMap.put(DHCP_TABLE, VTAG_TABLE);
         fromToTableMap.put(VTAG_TABLE, ARP_TABLE);
-        fromToTableMap.put(ARP_TABLE, ACL_TABLE);
-        fromToTableMap.put(ACL_TABLE, JUMP_TABLE);
+        fromToTableMap.put(ARP_TABLE, ACL_INGRESS_TABLE);
+        fromToTableMap.put(ACL_EGRESS_TABLE, JUMP_TABLE);
         fromToTableMap.put(STAT_OUTBOUND_TABLE, VTAP_OUTBOUND_TABLE);
         fromToTableMap.put(VTAP_OUTBOUND_TABLE, FORWARDING_TABLE);
         fromToTableMap.put(STAT_FLAT_OUTBOUND_TABLE, VTAP_FLAT_OUTBOUND_TABLE);
diff --git a/apps/openstacktroubleshoot/app/src/main/java/org/onosproject/openstacktroubleshoot/impl/OpenstackTroubleshootManager.java b/apps/openstacktroubleshoot/app/src/main/java/org/onosproject/openstacktroubleshoot/impl/OpenstackTroubleshootManager.java
index c2f4b22..4017fdd 100644
--- a/apps/openstacktroubleshoot/app/src/main/java/org/onosproject/openstacktroubleshoot/impl/OpenstackTroubleshootManager.java
+++ b/apps/openstacktroubleshoot/app/src/main/java/org/onosproject/openstacktroubleshoot/impl/OpenstackTroubleshootManager.java
@@ -84,7 +84,7 @@
 import static org.onosproject.net.flow.FlowEntry.FlowEntryState.ADDED;
 import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_DST;
 import static org.onosproject.net.flow.criteria.Criterion.Type.IPV4_SRC;
-import static org.onosproject.openstacknetworking.api.Constants.ACL_TABLE;
+import static org.onosproject.openstacknetworking.api.Constants.ACL_EGRESS_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
 import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
 import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
@@ -353,7 +353,7 @@
 
         TrafficTreatment.Builder tb = DefaultTrafficTreatment.builder()
                 .setTunnelId(getSegId(osNetworkService, port))
-                .transition(ACL_TABLE);
+                .transition(ACL_EGRESS_TABLE);
 
         osFlowRuleService.setRule(
                 appId,