Support security group for provider typed networks (FLAT and VLAN)

Change-Id: I759b89eb16c0ab27ee068694dd455265bac4bf52
(cherry picked from commit 8ed2c9875172daf2a2be95a210e3e151eb4a6525)
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
index 79e8351..cdeffbe 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/Constants.java
@@ -37,18 +37,14 @@
     // provider and VLAN integration bridge flow table index
     public static final int STAT_INBOUND_TABLE = 0;
     public static final int VTAP_INBOUND_TABLE = 1;
-    public static final int STAT_FLAT_OUTBOUND_TABLE = 10;
     public static final int DHCP_TABLE = 5;
-    public static final int VTAG_TABLE = 30;
-    public static final int PRE_FLAT_TABLE = 31;
-    public static final int FLAT_TABLE = 32;
+    public static final int GW_ENTRY_TABLE = 31;
+    public static final int GW_DROP_TABLE = 32;
     public static final int ARP_TABLE = 35;
     public static final int ACL_EGRESS_TABLE = 40;
     public static final int ACL_RECIRC_TABLE = 43;
     public static final int ACL_INGRESS_TABLE = 44;
     public static final int ACL_CT_TABLE = 45;
-    public static final int JUMP_TABLE = 50;
-    public static final int ROUTING_TABLE = 60;
     public static final int STAT_OUTBOUND_TABLE = 70;
     public static final int VTAP_OUTBOUND_TABLE = 71;
     public static final int FORWARDING_TABLE = 80;
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
index b77fb04..b7d0842 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFloatingIpHandler.java
@@ -62,8 +62,8 @@
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
-import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FLOATING_IP_RULE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
@@ -199,7 +199,7 @@
                 selector,
                 treatment,
                 PRIORITY_ARP_GATEWAY_RULE,
-                PRE_FLAT_TABLE,
+                GW_ENTRY_TABLE,
                 install);
     }
 
@@ -248,7 +248,7 @@
                 selector,
                 treatment,
                 PRIORITY_FLOATING_IP_RULE,
-                PRE_FLAT_TABLE,
+                GW_ENTRY_TABLE,
                 install);
     }
 
@@ -278,7 +278,7 @@
                 selector,
                 treatment,
                 PRIORITY_FLOATING_IP_RULE,
-                PRE_FLAT_TABLE,
+                GW_ENTRY_TABLE,
                 install);
     }
 
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFlowRuleManager.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFlowRuleManager.java
index 585c925..fd0669a 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFlowRuleManager.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtFlowRuleManager.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.kubevirtnetworking.impl;
 
+import org.onlab.packet.EthType;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cfg.ConfigProperty;
@@ -57,21 +58,15 @@
 
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.kubevirtnetworking.api.Constants.ACL_EGRESS_TABLE;
-import static org.onosproject.kubevirtnetworking.api.Constants.ACL_INGRESS_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.ARP_TABLE;
-import static org.onosproject.kubevirtnetworking.api.Constants.DEFAULT_GATEWAY_MAC;
 import static org.onosproject.kubevirtnetworking.api.Constants.DHCP_TABLE;
-import static org.onosproject.kubevirtnetworking.api.Constants.FLAT_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
-import static org.onosproject.kubevirtnetworking.api.Constants.JUMP_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.GW_DROP_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
-import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
-import static org.onosproject.kubevirtnetworking.api.Constants.ROUTING_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_DEFAULT_RULE;
 import static org.onosproject.kubevirtnetworking.api.Constants.STAT_INBOUND_TABLE;
-import static org.onosproject.kubevirtnetworking.api.Constants.STAT_OUTBOUND_TABLE;
-import static org.onosproject.kubevirtnetworking.api.Constants.VTAG_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.VTAP_INBOUND_TABLE;
-import static org.onosproject.kubevirtnetworking.api.Constants.VTAP_OUTBOUND_TABLE;
 import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.PROVIDER_NETWORK_ONLY;
 import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.PROVIDER_NETWORK_ONLY_DEFAULT;
 import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
@@ -95,9 +90,6 @@
 
     private static final int DROP_PRIORITY = 0;
     private static final int LOW_PRIORITY = 10000;
-    private static final int MID_PRIORITY = 20000;
-    private static final int HIGH_PRIORITY = 30000;
-    private static final int TIMEOUT_SNAT_RULE = 60;
 
     /** Use provider network only. */
     private boolean providerNetworkOnly = PROVIDER_NETWORK_ONLY_DEFAULT;
@@ -194,17 +186,14 @@
 
         treatment.drop();
 
-        FlowRule flowRule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(DROP_PRIORITY)
-                .fromApp(appId)
-                .makePermanent()
-                .forTable(table)
-                .build();
-
-        applyRule(flowRule, true);
+        this.setRule(
+                appId,
+                deviceId,
+                selector.build(),
+                treatment.build(),
+                DROP_PRIORITY,
+                table,
+                true);
     }
 
     @Override
@@ -214,17 +203,14 @@
 
         treatment.transition(toTable);
 
-        FlowRule flowRule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(DROP_PRIORITY)
-                .fromApp(appId)
-                .makePermanent()
-                .forTable(fromTable)
-                .build();
-
-        applyRule(flowRule, true);
+        this.setRule(
+                appId,
+                deviceId,
+                selector.build(),
+                treatment.build(),
+                DROP_PRIORITY,
+                fromTable,
+                true);
     }
 
     private void applyRule(FlowRule flowRule, boolean install) {
@@ -246,24 +232,14 @@
     }
 
     protected void initializeGatewayNodePipeline(DeviceId deviceId) {
-        // for inbound table transition
-        connectTables(deviceId, STAT_INBOUND_TABLE, VTAG_TABLE);
+        // for inbound to gateway entry table transition
+        connectTables(deviceId, STAT_INBOUND_TABLE, GW_ENTRY_TABLE);
 
-        if (getProviderNetworkOnlyFlag()) {
-            // we directly transit from vTag table to PRE_FLAT table for provider
-            // network only mode, because there is no need to differentiate ARP
-            // and IP packets on this mode
-            connectTables(deviceId, VTAG_TABLE, PRE_FLAT_TABLE);
-        } else {
-            // for vTag and ARP table transition
-            connectTables(deviceId, VTAG_TABLE, ARP_TABLE);
-        }
+        // for gateway entry to gateway drop table transition
+        connectTables(deviceId, GW_ENTRY_TABLE, GW_DROP_TABLE);
 
-        // for PRE_FLAT and FLAT table transition
-        connectTables(deviceId, PRE_FLAT_TABLE, FLAT_TABLE);
-
-        // for setting up default FLAT table behavior which is drop
-        setupGatewayNodeFlatTable(deviceId);
+        // for setting up default gateway drop table
+        setupGatewayNodeDropTable(deviceId);
 
         // for setting up default Forwarding table behavior which is NORMAL
         setupForwardingTable(deviceId);
@@ -273,80 +249,34 @@
         connectTables(deviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE);
         connectTables(deviceId, VTAP_INBOUND_TABLE, DHCP_TABLE);
 
-        // for DHCP and vTag table transition
-        connectTables(deviceId, DHCP_TABLE, VTAG_TABLE);
+        // for DHCP and ARP table transition
+        connectTables(deviceId, DHCP_TABLE, ARP_TABLE);
 
-        if (getProviderNetworkOnlyFlag()) {
-            // we directly transit from vTag table to PRE_FLAT table for provider
-            // network only mode, because there is no need to differentiate ARP
-            // and IP packets on this mode
-            connectTables(deviceId, VTAG_TABLE, PRE_FLAT_TABLE);
-        } else {
-            // for vTag and ARP table transition
-            connectTables(deviceId, VTAG_TABLE, ARP_TABLE);
-        }
+        // for ARP table and ACL egress table transition
+        connectTables(deviceId, ARP_TABLE, ACL_EGRESS_TABLE);
 
-        // for PRE_FLAT and FLAT table transition
-        connectTables(deviceId, PRE_FLAT_TABLE, FLAT_TABLE);
-
-        // for FLAT table and ACL table transition
-        connectTables(deviceId, FLAT_TABLE, ACL_EGRESS_TABLE);
-
-        // for ARP and ACL table transition
-        connectTables(deviceId, ARP_TABLE, ACL_INGRESS_TABLE);
-
-        // for ACL and JUMP table transition
-        connectTables(deviceId, ACL_EGRESS_TABLE, JUMP_TABLE);
-
-        // for outbound table transition
-        connectTables(deviceId, STAT_OUTBOUND_TABLE, VTAP_OUTBOUND_TABLE);
-        connectTables(deviceId, VTAP_OUTBOUND_TABLE, FORWARDING_TABLE);
-
-        // for JUMP table transition
-        // we need JUMP table for bypassing routing table which contains large
-        // amount of flow rules which might cause performance degradation during
-        // table lookup
-        setupJumpTable(deviceId);
+        // for setting up default ARP table behavior
+        setupArpTable(deviceId);
 
         // for setting up default Forwarding table behavior which is NORMAL
         setupForwardingTable(deviceId);
     }
 
-    private void setupJumpTable(DeviceId deviceId) {
-        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
-        TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+    private void setupArpTable(DeviceId deviceId) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        sBuilder.matchEthType(EthType.EtherType.ARP.ethType().toShort());
 
-        selector.matchEthDst(DEFAULT_GATEWAY_MAC);
-        treatment.transition(ROUTING_TABLE);
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+        tBuilder.transition(FORWARDING_TABLE);
 
-        FlowRule flowRule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(HIGH_PRIORITY)
-                .fromApp(appId)
-                .makePermanent()
-                .forTable(JUMP_TABLE)
-                .build();
-
-        applyRule(flowRule, true);
-
-        selector = DefaultTrafficSelector.builder();
-        treatment = DefaultTrafficTreatment.builder();
-
-        treatment.transition(STAT_OUTBOUND_TABLE);
-
-        flowRule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(DROP_PRIORITY)
-                .fromApp(appId)
-                .makePermanent()
-                .forTable(JUMP_TABLE)
-                .build();
-
-        applyRule(flowRule, true);
+        this.setRule(
+                appId,
+                deviceId,
+                sBuilder.build(),
+                tBuilder.build(),
+                PRIORITY_ARP_DEFAULT_RULE,
+                ARP_TABLE,
+                true);
     }
 
     private void setupForwardingTable(DeviceId deviceId) {
@@ -354,36 +284,29 @@
         TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
                 .setOutput(PortNumber.NORMAL);
 
-        FlowRule flowRule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(LOW_PRIORITY)
-                .fromApp(appId)
-                .makePermanent()
-                .forTable(FORWARDING_TABLE)
-                .build();
-
-        applyRule(flowRule, true);
+        this.setRule(
+                appId,
+                deviceId,
+                selector.build(),
+                treatment.build(),
+                LOW_PRIORITY,
+                FORWARDING_TABLE,
+                true);
     }
 
-    private void setupGatewayNodeFlatTable(DeviceId deviceId) {
+    private void setupGatewayNodeDropTable(DeviceId deviceId) {
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
         TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
                 .drop();
 
-        FlowRule flowRule = DefaultFlowRule.builder()
-                .forDevice(deviceId)
-                .withSelector(selector.build())
-                .withTreatment(treatment.build())
-                .withPriority(DROP_PRIORITY)
-                .fromApp(appId)
-                .makePermanent()
-                .forTable(FLAT_TABLE)
-                .build();
-
-        applyRule(flowRule, true);
-
+        this.setRule(
+                appId,
+                deviceId,
+                selector.build(),
+                treatment.build(),
+                DROP_PRIORITY,
+                GW_DROP_TABLE,
+                true);
     }
 
     private boolean getProviderNetworkOnlyFlag() {
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkHandler.java
index f3edd55..c853e3f 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtNetworkHandler.java
@@ -86,8 +86,8 @@
 import static org.onlab.packet.ICMP.TYPE_ECHO_REQUEST;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
-import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_DEFAULT_RULE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_DHCP_RULE;
@@ -400,7 +400,7 @@
 
         // security group related rules
         setTenantIngressTransitionRule(network, network.tenantDeviceId(node.hostname()), true);
-        setEgressTransitionRule(network.tenantDeviceId(node.hostname()), true);
+        setTenantEgressTransitionRule(network.tenantDeviceId(node.hostname()), true);
 
         log.info("Install default flow rules for tenant bridge {}", network.tenantBridgeName());
     }
@@ -468,9 +468,9 @@
             case FLAT:
             case VLAN:
                 setGatewayArpRuleForProviderInternalNetwork(router, network,
-                        PRE_FLAT_TABLE, electedGateway.intgBridge(), install);
+                        GW_ENTRY_TABLE, electedGateway.intgBridge(), install);
                 setGatewayIcmpRuleForProviderInternalNetwork(router, network,
-                        PRE_FLAT_TABLE, electedGateway.intgBridge(), install);
+                        GW_ENTRY_TABLE, electedGateway.intgBridge(), install);
                 setGatewayProviderInterNetworkRoutingWithinSameRouter(network,
                         router, electedGateway, install);
                 break;
@@ -555,7 +555,7 @@
         );
     }
 
-    private void setEgressTransitionRule(DeviceId deviceId, boolean install) {
+    private void setTenantEgressTransitionRule(DeviceId deviceId, boolean install) {
         TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
         sBuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
 
@@ -791,7 +791,7 @@
                     sBuilder.build(),
                     treatment,
                     PRIORITY_INTERNAL_ROUTING_RULE,
-                    PRE_FLAT_TABLE,
+                    GW_ENTRY_TABLE,
                     install);
         } else {
             KubevirtNetwork dstNetwork = kubevirtNetworkService.network(dstPort.networkId());
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingArpHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingArpHandler.java
index 11598a2..1e5260b 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingArpHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingArpHandler.java
@@ -62,8 +62,8 @@
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.kubevirtnetworking.api.Constants.DEFAULT_GATEWAY_MAC;
+import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
-import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -217,7 +217,7 @@
                 selector,
                 treatment,
                 PRIORITY_ARP_GATEWAY_RULE,
-                PRE_FLAT_TABLE,
+                GW_ENTRY_TABLE,
                 install
         );
     }
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingSnatHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingSnatHandler.java
index 9acf35e..2b99937 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingSnatHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtRoutingSnatHandler.java
@@ -69,10 +69,10 @@
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.kubevirtnetworking.api.Constants.DEFAULT_GATEWAY_MAC;
-import static org.onosproject.kubevirtnetworking.api.Constants.FLAT_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.GW_DROP_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.GW_ENTRY_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
-import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ARP_GATEWAY_RULE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
@@ -237,7 +237,7 @@
                 selector,
                 treatment,
                 PRIORITY_ARP_GATEWAY_RULE,
-                PRE_FLAT_TABLE,
+                GW_ENTRY_TABLE,
                 install);
     }
 
@@ -282,7 +282,7 @@
                 selector.build(),
                 tBuilder.build(),
                 PRIORITY_STATEFUL_SNAT_RULE,
-                PRE_FLAT_TABLE,
+                GW_ENTRY_TABLE,
                 install);
     }
 
@@ -315,7 +315,7 @@
                 sBuilder.build(),
                 tBuilder.build(),
                 PRIORITY_STATEFUL_SNAT_RULE,
-                FLAT_TABLE,
+                GW_DROP_TABLE,
                 install);
 
         if (network.type() == VXLAN || network.type() == GENEVE || network.type() == GRE) {
@@ -403,7 +403,7 @@
                 .niciraConnTrackTreatmentBuilder(driverService, gatewayNode.intgBridge())
                 .commit(false)
                 .natAction(true)
-                .table((short) FLAT_TABLE)
+                .table((short) GW_DROP_TABLE)
                 .build();
 
         tBuilder.setEthSrc(routerMacAddress)
@@ -415,7 +415,7 @@
                 sBuilder.build(),
                 tBuilder.build(),
                 PRIORITY_STATEFUL_SNAT_RULE,
-                PRE_FLAT_TABLE,
+                GW_ENTRY_TABLE,
                 install);
     }
 
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSecurityGroupHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSecurityGroupHandler.java
index 77b60d9..c4802a6 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSecurityGroupHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSecurityGroupHandler.java
@@ -21,8 +21,8 @@
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
 import org.onlab.packet.TpPort;
-import org.onlab.packet.VlanId;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cfg.ConfigProperty;
@@ -33,7 +33,6 @@
 import org.onosproject.core.CoreService;
 import org.onosproject.kubevirtnetworking.api.KubevirtFlowRuleService;
 import org.onosproject.kubevirtnetworking.api.KubevirtNetwork;
-import org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type;
 import org.onosproject.kubevirtnetworking.api.KubevirtNetworkEvent;
 import org.onosproject.kubevirtnetworking.api.KubevirtNetworkListener;
 import org.onosproject.kubevirtnetworking.api.KubevirtNetworkService;
@@ -53,6 +52,7 @@
 import org.onosproject.kubevirtnode.api.KubevirtNodeService;
 import org.onosproject.mastership.MastershipService;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -81,7 +81,12 @@
 import static java.lang.Thread.sleep;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.kubevirtnetworking.api.Constants.ACL_CT_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.ACL_EGRESS_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.ACL_INGRESS_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.ACL_RECIRC_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.ERROR_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.FORWARDING_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_INGRESS_RULE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_ACL_RULE;
@@ -93,10 +98,8 @@
 import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_INGRESS_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_ACL_RECIRC_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.TENANT_FORWARDING_TABLE;
-import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GENEVE;
-import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.GRE;
+import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.FLAT;
 import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VLAN;
-import static org.onosproject.kubevirtnetworking.api.KubevirtNetwork.Type.VXLAN;
 import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP;
 import static org.onosproject.kubevirtnetworking.impl.OsgiPropertyConstants.USE_SECURITY_GROUP_DEFAULT;
 import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.getPropertyValueAsBoolean;
@@ -260,19 +263,28 @@
         return getPropertyValueAsBoolean(properties, USE_SECURITY_GROUP);
     }
 
-    private void initializeConnTrackTable(DeviceId deviceId, boolean install) {
+    private void initializeProviderConnTrackTable(DeviceId deviceId, boolean install) {
+        initializeConnTrackTable(deviceId, ACL_CT_TABLE, FORWARDING_TABLE, install);
+    }
+
+    private void initializeTenantConnTrackTable(DeviceId deviceId, boolean install) {
+        initializeConnTrackTable(deviceId, TENANT_ACL_CT_TABLE, TENANT_FORWARDING_TABLE, install);
+    }
+
+    private void initializeConnTrackTable(DeviceId deviceId, int ctTable,
+                                            int forwardTable, boolean install) {
 
         // table={ACL_INGRESS_TABLE(44)},ip,ct_state=-trk, actions=ct(table:{ACL_CT_TABLE(45)})
         long ctState = computeCtStateFlag(false, false, false);
         long ctMask = computeCtMaskFlag(true, false, false);
-        setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) TENANT_ACL_CT_TABLE,
+        setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, (short) ctTable,
                 ACTION_NONE, PRIORITY_CT_HOOK_RULE, install);
 
         //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+est,action=goto_table:{NORMAL_TABLE(80)}
         ctState = computeCtStateFlag(true, false, true);
         ctMask = computeCtMaskFlag(true, false, true);
         setConnTrackRule(deviceId, ctState, ctMask, CT_NO_COMMIT, CT_NO_RECIRC,
-                TENANT_FORWARDING_TABLE, PRIORITY_CT_RULE, install);
+                forwardTable, PRIORITY_CT_RULE, install);
 
         //table={ACL_CT_TABLE(45)},ip,nw_dst=10.10.0.2,ct_state=+trk+new,action=drop
         ctState = computeCtStateFlag(true, true, false);
@@ -281,7 +293,23 @@
                 ACTION_DROP, PRIORITY_CT_DROP_RULE, install);
     }
 
-    private void initializeAclTable(DeviceId deviceId, boolean install) {
+    private void initializeProviderAclTable(KubevirtNode node,
+                                            DeviceId deviceId, boolean install) {
+        // FIXME: we need to use group table to multi-cast traffic to all
+        // physPatchPorts later, we only choose one of the physPatchPorts to
+        // stream the outbound traffic for now
+        node.physPatchPorts().stream().findFirst().ifPresent(p ->
+                    initializeAclTable(deviceId, ACL_RECIRC_TABLE, p, install));
+    }
+
+    private void initializeTenantAclTable(KubevirtNetwork network,
+                                            DeviceId deviceId, boolean install) {
+        PortNumber patchPort = network.tenantToTunnelPort(deviceId);
+        initializeAclTable(deviceId, TENANT_ACL_RECIRC_TABLE, patchPort, install);
+    }
+
+    private void initializeAclTable(DeviceId deviceId, int recircTable,
+                                    PortNumber outport, boolean install) {
 
         ExtensionTreatment ctTreatment =
                 niciraConnTrackTreatmentBuilder(driverService, deviceId)
@@ -293,33 +321,70 @@
 
         TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
         tBuilder.extension(ctTreatment, deviceId)
-                .transition(TENANT_FORWARDING_TABLE);
+                .setOutput(outport);
 
         flowRuleService.setRule(appId,
                 deviceId,
                 sBuilder.build(),
                 tBuilder.build(),
                 PRIORITY_ACL_INGRESS_RULE,
-                TENANT_ACL_RECIRC_TABLE,
+                recircTable,
                 install);
     }
 
-    private void initializeEgressTable(DeviceId deviceId, boolean install) {
+    private void initializeProviderEgressTable(DeviceId deviceId, boolean install) {
+        initializeEgressTable(deviceId, ACL_EGRESS_TABLE, FORWARDING_TABLE, install);
+    }
+
+    private void initializeTenantEgressTable(DeviceId deviceId, boolean install) {
+        initializeEgressTable(deviceId, TENANT_ACL_EGRESS_TABLE, TENANT_FORWARDING_TABLE, install);
+    }
+
+    private void initializeEgressTable(DeviceId deviceId, int egressTable,
+                                        int forwardTable, boolean install) {
         if (install) {
             flowRuleService.setUpTableMissEntry(deviceId, TENANT_ACL_EGRESS_TABLE);
         } else {
-            flowRuleService.connectTables(deviceId, TENANT_ACL_EGRESS_TABLE, TENANT_FORWARDING_TABLE);
+            flowRuleService.connectTables(deviceId, egressTable, forwardTable);
         }
     }
 
-    private void initializeIngressTable(DeviceId deviceId, boolean install) {
+    private void initializeProviderIngressTable(DeviceId deviceId, boolean install) {
+        initializeIngressTable(deviceId, ACL_INGRESS_TABLE, FORWARDING_TABLE, install);
+    }
+
+    private void initializeTenantIngressTable(DeviceId deviceId, boolean install) {
+        initializeIngressTable(deviceId, TENANT_ACL_INGRESS_TABLE, TENANT_FORWARDING_TABLE, install);
+    }
+
+    private void initializeIngressTable(DeviceId deviceId, int ingressTable,
+                                        int forwardTable, boolean install) {
         if (install) {
-            flowRuleService.setUpTableMissEntry(deviceId, TENANT_ACL_INGRESS_TABLE);
+            flowRuleService.setUpTableMissEntry(deviceId, ingressTable);
         } else {
-            flowRuleService.connectTables(deviceId, TENANT_ACL_INGRESS_TABLE, TENANT_FORWARDING_TABLE);
+            flowRuleService.connectTables(deviceId, ingressTable, forwardTable);
         }
     }
 
+    private void initializeProviderPipeline(KubevirtNode node, boolean install) {
+        initializeProviderIngressTable(node.intgBridge(), install);
+        initializeProviderEgressTable(node.intgBridge(), install);
+        initializeProviderConnTrackTable(node.intgBridge(), install);
+        initializeProviderAclTable(node, node.intgBridge(), install);
+    }
+
+    private void initializeTenantPipeline(KubevirtNetwork network,
+                                          KubevirtNode node, boolean install) {
+        DeviceId deviceId = network.tenantDeviceId(node.hostname());
+        if (deviceId == null) {
+            return;
+        }
+        initializeTenantIngressTable(deviceId, install);
+        initializeTenantEgressTable(deviceId, install);
+        initializeTenantConnTrackTable(deviceId, install);
+        initializeTenantAclTable(network, deviceId, install);
+    }
+
     private void updateSecurityGroupRule(KubevirtPort port,
                                          KubevirtSecurityGroupRule sgRule, boolean install) {
 
@@ -384,10 +449,12 @@
 
         DeviceId deviceId = port.isTenant() ? port.tenantDeviceId() : port.deviceId();
 
-        Set<TrafficSelector> selectors = buildSelectors(sgRule,
+        Set<TrafficSelector> ctSelectors = buildSelectors(
+                sgRule,
                 Ip4Address.valueOf(port.ipAddress().toInetAddress()),
+                port.macAddress(),
                 remoteIp, port.networkId());
-        if (selectors == null || selectors.isEmpty()) {
+        if (ctSelectors == null || ctSelectors.isEmpty()) {
             return;
         }
 
@@ -405,18 +472,32 @@
 
         TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
 
+        KubevirtNetwork net = networkService.network(port.networkId());
+
         int aclTable;
         if (sgRule.direction().equalsIgnoreCase(EGRESS)) {
-            aclTable = TENANT_ACL_EGRESS_TABLE;
+
+            if (net.type() == FLAT || net.type() == VLAN) {
+                aclTable = ACL_EGRESS_TABLE;
+            } else {
+                aclTable = TENANT_ACL_EGRESS_TABLE;
+            }
+
             tBuilder.transition(TENANT_ACL_RECIRC_TABLE);
         } else {
-            aclTable = TENANT_ACL_INGRESS_TABLE;
+
+            if (net.type() == FLAT || net.type() == VLAN) {
+                aclTable = ACL_INGRESS_TABLE;
+            } else {
+                aclTable = TENANT_ACL_INGRESS_TABLE;
+            }
+
             tBuilder.extension(ctTreatment, deviceId)
                     .transition(TENANT_FORWARDING_TABLE);
         }
 
         int finalAclTable = aclTable;
-        selectors.forEach(selector -> {
+        ctSelectors.forEach(selector -> {
             flowRuleService.setRule(appId,
                     deviceId,
                     selector, tBuilder.build(),
@@ -424,6 +505,23 @@
                     finalAclTable,
                     install);
         });
+
+        TrafficSelector tSelector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchEthDst(port.macAddress())
+                        .matchIPDst(IpPrefix.valueOf(port.ipAddress(), 32))
+                        .build();
+        TrafficTreatment tTreatment = DefaultTrafficTreatment.builder()
+                        .transition(TENANT_ACL_INGRESS_TABLE)
+                        .build();
+
+        flowRuleService.setRule(appId,
+                    deviceId,
+                    tSelector,
+                    tTreatment,
+                    PRIORITY_ACL_RULE,
+                    TENANT_ACL_RECIRC_TABLE,
+                    install);
     }
 
     /**
@@ -512,6 +610,7 @@
 
     private Set<TrafficSelector> buildSelectors(KubevirtSecurityGroupRule sgRule,
                                                 Ip4Address vmIp,
+                                                MacAddress vmMac,
                                                 IpPrefix remoteIp,
                                                 String netId) {
         if (remoteIp != null && remoteIp.equals(IpPrefix.valueOf(vmIp, VM_IP_PREFIX))) {
@@ -529,7 +628,7 @@
             portRangeMatchMap.forEach((key, value) -> {
 
                 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-                buildMatches(sBuilder, sgRule, vmIp, remoteIp, netId);
+                buildMatches(sBuilder, sgRule, vmIp, vmMac, remoteIp);
 
                 if (sgRule.protocol().equalsIgnoreCase(PROTO_TCP) ||
                         sgRule.protocol().equals(PROTO_TCP_NUM)) {
@@ -583,7 +682,7 @@
         } else {
 
             TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
-            buildMatches(sBuilder, sgRule, vmIp, remoteIp, netId);
+            buildMatches(sBuilder, sgRule, vmIp, vmMac, remoteIp);
 
             selectorSet.add(sBuilder.build());
         }
@@ -593,10 +692,9 @@
 
     private void buildMatches(TrafficSelector.Builder sBuilder,
                               KubevirtSecurityGroupRule sgRule, Ip4Address vmIp,
-                              IpPrefix remoteIp, String netId) {
-        buildTunnelId(sBuilder, netId);
+                              MacAddress vmMac, IpPrefix remoteIp) {
         buildMatchEthType(sBuilder, sgRule.etherType());
-        buildMatchDirection(sBuilder, sgRule.direction(), vmIp);
+        buildMatchDirection(sBuilder, sgRule.direction(), vmIp, vmMac);
         buildMatchProto(sBuilder, sgRule.protocol());
         buildMatchPort(sBuilder, sgRule.protocol(), sgRule.direction(),
                 sgRule.portRangeMin() == null ? 0 : sgRule.portRangeMin(),
@@ -606,36 +704,16 @@
         buildMatchRemoteIp(sBuilder, remoteIp, sgRule.direction());
     }
 
-    private void buildTunnelId(TrafficSelector.Builder sBuilder, String netId) {
-        KubevirtNetwork network = networkService.network(netId);
-
-        if (network == null) {
-            log.warn("Network {} not found!", netId);
-            return;
-        }
-
-        String segId = network.segmentId();
-        Type netType = network.type();
-
-        if (netType == VLAN) {
-            sBuilder.matchVlanId(VlanId.vlanId(segId));
-        } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
-            // sBuilder.matchTunnelId(Long.parseLong(segId));
-            log.trace("{} typed match rules are installed for security group", netType);
-        } else {
-            log.debug("Cannot tag the VID as it is unsupported vnet type {}", netType);
-        }
-
-
-    }
-
     private void buildMatchDirection(TrafficSelector.Builder sBuilder,
                                      String direction,
-                                     Ip4Address vmIp) {
+                                     Ip4Address vmIp,
+                                     MacAddress vmMac) {
         if (direction.equalsIgnoreCase(EGRESS)) {
             sBuilder.matchIPSrc(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
+            sBuilder.matchEthSrc(vmMac);
         } else {
             sBuilder.matchIPDst(IpPrefix.valueOf(vmIp, VM_IP_PREFIX));
+            sBuilder.matchEthDst(vmMac);
         }
     }
 
@@ -735,16 +813,10 @@
 
         if (getUseSecurityGroupFlag()) {
             nodeService.completeNodes(WORKER).forEach(node -> {
-                initializeEgressTable(node.intgBridge(), true);
-                initializeConnTrackTable(node.intgBridge(), true);
-                initializeAclTable(node.intgBridge(), true);
-                initializeIngressTable(node.intgBridge(), true);
+                initializeProviderPipeline(node, true);
 
                 for (KubevirtNetwork network : networkService.tenantNetworks()) {
-                    initializeEgressTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeIngressTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeConnTrackTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeAclTable(network.tenantDeviceId(node.hostname()), true);
+                    initializeTenantPipeline(network, node, true);
                 }
             });
 
@@ -752,16 +824,10 @@
                     securityGroup.rules().forEach(this::securityGroupRuleAdded));
         } else {
             nodeService.completeNodes(WORKER).forEach(node -> {
-                initializeEgressTable(node.intgBridge(), false);
-                initializeConnTrackTable(node.intgBridge(), false);
-                initializeAclTable(node.intgBridge(), false);
-                initializeIngressTable(node.intgBridge(), false);
+                initializeProviderPipeline(node, false);
 
                 for (KubevirtNetwork network : networkService.tenantNetworks()) {
-                    initializeEgressTable(network.tenantDeviceId(node.hostname()), false);
-                    initializeIngressTable(network.tenantDeviceId(node.hostname()), false);
-                    initializeConnTrackTable(network.tenantDeviceId(node.hostname()), false);
-                    initializeAclTable(network.tenantDeviceId(node.hostname()), false);
+                    initializeTenantPipeline(network, node, false);
                 }
             });
 
@@ -901,7 +967,7 @@
                     updateSecurityGroupRule(event.subject(), sgRule, true);
                 });
                 log.info("Added security group {} to port {}",
-                        event.securityGroupId(), event.subject().macAddress());
+                        sg.id(), event.subject().macAddress());
             }
         }
     }
@@ -944,10 +1010,7 @@
                 }
 
                 for (KubevirtNode node : nodes) {
-                    initializeEgressTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeIngressTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeConnTrackTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeAclTable(network.tenantDeviceId(node.hostname()), true);
+                    initializeTenantPipeline(network, node, true);
                 }
             }
         }
@@ -1027,37 +1090,32 @@
                 return;
             }
 
+            // FIXME: we wait all port get its deviceId updated
+            try {
+                sleep(SLEEP_MS);
+            } catch (InterruptedException e) {
+                log.error("Failed to install security group default rules.");
+            }
+
             resetSecurityGroupRulesByNode(node);
         }
 
         private void resetSecurityGroupRulesByNode(KubevirtNode node) {
             if (getUseSecurityGroupFlag()) {
-                initializeEgressTable(node.intgBridge(), true);
-                initializeConnTrackTable(node.intgBridge(), true);
-                initializeAclTable(node.intgBridge(), true);
-                initializeIngressTable(node.intgBridge(), true);
+                initializeProviderPipeline(node, true);
 
                 for (KubevirtNetwork network : networkService.tenantNetworks()) {
-                    initializeEgressTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeIngressTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeConnTrackTable(network.tenantDeviceId(node.hostname()), true);
-                    initializeAclTable(network.tenantDeviceId(node.hostname()), true);
+                    initializeTenantPipeline(network, node, true);
                 }
 
                 securityGroupService.securityGroups().forEach(securityGroup ->
                         securityGroup.rules().forEach(
                                 KubevirtSecurityGroupHandler.this::securityGroupRuleAdded));
             } else {
-                initializeEgressTable(node.intgBridge(), false);
-                initializeConnTrackTable(node.intgBridge(), false);
-                initializeAclTable(node.intgBridge(), false);
-                initializeIngressTable(node.intgBridge(), false);
+                initializeProviderPipeline(node, false);
 
                 for (KubevirtNetwork network : networkService.tenantNetworks()) {
-                    initializeEgressTable(network.tenantDeviceId(node.hostname()), false);
-                    initializeIngressTable(network.tenantDeviceId(node.hostname()), false);
-                    initializeConnTrackTable(network.tenantDeviceId(node.hostname()), false);
-                    initializeAclTable(network.tenantDeviceId(node.hostname()), false);
+                    initializeTenantPipeline(network, node, false);
                 }
 
                 securityGroupService.securityGroups().forEach(securityGroup ->
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSwitchingPhysicalHandler.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSwitchingPhysicalHandler.java
index c8089fb..9d9757d 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSwitchingPhysicalHandler.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/KubevirtSwitchingPhysicalHandler.java
@@ -47,10 +47,10 @@
 
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.kubevirtnetworking.api.Constants.ACL_INGRESS_TABLE;
+import static org.onosproject.kubevirtnetworking.api.Constants.ARP_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.KUBEVIRT_NETWORKING_APP_ID;
-import static org.onosproject.kubevirtnetworking.api.Constants.PRE_FLAT_TABLE;
 import static org.onosproject.kubevirtnetworking.api.Constants.PRIORITY_FORWARDING_RULE;
-import static org.onosproject.kubevirtnetworking.api.Constants.VTAG_TABLE;
 import static org.onosproject.kubevirtnetworking.util.KubevirtNetworkingUtil.structurePortName;
 import static org.onosproject.kubevirtnode.api.Constants.INTEGRATION_TO_PHYSICAL_PREFIX;
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
@@ -107,14 +107,14 @@
         return intPatchPorts.contains(portName);
     }
 
-    private void setFlatJumpRuleForPatchPort(DeviceId deviceId,
-                                             PortNumber portNumber,
-                                             boolean install) {
+    private void setIngressRuleForPatchPort(DeviceId deviceId,
+                                            PortNumber portNumber,
+                                            boolean install) {
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder()
                 .matchInPort(portNumber);
 
         TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
-                .transition(PRE_FLAT_TABLE);
+                .transition(ACL_INGRESS_TABLE);
 
         flowRuleService.setRule(
                 appId,
@@ -122,7 +122,7 @@
                 selector.build(),
                 treatment.build(),
                 PRIORITY_FORWARDING_RULE,
-                VTAG_TABLE,
+                ARP_TABLE,
                 install);
     }
 
@@ -168,14 +168,14 @@
             if (!isRelevantHelper(event)) {
                 return;
             }
-            setFlatJumpRuleForPatchPort(event.subject().id(),
+            setIngressRuleForPatchPort(event.subject().id(),
                     event.port().number(), true);
         }
         private void processPortRemoval(DeviceEvent event) {
             if (!isRelevantHelper(event)) {
                 return;
             }
-            setFlatJumpRuleForPatchPort(event.subject().id(),
+            setIngressRuleForPatchPort(event.subject().id(),
                     event.port().number(), false);
         }
     }
diff --git a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/DefaultKubevirtNode.java b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/DefaultKubevirtNode.java
index 2b0c8f8..f647503 100644
--- a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/DefaultKubevirtNode.java
+++ b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/DefaultKubevirtNode.java
@@ -26,12 +26,15 @@
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Objects;
+import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static org.onosproject.kubevirtnode.api.Constants.DEFAULT_CLUSTER_NAME;
 import static org.onosproject.kubevirtnode.api.Constants.GENEVE;
 import static org.onosproject.kubevirtnode.api.Constants.GRE;
+import static org.onosproject.kubevirtnode.api.Constants.INTEGRATION_TO_PHYSICAL_PREFIX;
 import static org.onosproject.kubevirtnode.api.Constants.VXLAN;
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 
@@ -42,6 +45,7 @@
 
     private static final String NOT_NULL_MSG = "Node % cannot be null";
     private static final String OVSDB = "ovsdb:";
+    private static final int PORT_NAME_MAX_LENGTH = 15;
 
     private final String clusterName;
     private final String hostname;
@@ -189,6 +193,20 @@
     }
 
     @Override
+    public Set<PortNumber> physPatchPorts() {
+        Set<PortNumber> portNumbers = new HashSet<>();
+        for (KubevirtPhyInterface phyIntf : this.phyIntfs()) {
+            String portName = structurePortName(
+                    INTEGRATION_TO_PHYSICAL_PREFIX + phyIntf.network());
+            PortNumber portNumber = patchPort(portName);
+            if (portNumber != null) {
+                portNumbers.add(portNumber);
+            }
+        }
+        return portNumbers;
+    }
+
+    @Override
     public PortNumber vxlanPort() {
         return tunnelPort(VXLAN);
     }
@@ -220,6 +238,32 @@
         return port != null ? port.number() : null;
     }
 
+    private PortNumber patchPort(String portName) {
+        DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
+        Port port = deviceService.getPorts(intgBridge).stream()
+                .filter(p -> p.isEnabled() &&
+                        Objects.equals(p.annotations().value(PORT_NAME), portName))
+                .findAny().orElse(null);
+        return port != null ? port.number() : null;
+    }
+
+    /**
+     * Re-structures the OVS port name.
+     * The length of OVS port name should be not large than 15.
+     *
+     * @param portName  original port name
+     * @return re-structured OVS port name
+     */
+    private String structurePortName(String portName) {
+
+        // The size of OVS port name should not be larger than 15
+        if (portName.length() > PORT_NAME_MAX_LENGTH) {
+            return StringUtils.substring(portName, 0, PORT_NAME_MAX_LENGTH);
+        }
+
+        return portName;
+    }
+
     /**
      * Returns new builder instance.
      *
diff --git a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtNode.java b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtNode.java
index 90d3400..f4aac55 100644
--- a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtNode.java
+++ b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtNode.java
@@ -20,6 +20,7 @@
 import org.onosproject.net.PortNumber;
 
 import java.util.Collection;
+import java.util.Set;
 
 /**
  * Representation of a KubeVirt node used in kubevirt networking service.
@@ -141,6 +142,13 @@
     Collection<KubevirtPhyInterface> phyIntfs();
 
     /**
+     * Returns a set of integration to physnet patch port number.
+     *
+     * @return a set of patch port numbers
+     */
+    Set<PortNumber> physPatchPorts();
+
+    /**
      * Returns the VXLAN tunnel port.
      *
      * @return VXLAN port number; null if tunnel port does not exist
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/DefaultKubevirtNodeHandler.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/DefaultKubevirtNodeHandler.java
index 86fa27d..e7d3613 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/DefaultKubevirtNodeHandler.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/DefaultKubevirtNodeHandler.java
@@ -124,7 +124,6 @@
     private static final long SLEEP_SHORT_MS = 1000; // we wait 1s
     private static final long SLEEP_MID_MS = 2000; // we wait 2s
     private static final long SLEEP_LONG_MS = 5000; // we wait 5s
-    private static final IpAddress DNS_SERVER_IP = IpAddress.valueOf("169.254.25.10");
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected CoreService coreService;