Support inter-node routing for k8s passthrough use case

Change-Id: I64411d8b20c7d501603eda5cd44d0aa7c47c99c7
(cherry picked from commit c9d0d7088439fedac8c255172a321f323433bcfc)
diff --git a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/Constants.java b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/Constants.java
index ecec966..3731936 100644
--- a/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/Constants.java
+++ b/apps/k8s-networking/api/src/main/java/org/onosproject/k8snetworking/api/Constants.java
@@ -88,6 +88,7 @@
     public static final int PRIORITY_CT_DROP_RULE = 32500;
     public static final int PRIORITY_NAT_RULE = 30000;
     public static final int PRIORITY_GATEWAY_RULE = 31000;
+    public static final int PRIORITY_INTER_NODE_RULE = 33000;
     public static final int PRIORITY_LOCAL_BRIDGE_RULE = 32000;
     public static final int PRIORITY_SWITCHING_RULE = 30000;
     public static final int PRIORITY_CIDR_RULE = 30000;
diff --git a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sSwitchingGatewayHandler.java b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sSwitchingGatewayHandler.java
index dde6828..3efe41b 100644
--- a/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sSwitchingGatewayHandler.java
+++ b/apps/k8s-networking/app/src/main/java/org/onosproject/k8snetworking/impl/K8sSwitchingGatewayHandler.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.k8snetworking.impl;
 
+import org.apache.commons.lang.StringUtils;
 import org.onlab.packet.ARP;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.Ip4Address;
@@ -29,6 +30,8 @@
 import org.onosproject.k8snetworking.api.K8sNetworkEvent;
 import org.onosproject.k8snetworking.api.K8sNetworkListener;
 import org.onosproject.k8snetworking.api.K8sNetworkService;
+import org.onosproject.k8snode.api.K8sHost;
+import org.onosproject.k8snode.api.K8sHostService;
 import org.onosproject.k8snode.api.K8sNode;
 import org.onosproject.k8snode.api.K8sNodeEvent;
 import org.onosproject.k8snode.api.K8sNodeListener;
@@ -51,6 +54,7 @@
 import org.slf4j.Logger;
 
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
@@ -62,6 +66,7 @@
 import static org.onosproject.k8snetworking.api.Constants.LOCAL_ENTRY_TABLE;
 import static org.onosproject.k8snetworking.api.Constants.PRIORITY_ARP_REPLY_RULE;
 import static org.onosproject.k8snetworking.api.Constants.PRIORITY_GATEWAY_RULE;
+import static org.onosproject.k8snetworking.api.Constants.PRIORITY_INTER_NODE_RULE;
 import static org.onosproject.k8snetworking.api.Constants.PRIORITY_LOCAL_BRIDGE_RULE;
 import static org.onosproject.k8snetworking.api.Constants.ROUTING_TABLE;
 import static org.onosproject.k8snetworking.api.Constants.SHIFTED_IP_PREFIX;
@@ -116,6 +121,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY)
     protected K8sNodeService k8sNodeService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected K8sHostService k8sHostService;
+
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler"));
     private final InternalK8sNetworkListener k8sNetworkListener =
@@ -218,6 +226,52 @@
         }
     }
 
+    private void setInterNodeRoutingRules(K8sNetwork k8sNetwork, boolean install) {
+        K8sNode srcNode = k8sNodeService.node(k8sNetwork.name());
+
+        if (srcNode == null) {
+            return;
+        }
+
+        for (K8sNode dstNode : k8sNodeService.completeNodes()) {
+            if (StringUtils.equals(srcNode.hostname(), dstNode.hostname())) {
+                continue;
+            }
+
+            boolean sameHost = false;
+            for (K8sHost host : k8sHostService.completeHosts()) {
+                Set<String> nodeNames = host.nodeNames();
+                // if the src and dst nodes located in the same hosts,
+                // we simply do not tunnel the traffic, instead we route the traffic
+                if (nodeNames.contains(srcNode.hostname()) &&
+                        nodeNames.contains(dstNode.hostname())) {
+                    sameHost = true;
+                }
+            }
+
+            if (sameHost) {
+                TrafficSelector selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchIPSrc(IpPrefix.valueOf(srcNode.podCidr()))
+                        .matchIPDst(IpPrefix.valueOf(dstNode.podCidr()))
+                        .build();
+
+                TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                        .setOutput(dstNode.tunToIntgPortNum())
+                        .build();
+
+                k8sFlowRuleService.setRule(
+                        appId,
+                        dstNode.tunBridge(),
+                        selector,
+                        treatment,
+                        PRIORITY_INTER_NODE_RULE,
+                        TUN_ENTRY_TABLE,
+                        install);
+            }
+        }
+    }
+
     private void setLocalBridgeRules(K8sNetwork k8sNetwork, boolean install) {
         for (K8sNode node : k8sNodeService.completeNodes()) {
             if (node.hostname().equals(k8sNetwork.name())) {
@@ -338,6 +392,7 @@
             setGatewayRule(event.subject(), true);
             setLocalBridgeRules(event.subject(), true);
             setLocalBridgeArpRules(event.subject(), true);
+            setInterNodeRoutingRules(event.subject(), true);
         }
 
         private void processNetworkRemoval(K8sNetworkEvent event) {
@@ -348,6 +403,7 @@
             setGatewayRule(event.subject(), false);
             setLocalBridgeRules(event.subject(), false);
             setLocalBridgeArpRules(event.subject(), false);
+            setInterNodeRoutingRules(event.subject(), false);
         }
     }
 
@@ -378,6 +434,7 @@
             k8sNetworkService.networks().forEach(n -> setGatewayRule(n, true));
             k8sNetworkService.networks().forEach(n -> setLocalBridgeRules(n, true));
             k8sNetworkService.networks().forEach(n -> setLocalBridgeArpRules(n, true));
+            k8sNetworkService.networks().forEach(n -> setInterNodeRoutingRules(n, true));
         }
     }
 }