Inter-connect k8s and openstack intg bridge, kbr-ex and kbr-router

Change-Id: Id7d3c874e8b267252ca387b1ca6f67b9f9bc5116
diff --git a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/cli/K8sHostListCommand.java b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/cli/K8sHostListCommand.java
index fa996ba..010fcc1 100644
--- a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/cli/K8sHostListCommand.java
+++ b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/cli/K8sHostListCommand.java
@@ -24,6 +24,7 @@
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.k8snode.api.K8sHost;
 import org.onosproject.k8snode.api.K8sHostService;
+import org.onosproject.k8snode.api.K8sRouterBridge;
 import org.onosproject.k8snode.api.K8sTunnelBridge;
 
 import java.util.Comparator;
@@ -42,8 +43,8 @@
 public class K8sHostListCommand extends AbstractShellCommand {
 
     private static final int HOST_IP_LENGTH = 15;
-    private static final int NODES_LENGTH = 40;
     private static final int TUNBRS_LENGTH = 40;
+    private static final int RTRBRS_LENGTH = 40;
     private static final int STATUS_LENGTH = 15;
 
     @Override
@@ -53,18 +54,19 @@
         hosts.sort(Comparator.comparing(K8sHost::hostIp));
 
         String format = genFormatString(
-                ImmutableList.of(HOST_IP_LENGTH, NODES_LENGTH, TUNBRS_LENGTH, STATUS_LENGTH));
+                ImmutableList.of(HOST_IP_LENGTH, TUNBRS_LENGTH, RTRBRS_LENGTH, STATUS_LENGTH));
 
         if (outputJson()) {
             print("%s", json(hosts));
         } else {
-            print(format, "Host IP", "Nodes", "Tunnel Bridges", "State");
+            print(format, "Host IP", "Tunnel Bridges", "Router Bridges", "State");
             for (K8sHost host : hosts) {
                 print(format,
                         host.hostIp().toString(),
-                        host.nodeNames().toString(),
                         host.tunBridges().stream().map(K8sTunnelBridge::name)
                                 .collect(Collectors.toSet()).toString(),
+                        host.routerBridges().stream().map(K8sRouterBridge::name)
+                                .collect(Collectors.toSet()).toString(),
                         host.state().toString());
             }
             print("Total %s hosts", hosts.size());
diff --git a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sApiConfigHandler.java b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sApiConfigHandler.java
index cf78b6e..bf81f85a 100644
--- a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sApiConfigHandler.java
+++ b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sApiConfigHandler.java
@@ -39,6 +39,7 @@
 import org.onosproject.k8snode.api.K8sHostState;
 import org.onosproject.k8snode.api.K8sNode;
 import org.onosproject.k8snode.api.K8sNodeAdminService;
+import org.onosproject.k8snode.api.K8sRouterBridge;
 import org.onosproject.k8snode.api.K8sTunnelBridge;
 import org.osgi.service.component.annotations.Activate;
 import org.osgi.service.component.annotations.Component;
@@ -186,12 +187,14 @@
 
     private K8sHost buildK8sHost(HostNodesInfo hostNodesInfo, K8sApiConfig config) {
         int segmentId = config.segmentId();
-        K8sTunnelBridge bridge = new K8sTunnelBridge(segmentId);
+        K8sTunnelBridge tBridge = new K8sTunnelBridge(segmentId);
+        K8sRouterBridge rBridge = new K8sRouterBridge(segmentId);
 
         return DefaultK8sHost.builder()
                 .hostIp(hostNodesInfo.hostIp())
                 .state(K8sHostState.INIT)
-                .tunBridges(ImmutableSet.of(bridge))
+                .tunBridges(ImmutableSet.of(tBridge))
+                .routerBridges(ImmutableSet.of(rBridge))
                 .nodeNames(hostNodesInfo.nodes())
                 .build();
     }
diff --git a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sHostHandler.java b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sHostHandler.java
index 5da9624..3827e21 100644
--- a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sHostHandler.java
+++ b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sHostHandler.java
@@ -20,6 +20,7 @@
 import org.onosproject.cluster.NodeId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.k8snode.api.K8sBridge;
 import org.onosproject.k8snode.api.K8sHost;
 import org.onosproject.k8snode.api.K8sHostAdminService;
 import org.onosproject.k8snode.api.K8sHostEvent;
@@ -28,6 +29,7 @@
 import org.onosproject.k8snode.api.K8sHostState;
 import org.onosproject.k8snode.api.K8sNode;
 import org.onosproject.k8snode.api.K8sNodeAdminService;
+import org.onosproject.k8snode.api.K8sRouterBridge;
 import org.onosproject.k8snode.api.K8sTunnelBridge;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
@@ -68,6 +70,7 @@
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.k8snode.api.Constants.GENEVE;
 import static org.onosproject.k8snode.api.Constants.GRE;
+import static org.onosproject.k8snode.api.Constants.OS_INTEGRATION_BRIDGE;
 import static org.onosproject.k8snode.api.Constants.VXLAN;
 import static org.onosproject.k8snode.api.K8sHostState.COMPLETE;
 import static org.onosproject.k8snode.api.K8sHostState.DEVICE_CREATED;
@@ -163,6 +166,12 @@
                 createBridge(k8sHost.ovsdb(), tunBridge);
             }
         }
+
+        for (K8sRouterBridge routerBridge : k8sHost.routerBridges()) {
+            if (!deviceService.isAvailable(routerBridge.deviceId())) {
+                createBridge(k8sHost.ovsdb(), routerBridge);
+            }
+        }
     }
 
     @Override
@@ -178,7 +187,8 @@
                 for (String node : k8sHost.nodeNames()) {
                     K8sNode k8sNode = k8sNodeAdminService.node(node);
                     if (k8sNode.segmentId() == bridge.tunnelId()) {
-                        createPatchInterfaces(k8sHost.ovsdb(), bridge, k8sNode);
+                        createTunnelPatchInterfaces(k8sHost.ovsdb(), bridge, k8sNode);
+                        createInterPatchInterfaces(k8sHost.ovsdb(), k8sNode);
                     }
                 }
             }
@@ -197,6 +207,16 @@
                     createGeneveTunnelInterface(k8sHost.ovsdb(), bridge);
                 }
             }
+
+            // create patch ports into router bridge face to external bridge
+            for (K8sRouterBridge bridge : k8sHost.routerBridges()) {
+                for (String node : k8sHost.nodeNames()) {
+                    K8sNode k8sNode = k8sNodeAdminService.node(node);
+                    if (k8sNode.segmentId() == bridge.segmentId()) {
+                        createRouterPatchInterfaces(k8sHost.ovsdb(), bridge, k8sNode);
+                    }
+                }
+            }
         } catch (Exception e) {
             log.error("Exception occurred because of {}", e);
         }
@@ -212,7 +232,7 @@
         // do something if needed
     }
 
-    private void createBridge(DeviceId ovsdb, K8sTunnelBridge bridge) {
+    private void createBridge(DeviceId ovsdb, K8sBridge bridge) {
         Device device = deviceService.getDevice(ovsdb);
 
         List<ControllerInfo> controllers = clusterService.getNodes().stream()
@@ -232,7 +252,7 @@
         bridgeConfig.addBridge(builder.build());
     }
 
-    private void createPatchInterfaces(DeviceId ovsdb, K8sTunnelBridge bridge, K8sNode k8sNode) {
+    private void createTunnelPatchInterfaces(DeviceId ovsdb, K8sBridge bridge, K8sNode k8sNode) {
         Device device = deviceService.getDevice(ovsdb);
         if (device == null || !device.is(InterfaceConfig.class)) {
             log.error("Failed to create patch interface on {}", ovsdb);
@@ -241,7 +261,7 @@
 
         InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
 
-        // tunnel bridge -> integration bridge
+        // tunnel bridge -> k8s integration bridge
         PatchDescription brTunIntPatchDesc =
                 DefaultPatchDescription.builder()
                         .deviceId(bridge.name())
@@ -252,6 +272,46 @@
         ifaceConfig.addPatchMode(k8sNode.tunToIntgPatchPortName(), brTunIntPatchDesc);
     }
 
+    private void createInterPatchInterfaces(DeviceId ovsdb, K8sNode k8sNode) {
+        Device device = deviceService.getDevice(ovsdb);
+        if (device == null || !device.is(InterfaceConfig.class)) {
+            log.error("Failed to create patch interface on {}", ovsdb);
+            return;
+        }
+
+        InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
+
+        // openstack integration bridge -> k8s integration bridge
+        PatchDescription osIntK8sIntPatchDesc =
+                DefaultPatchDescription.builder()
+                        .deviceId(OS_INTEGRATION_BRIDGE)
+                        .ifaceName(k8sNode.osToK8sIntgPatchPortName())
+                        .peer(k8sNode.k8sToOsIntgPatchPortName())
+                        .build();
+
+        ifaceConfig.addPatchMode(k8sNode.tunToIntgPatchPortName(), osIntK8sIntPatchDesc);
+    }
+
+    private void createRouterPatchInterfaces(DeviceId ovsdb, K8sBridge bridge, K8sNode k8sNode) {
+        Device device = deviceService.getDevice(ovsdb);
+        if (device == null || !device.is(InterfaceConfig.class)) {
+            log.error("Failed to create patch interface on {}", ovsdb);
+            return;
+        }
+
+        InterfaceConfig ifaceConfig = device.as(InterfaceConfig.class);
+
+        // router bridge -> external bridge
+        PatchDescription brRouterExtPatchDesc =
+                DefaultPatchDescription.builder()
+                        .deviceId(bridge.name())
+                        .ifaceName(k8sNode.routerToExtPatchPortName())
+                        .peer(k8sNode.extToRouterPatchPortName())
+                        .build();
+
+        ifaceConfig.addPatchMode(k8sNode.tunToIntgPatchPortName(), brRouterExtPatchDesc);
+    }
+
     private void createVxlanTunnelInterface(DeviceId ovsdb, K8sTunnelBridge bridge) {
         createTunnelInterface(ovsdb, bridge, VXLAN, bridge.vxlanPortName());
     }
@@ -356,12 +416,18 @@
             log.error("Exception caused during init state checking...");
         }
 
-        for (K8sTunnelBridge tunBridge : k8sHost.tunBridges()) {
+        for (K8sBridge tunBridge : k8sHost.tunBridges()) {
             if (!deviceService.isAvailable(tunBridge.deviceId())) {
                 return false;
             }
         }
 
+        for (K8sBridge routerBridge: k8sHost.routerBridges()) {
+            if (!deviceService.isAvailable(routerBridge.deviceId())) {
+                return false;
+            }
+        }
+
         return true;
     }
 
diff --git a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sNodeHandler.java b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sNodeHandler.java
index cec3d2c..62db27d 100644
--- a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sNodeHandler.java
+++ b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DefaultK8sNodeHandler.java
@@ -408,6 +408,24 @@
                             .build();
 
             ifaceConfig.addPatchMode(k8sNode.tunToIntgPatchPortName(), brTunIntPatchDesc);
+        } else {
+            // k8s integration bridge -> openstack integration bridge
+            PatchDescription k8sIntOsIntPatchDesc =
+                    DefaultPatchDescription.builder()
+                            .deviceId(k8sNode.intgBridgeName())
+                            .ifaceName(k8sNode.k8sToOsIntgPatchPortName())
+                            .peer(k8sNode.osToK8sIntgPatchPortName())
+                            .build();
+            ifaceConfig.addPatchMode(k8sNode.k8sToOsIntgPatchPortName(), k8sIntOsIntPatchDesc);
+
+            // external bridge -> router bridge
+            PatchDescription extRouterPatchDesc =
+                    DefaultPatchDescription.builder()
+                            .deviceId(k8sNode.extBridgeName())
+                            .ifaceName(k8sNode.extToRouterPatchPortName())
+                            .peer(k8sNode.routerToExtPatchPortName())
+                            .build();
+            ifaceConfig.addPatchMode(k8sNode.extToRouterPatchPortName(), extRouterPatchDesc);
         }
     }
 
diff --git a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DistributedK8sHostStore.java b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DistributedK8sHostStore.java
index 73dd7a4..360f2fa 100644
--- a/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DistributedK8sHostStore.java
+++ b/apps/k8s-node/app/src/main/java/org/onosproject/k8snode/impl/DistributedK8sHostStore.java
@@ -21,11 +21,13 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.k8snode.api.DefaultK8sHost;
+import org.onosproject.k8snode.api.K8sBridge;
 import org.onosproject.k8snode.api.K8sHost;
 import org.onosproject.k8snode.api.K8sHostEvent;
 import org.onosproject.k8snode.api.K8sHostState;
 import org.onosproject.k8snode.api.K8sHostStore;
 import org.onosproject.k8snode.api.K8sHostStoreDelegate;
+import org.onosproject.k8snode.api.K8sRouterBridge;
 import org.onosproject.k8snode.api.K8sTunnelBridge;
 import org.onosproject.store.AbstractStore;
 import org.onosproject.store.serializers.KryoNamespaces;
@@ -81,7 +83,9 @@
             .register(K8sHost.class)
             .register(DefaultK8sHost.class)
             .register(K8sHostState.class)
+            .register(K8sBridge.class)
             .register(K8sTunnelBridge.class)
+            .register(K8sRouterBridge.class)
             .register(Collection.class)
             .build();