Connects to all the physical bridges in Kubevirt Node app to deal with the case that the physical port is disabled.

Change-Id: I9706cd4b670fbbb7ffdaaa2924fb893c801b2253
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 00aa0bf..0850ba2 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
@@ -88,6 +88,7 @@
 import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_TO_INTEGRATION;
 import static org.onosproject.kubevirtnode.api.Constants.VXLAN;
 import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.GATEWAY;
+import static org.onosproject.kubevirtnode.api.KubevirtNode.Type.WORKER;
 import static org.onosproject.kubevirtnode.api.KubevirtNodeService.APP_ID;
 import static org.onosproject.kubevirtnode.api.KubevirtNodeState.COMPLETE;
 import static org.onosproject.kubevirtnode.api.KubevirtNodeState.DEVICE_CREATED;
@@ -585,18 +586,42 @@
                 log.error("Exception caused during init state checking...");
             }
 
-            String bridgeName = BRIDGE_PREFIX + phyIntf.network();
             String patchPortName = structurePortName(
                     INTEGRATION_TO_PHYSICAL_PREFIX + phyIntf.network());
 
-            if (!(hasPhyBridge(node, bridgeName) &&
-                    hasPhyPatchPort(node, patchPortName) &&
-                    hasPhyIntf(node, phyIntf.intf()))) {
-                log.warn("PhyBridge {}", hasPhyBridge(node, bridgeName));
-                log.warn("hasPhyPatchPort {}", hasPhyPatchPort(node, patchPortName));
-                log.warn("hasPhyIntf {}", hasPhyIntf(node, phyIntf.intf()));
-                return false;
+            if (node.type() == WORKER) {
+                String bridgeName = BRIDGE_PREFIX + phyIntf.network();
+                if (!(hasPhyBridge(node, bridgeName) &&
+                        hasPhyPatchPort(node, patchPortName) &&
+                        hasPhyIntf(node, phyIntf.intf()))) {
+                    log.warn("PhyBridge {}", hasPhyBridge(node, bridgeName));
+                    log.warn("hasPhyPatchPort {}", hasPhyPatchPort(node, patchPortName));
+                    log.warn("hasPhyIntf {}", hasPhyIntf(node, phyIntf.intf()));
+                    return false;
+                }
+            } else {
+                //In case node type is GATEWAY, we create physical bridges connected to the contoller.
+                //By doing so, ONOS immediately recognizes the status of physical interface and performs RM procedures.
+                Port phyIntfPort = deviceService.getPorts(phyIntf.physBridge()).stream()
+                        .filter(port -> port.annotations().value(PORT_NAME).equals(phyIntf.intf()))
+                        .findAny().orElse(null);
+                if (phyIntfPort == null) {
+                    log.warn("There's no connected physical port {} on physical device {}",
+                            phyIntf.intf(), phyIntf.physBridge());
+                }
+
+                if (!(deviceService.isAvailable(phyIntf.physBridge()) &&
+                        hasPhyPatchPort(node, patchPortName) &&
+                        hasPhyIntf(node, phyIntf.intf()) &&
+                        phyIntfPort.isEnabled())) {
+                    log.warn("PhysBridge {}", deviceService.isAvailable(phyIntf.physBridge()));
+                    log.warn("hasPhyPatchPort {}", hasPhyPatchPort(node, patchPortName));
+                    log.warn("hasPhyIntf {}", hasPhyIntf(node, phyIntf.intf()));
+                    log.warn("physical interface port {}", phyIntfPort.isEnabled());
+                    return false;
+                }
             }
+
         }
 
         if (node.type() == GATEWAY) {
@@ -610,6 +635,12 @@
         return true;
     }
 
+    private boolean hasPhyBridge(KubevirtNode node, String bridgeName) {
+        BridgeConfig bridgeConfig =
+                deviceService.getDevice(node.ovsdb()).as(BridgeConfig.class);
+        return bridgeConfig.getBridges().stream()
+                .anyMatch(br -> br.name().equals(bridgeName));
+    }
     /**
      * Configures the kubernetes node with new state.
      *
@@ -630,14 +661,21 @@
             String bridgeName = BRIDGE_PREFIX + pi.network();
             String patchPortName =
                     structurePortName(INTEGRATION_TO_PHYSICAL_PREFIX + pi.network());
-
-            if (!hasPhyBridge(node, bridgeName)) {
+            if (node.type() == WORKER && !hasPhyBridge(node, bridgeName)) {
                 createPhysicalBridge(node, pi);
                 createPhysicalPatchPorts(node, pi);
                 attachPhysicalPort(node, pi);
 
-                log.info("Creating physnet bridge {}", bridgeName);
-                log.info("Creating patch ports for physnet {}", bridgeName);
+                log.info("Creating physnet bridge {} for worker node {}", bridgeName, node.hostname());
+                log.info("Creating patch ports for physnet {} for worker node {}", bridgeName, node.hostname());
+
+            } else if (node.type() == GATEWAY && (!deviceService.isAvailable(pi.physBridge()))) {
+                createPhysicalBridgeWithConnectedMode(node, pi);
+                createPhysicalPatchPorts(node, pi);
+                attachPhysicalPort(node, pi);
+
+                log.info("Creating physnet bridge {} for gateway node {}", bridgeName, node.hostname());
+                log.info("Creating patch ports for physnet {} for gateway node {}", bridgeName, node.hostname());
             } else {
                 // in case physical bridge exists, but patch port is missing,
                 // we will add patch port to connect br-physnet with physical bridge
@@ -728,13 +766,6 @@
         });
     }
 
-    private boolean hasPhyBridge(KubevirtNode node, String bridgeName) {
-        BridgeConfig bridgeConfig =
-                deviceService.getDevice(node.ovsdb()).as(BridgeConfig.class);
-        return bridgeConfig.getBridges().stream()
-                .anyMatch(br -> br.name().equals(bridgeName));
-    }
-
     private boolean hasPhyPatchPort(KubevirtNode node, String patchPortName) {
         List<Port> ports = deviceService.getPorts(node.intgBridge());
         return ports.stream().anyMatch(p ->
@@ -762,6 +793,44 @@
         bridgeConfig.addBridge(builder.build());
     }
 
+    private void createPhysicalBridgeWithConnectedMode(KubevirtNode osNode,
+                                                       KubevirtPhyInterface phyInterface) {
+        Device device = deviceService.getDevice(osNode.ovsdb());
+        IpAddress controllerIp = apiConfigService.apiConfig().controllerIp();
+        String serviceFqdn = apiConfigService.apiConfig().serviceFqdn();
+        IpAddress serviceIp = null;
+
+        if (controllerIp == null) {
+            if (serviceFqdn != null) {
+                serviceIp = resolveHostname(serviceFqdn);
+            }
+
+            if (serviceIp != null) {
+                controllerIp = serviceIp;
+            } else {
+                controllerIp = apiConfigService.apiConfig().ipAddress();
+            }
+        }
+
+        ControllerInfo controlInfo = new ControllerInfo(controllerIp, DEFAULT_OFPORT, DEFAULT_OF_PROTO);
+        List<ControllerInfo> controllers = Lists.newArrayList(controlInfo);
+
+        String dpid = phyInterface.physBridge().toString().substring(DPID_BEGIN);
+
+        String bridgeName = BRIDGE_PREFIX + phyInterface.network();
+
+        BridgeDescription.Builder builder = DefaultBridgeDescription.builder()
+                .name(bridgeName)
+                .failMode(BridgeDescription.FailMode.SECURE)
+                .datapathId(dpid)
+                .mcastSnoopingEnable()
+                .disableInBand()
+                .controllers(controllers);
+
+        BridgeConfig bridgeConfig = device.as(BridgeConfig.class);
+        bridgeConfig.addBridge(builder.build());
+    }
+
     private void removePhysicalBridge(KubevirtNode node, String network) {
         Device device = deviceService.getDevice(node.ovsdb());
 
@@ -843,6 +912,17 @@
         addOrRemoveSystemInterface(node, physicalDeviceId, portName, deviceService, false);
     }
 
+    private KubevirtNode nodeByTunOrPhyBridge(DeviceId deviceId) {
+        KubevirtNode node = nodeAdminService.nodeByTunBridge(deviceId);
+        if (node == null) {
+            node = nodeAdminService.nodeByPhyBridge(deviceId);
+            if (node == null) {
+                return null;
+            }
+        }
+        return node;
+    }
+
     /**
      * An internal OVSDB listener. This listener is used for listening the
      * network facing events from OVSDB device. If a new OVSDB device is detected,
@@ -923,7 +1003,7 @@
                     break;
                 case PORT_UPDATED:
                 case PORT_ADDED:
-                    eventExecutor.execute(() -> processPortAddition(device, port));
+                    eventExecutor.execute(() -> processPortAdditionOrUpdate(device, port));
                     break;
                 case PORT_REMOVED:
                     eventExecutor.execute(() -> processPortRemoval(device, port));
@@ -962,12 +1042,12 @@
             }
         }
 
-        void processPortAddition(Device device, Port port) {
+        void processPortAdditionOrUpdate(Device device, Port port) {
             if (!isRelevantHelper()) {
                 return;
             }
 
-            KubevirtNode node = nodeAdminService.nodeByTunBridge(device.id());
+            KubevirtNode node = nodeByTunOrPhyBridge(device.id());
 
             if (node == null) {
                 return;
@@ -983,6 +1063,24 @@
                         portName, device.id());
                 bootstrapNode(node);
             }
+
+            //When the physical port is down, in the middle of normal operation, we set the node state to INCOMPLTE
+            //so that respective handlers do their related jobs.
+            if (node.state() == COMPLETE && node.type().equals(GATEWAY) && !port.isEnabled()) {
+                node.phyIntfs().stream()
+                        .filter(pi -> pi.intf().equals(portName))
+                        .findAny()
+                        .ifPresent(pi -> setState(node, INCOMPLETE));
+            }
+
+            //When the physical port up again, we set the node state to INIT
+            //so that respective handlers do their related jobs.
+            if (node.state() == INCOMPLETE && node.type().equals(GATEWAY) && port.isEnabled()) {
+                node.phyIntfs().stream()
+                        .filter(pi -> pi.intf().equals(portName))
+                        .findAny()
+                        .ifPresent(pi -> setState(node, INIT));
+            }
         }
 
         void processPortRemoval(Device device, Port port) {