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

Change-Id: I9706cd4b670fbbb7ffdaaa2924fb893c801b2253
(cherry picked from commit 17fe79854d31a89cda1a666e4a19be47e89aea75)
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 a79eeb0..8d72286 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
@@ -130,9 +130,7 @@
         nodeService.addListener(internalNodeListener);
         localNodeId = clusterService.getLocalNode().id();
         leadershipService.runForLeadership(appId.name());
-        nodeService.completeNodes(WORKER)
-                .forEach(node -> initializeWorkerNodePipeline(node.intgBridge()));
-
+        nodeService.completeNodes(WORKER).forEach(this::initializeGatewayNodePipeline);
         log.info("Started");
     }
 
@@ -236,7 +234,8 @@
         }));
     }
 
-    protected void initializeGatewayNodePipeline(DeviceId deviceId) {
+    protected void initializeGatewayNodePipeline(KubevirtNode kubevirtNode) {
+        DeviceId deviceId = kubevirtNode.intgBridge();
         // for inbound to gateway entry table transition
         connectTables(deviceId, STAT_INBOUND_TABLE, GW_ENTRY_TABLE);
 
@@ -247,9 +246,15 @@
         setupGatewayNodeDropTable(deviceId);
 
         // for setting up default Forwarding table behavior which is NORMAL
-        setupForwardingTable(deviceId);
+        setupNormalTable(deviceId, FORWARDING_TABLE);
+
+        kubevirtNode.phyIntfs().stream().filter(intf -> intf.physBridge() != null)
+                .forEach(phyIntf -> {
+                    setupNormalTable(phyIntf.physBridge(), STAT_INBOUND_TABLE);
+                });
     }
-    protected void initializeWorkerNodePipeline(DeviceId deviceId) {
+    protected void initializeWorkerNodePipeline(KubevirtNode kubevirtNode) {
+        DeviceId deviceId = kubevirtNode.intgBridge();
         // for inbound table transition
         connectTables(deviceId, STAT_INBOUND_TABLE, VTAP_INBOUND_TABLE);
         connectTables(deviceId, VTAP_INBOUND_TABLE, DHCP_TABLE);
@@ -264,7 +269,12 @@
         setupArpTable(deviceId);
 
         // for setting up default Forwarding table behavior which is NORMAL
-        setupForwardingTable(deviceId);
+        setupNormalTable(deviceId, FORWARDING_TABLE);
+
+        kubevirtNode.phyIntfs().stream().filter(intf -> intf.physBridge() != null)
+                .forEach(phyIntf -> {
+                    setupNormalTable(phyIntf.physBridge(), STAT_INBOUND_TABLE);
+                });
     }
 
     private void setupArpTable(DeviceId deviceId) {
@@ -284,7 +294,7 @@
                 true);
     }
 
-    private void setupForwardingTable(DeviceId deviceId) {
+    private void setupNormalTable(DeviceId deviceId, int tableNum) {
         TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
         TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
                 .setOutput(PortNumber.NORMAL);
@@ -295,7 +305,7 @@
                 selector.build(),
                 treatment.build(),
                 LOW_PRIORITY,
-                FORWARDING_TABLE,
+                tableNum,
                 true);
     }
 
@@ -346,9 +356,9 @@
                         }
 
                         if (event.subject().type().equals(WORKER)) {
-                            initializeWorkerNodePipeline(node.intgBridge());
+                            initializeWorkerNodePipeline(node);
                         } else {
-                            initializeGatewayNodePipeline(node.intgBridge());
+                            initializeGatewayNodePipeline(node);
                         }
                     });
                     break;
diff --git a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/DefaultKubevirtPhyInterface.java b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/DefaultKubevirtPhyInterface.java
index 1cae8f2..5d95b78 100644
--- a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/DefaultKubevirtPhyInterface.java
+++ b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/DefaultKubevirtPhyInterface.java
@@ -16,6 +16,7 @@
 package org.onosproject.kubevirtnode.api;
 
 import com.google.common.base.MoreObjects;
+import org.onosproject.net.DeviceId;
 
 import java.util.Objects;
 
@@ -28,6 +29,7 @@
 
     private final String network;
     private final String intf;
+    private final DeviceId physBridge;
 
     private static final String NOT_NULL_MSG = "% cannot be null";
 
@@ -36,10 +38,12 @@
      *
      * @param network network that this physical interface connects with
      * @param intf    name of physical interface
+     * @param physBridge device id of the physical bridge
      */
-    protected DefaultKubevirtPhyInterface(String network, String intf) {
+    protected DefaultKubevirtPhyInterface(String network, String intf, DeviceId physBridge) {
         this.network = network;
         this.intf = intf;
+        this.physBridge = physBridge;
     }
 
     @Override
@@ -53,6 +57,11 @@
     }
 
     @Override
+    public DeviceId physBridge() {
+        return physBridge;
+    }
+
+    @Override
     public boolean equals(Object o) {
         if (this == o) {
             return true;
@@ -62,12 +71,13 @@
         }
         DefaultKubevirtPhyInterface that = (DefaultKubevirtPhyInterface) o;
         return network.equals(that.network) &&
-                intf.equals(that.intf);
+                intf.equals(that.intf) &&
+                physBridge.equals(that.physBridge);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(network, intf);
+        return Objects.hash(network, intf, physBridge);
     }
 
     @Override
@@ -75,6 +85,7 @@
         return MoreObjects.toStringHelper(this)
                 .add("network", network)
                 .add("intf", intf)
+                .add("physnetBridge", physBridge)
                 .toString();
     }
 
@@ -91,6 +102,7 @@
 
         private String network;
         private String intf;
+        private DeviceId physBridge;
 
         // private constructor not intended to use from external
         private Builder() {
@@ -100,8 +112,9 @@
         public KubevirtPhyInterface build() {
             checkArgument(network != null, NOT_NULL_MSG, "network");
             checkArgument(intf != null, NOT_NULL_MSG, "intf");
+            checkArgument(physBridge != null, NOT_NULL_MSG, "physBridge");
 
-            return new DefaultKubevirtPhyInterface(network, intf);
+            return new DefaultKubevirtPhyInterface(network, intf, physBridge);
         }
 
         @Override
@@ -115,5 +128,12 @@
             this.intf = intf;
             return this;
         }
+
+        @Override
+        public KubevirtPhyInterface.Builder physBridge(DeviceId physBridge) {
+            this.physBridge = physBridge;
+            return this;
+        }
+
     }
 }
diff --git a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtNodeService.java b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtNodeService.java
index 41e90a3..e9ed65b 100644
--- a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtNodeService.java
+++ b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtNodeService.java
@@ -99,4 +99,12 @@
      * @return kubevirt node
      */
     KubevirtNode nodeByTunBridge(DeviceId deviceId);
+
+    /**
+     * Returns the node with the specified physical device ID.
+     *
+     * @param deviceId device id
+     * @return node
+     */
+    KubevirtNode nodeByPhyBridge(DeviceId deviceId);
 }
diff --git a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtPhyInterface.java b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtPhyInterface.java
index b3e0061..d17d796 100644
--- a/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtPhyInterface.java
+++ b/apps/kubevirt-node/api/src/main/java/org/onosproject/kubevirtnode/api/KubevirtPhyInterface.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.kubevirtnode.api;
 
+import org.onosproject.net.DeviceId;
+
 /**
  * Representation of a KubeVirt physical interface used in KubeVirt networking service.
  */
@@ -34,6 +36,13 @@
     String intf();
 
     /**
+     * Returns the device ID of the physical interface bridge at the node.
+     *
+     * @return device id
+     */
+    DeviceId physBridge();
+
+    /**
      * Builder of kubevirt physical interface.
      */
     interface Builder {
@@ -55,5 +64,13 @@
          * @return kubevirt physical interface builder
          */
         Builder intf(String intf);
+
+        /**
+         * Returns kubevirt physical interface builder with supplied.
+         *
+         * @param physBridge device id of the physical bridge
+         * @return kubevirt physical interface builder
+         */
+        Builder physBridge(DeviceId physBridge);
     }
 }
diff --git a/apps/kubevirt-node/api/src/test/java/org/onosproject/kubevirtnode/api/DefaultKubevirtNodeTest.java b/apps/kubevirt-node/api/src/test/java/org/onosproject/kubevirtnode/api/DefaultKubevirtNodeTest.java
index d66528c..6ad846b 100644
--- a/apps/kubevirt-node/api/src/test/java/org/onosproject/kubevirtnode/api/DefaultKubevirtNodeTest.java
+++ b/apps/kubevirt-node/api/src/test/java/org/onosproject/kubevirtnode/api/DefaultKubevirtNodeTest.java
@@ -21,6 +21,7 @@
 import org.junit.Test;
 import org.onlab.packet.IpAddress;
 import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
 
 import java.util.List;
 
@@ -47,6 +48,7 @@
 
     private static final String PHY_INTF_NETWORK = "mgmtnetwork";
     private static final String PHY_INTF_NAME = "eth3";
+    private static final DeviceId BRIDGE = DeviceId.deviceId("phys1");
 
     private static final String GATEWAY_BRIDGE_NAME = "gateway";
 
@@ -203,6 +205,7 @@
         KubevirtPhyInterface phyIntf = DefaultKubevirtPhyInterface.builder()
                 .intf(PHY_INTF_NAME)
                 .network(PHY_INTF_NETWORK)
+                .physBridge(BRIDGE)
                 .build();
 
         return ImmutableList.of(phyIntf);
diff --git a/apps/kubevirt-node/api/src/test/java/org/onosproject/kubevirtnode/api/DefaultKubevirtPhyInterfaceTest.java b/apps/kubevirt-node/api/src/test/java/org/onosproject/kubevirtnode/api/DefaultKubevirtPhyInterfaceTest.java
index 37ecdf4..73908f2 100644
--- a/apps/kubevirt-node/api/src/test/java/org/onosproject/kubevirtnode/api/DefaultKubevirtPhyInterfaceTest.java
+++ b/apps/kubevirt-node/api/src/test/java/org/onosproject/kubevirtnode/api/DefaultKubevirtPhyInterfaceTest.java
@@ -17,6 +17,7 @@
 
 import com.google.common.testing.EqualsTester;
 import org.junit.Test;
+import org.onosproject.net.DeviceId;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
@@ -30,13 +31,15 @@
     private static final String NETWORK_2 = "oamnetwork";
     private static final String INTERFACE_1 = "eth3";
     private static final String INTERFACE_2 = "eth4";
+    private static final DeviceId BRIDGE_1 = DeviceId.deviceId("phys1");
+    private static final DeviceId BRIDGE_2 = DeviceId.deviceId("phys2");
 
-    private static final KubevirtPhyInterface KV_PHY_INTF_1 =
-            new DefaultKubevirtPhyInterface(NETWORK_1, INTERFACE_1);
-    private static final KubevirtPhyInterface KV_PHY_INTF_2 =
-            new DefaultKubevirtPhyInterface(NETWORK_1, INTERFACE_1);
-    private static final KubevirtPhyInterface KV_PHY_INTF_3 =
-            new DefaultKubevirtPhyInterface(NETWORK_2, INTERFACE_2);
+    private static final KubevirtPhyInterface KV_PHY_INTF_1 = createPhysIntf(
+            NETWORK_1, INTERFACE_1, BRIDGE_1);
+    private static final KubevirtPhyInterface KV_PHY_INTF_2 = createPhysIntf(
+            NETWORK_1, INTERFACE_1, BRIDGE_1);
+    private static final KubevirtPhyInterface KV_PHY_INTF_3 = createPhysIntf(
+            NETWORK_2, INTERFACE_2, BRIDGE_2);
 
     @Test
     public void testEquality() {
@@ -53,4 +56,13 @@
         assertThat(phyIntf.network(), is(NETWORK_1));
         assertThat(phyIntf.intf(), is(INTERFACE_1));
     }
+
+    private static KubevirtPhyInterface createPhysIntf(String network,
+                                                       String intf, DeviceId physBridge) {
+        return DefaultKubevirtPhyInterface.builder()
+                .network(network)
+                .intf(intf)
+                .physBridge(physBridge)
+                .build();
+    }
 }
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/codec/KubevirtPhyInterfaceCodec.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/codec/KubevirtPhyInterfaceCodec.java
index 3ba0164..796a1b1 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/codec/KubevirtPhyInterfaceCodec.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/codec/KubevirtPhyInterfaceCodec.java
@@ -15,11 +15,13 @@
  */
 package org.onosproject.kubevirtnode.codec;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.codec.JsonCodec;
 import org.onosproject.kubevirtnode.api.DefaultKubevirtPhyInterface;
 import org.onosproject.kubevirtnode.api.KubevirtPhyInterface;
+import org.onosproject.net.DeviceId;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.onlab.util.Tools.nullIsIllegal;
@@ -31,6 +33,7 @@
 
     private static final String NETWORK = "network";
     private static final String INTERFACE = "intf";
+    private static final String PHYS_BRIDGE_ID = "physBridgeId";
 
     private static final String MISSING_MESSAGE = " is required in KubevirtPhyInterface";
 
@@ -38,9 +41,15 @@
     public ObjectNode encode(KubevirtPhyInterface phyIntf, CodecContext context) {
         checkNotNull(phyIntf, "Kubevirt physical interface cannot be null");
 
-        return context.mapper().createObjectNode()
+        ObjectNode result = context.mapper().createObjectNode()
                 .put(NETWORK, phyIntf.network())
                 .put(INTERFACE, phyIntf.intf());
+
+        if (phyIntf.physBridge() != null) {
+            result.put(PHYS_BRIDGE_ID, phyIntf.physBridge().toString());
+        }
+
+        return result;
     }
 
     @Override
@@ -54,9 +63,15 @@
         String intf = nullIsIllegal(json.get(INTERFACE).asText(),
                 INTERFACE + MISSING_MESSAGE);
 
-        return DefaultKubevirtPhyInterface.builder()
+        KubevirtPhyInterface.Builder builder = DefaultKubevirtPhyInterface.builder()
                 .network(network)
-                .intf(intf)
-                .build();
+                .intf(intf);
+
+        JsonNode physBridgeJson = json.get(PHYS_BRIDGE_ID);
+        if (physBridgeJson != null) {
+            builder.physBridge(DeviceId.deviceId(physBridgeJson.asText()));
+        }
+
+        return builder.build();
     }
 }
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) {
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/KubevirtNodeManager.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/KubevirtNodeManager.java
index 4e7e39e..f16837e 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/KubevirtNodeManager.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/impl/KubevirtNodeManager.java
@@ -61,6 +61,7 @@
 import static org.onosproject.kubevirtnode.api.Constants.TUNNEL_BRIDGE;
 import static org.onosproject.kubevirtnode.impl.OsgiPropertyConstants.OVSDB_PORT;
 import static org.onosproject.kubevirtnode.impl.OsgiPropertyConstants.OVSDB_PORT_NUM_DEFAULT;
+import static org.onosproject.kubevirtnode.util.KubevirtNodeUtil.genDpidFromName;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -305,6 +306,21 @@
                 .findFirst().orElse(null);
     }
 
+    @Override
+    public KubevirtNode nodeByPhyBridge(DeviceId deviceId) {
+        return nodeStore.nodes().stream()
+                .filter(node -> hasPhyBridge(node, deviceId))
+                .findAny()
+                .orElse(null);
+    }
+
+    private boolean hasPhyBridge(KubevirtNode node, DeviceId deviceId) {
+        return node.phyIntfs().stream()
+                .filter(phyIntf -> phyIntf.physBridge().equals(deviceId))
+                .findAny()
+                .isPresent();
+    }
+
     private boolean hasIntgBridge(DeviceId deviceId, String hostname) {
         Optional<KubevirtNode> existNode = nodeStore.nodes().stream()
                 .filter(n -> !n.hostname().equals(hostname))
@@ -323,15 +339,6 @@
         return existNode.isPresent();
     }
 
-    private String genDpidFromName(String name) {
-        if (name != null) {
-            String hexString = Integer.toHexString(name.hashCode());
-            return OF_PREFIX + Strings.padStart(hexString, 16, '0');
-        }
-
-        return null;
-    }
-
     private class InternalNodeStoreDelegate implements KubevirtNodeStoreDelegate {
 
         @Override
diff --git a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/util/KubevirtNodeUtil.java b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/util/KubevirtNodeUtil.java
index 66b1af8..7107285 100644
--- a/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/util/KubevirtNodeUtil.java
+++ b/apps/kubevirt-node/app/src/main/java/org/onosproject/kubevirtnode/util/KubevirtNodeUtil.java
@@ -38,6 +38,7 @@
 import org.onosproject.kubevirtnode.api.KubevirtNodeState;
 import org.onosproject.kubevirtnode.api.KubevirtPhyInterface;
 import org.onosproject.net.Device;
+import org.onosproject.net.DeviceId;
 import org.onosproject.net.behaviour.BridgeConfig;
 import org.onosproject.net.behaviour.BridgeName;
 import org.onosproject.net.device.DeviceService;
@@ -86,6 +87,7 @@
     private static final String GATEWAY_BRIDGE_NAME = "gatewayBridgeName";
     private static final String NETWORK_KEY = "network";
     private static final String INTERFACE_KEY = "interface";
+    private static final String PHYS_BRIDGE_ID = "physBridgeId";
 
     private static final int PORT_NAME_MAX_LENGTH = 15;
 
@@ -365,8 +367,20 @@
                     String intf = object.getString(INTERFACE_KEY);
 
                     if (network != null && intf != null) {
+                        String physBridgeId;
+                        if (object.has(PHYS_BRIDGE_ID)) {
+                            physBridgeId = object.getString(PHYS_BRIDGE_ID);
+                        } else {
+                            physBridgeId = genDpidFromName(network + intf + hostname);
+                            log.trace("host {} physnet dpid for network {} intf {} is null so generate dpid {}",
+                                    hostname, network, intf, physBridgeId);
+                        }
+
                         phys.add(DefaultKubevirtPhyInterface.builder()
-                                .network(network).intf(intf).build());
+                                .network(network)
+                                .intf(intf)
+                                .physBridge(DeviceId.deviceId(physBridgeId))
+                                .build());
                     }
                 }
             }
@@ -414,6 +428,20 @@
     }
 
     /**
+     * Generates a unique dpid from given name.
+     *
+     * @param name name
+     * @return device id in string
+     */
+    public static String genDpidFromName(String name) {
+        if (name != null) {
+            String hexString = Integer.toHexString(name.hashCode());
+            return OF_PREFIX + Strings.padStart(hexString, 16, '0');
+        }
+        return null;
+    }
+
+    /**
      * Resolve a DNS with the given DNS server and hostname.
      *
      * @param hostname      hostname to be resolved
diff --git a/apps/kubevirt-node/app/src/test/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodecTest.java b/apps/kubevirt-node/app/src/test/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodecTest.java
index eee6bf7..ae3467a 100644
--- a/apps/kubevirt-node/app/src/test/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodecTest.java
+++ b/apps/kubevirt-node/app/src/test/java/org/onosproject/kubevirtnode/codec/KubevirtNodeCodecTest.java
@@ -59,6 +59,10 @@
 
     final CoreService mockCoreService = createMock(CoreService.class);
     private static final String REST_APP_ID = "org.onosproject.rest";
+    private static final DeviceId DEVICE_ID_1 = DeviceId.deviceId(String.format("of:%016d", 1));
+    private static final DeviceId DEVICE_ID_2 = DeviceId.deviceId(String.format("of:%016d", 2));
+    private static final DeviceId DEVICE_ID_3 = DeviceId.deviceId(String.format("of:%016d", 3));
+
 
     @Before
     public void setUp() {
@@ -83,11 +87,13 @@
         KubevirtPhyInterface phyIntf1 = DefaultKubevirtPhyInterface.builder()
                 .network("mgmtnetwork")
                 .intf("eth3")
+                .physBridge(DEVICE_ID_1)
                 .build();
 
         KubevirtPhyInterface phyIntf2 = DefaultKubevirtPhyInterface.builder()
                 .network("oamnetwork")
                 .intf("eth4")
+                .physBridge(DEVICE_ID_2)
                 .build();
 
         KubevirtNode node = DefaultKubevirtNode.builder()
@@ -125,9 +131,11 @@
         node.phyIntfs().forEach(intf -> {
             if (intf.network().equals("mgmtnetwork")) {
                 assertThat(intf.intf(), is("eth3"));
+                assertThat(intf.physBridge().toString(), is("of:00000000000000a3"));
             }
             if (intf.network().equals("oamnetwork")) {
                 assertThat(intf.intf(), is("eth4"));
+                assertThat(intf.physBridge().toString(), is("of:00000000000000a4"));
             }
         });
     }
diff --git a/apps/kubevirt-node/app/src/test/resources/org/onosproject/kubevirtnode/codec/KubevirtWorkerNode.json b/apps/kubevirt-node/app/src/test/resources/org/onosproject/kubevirtnode/codec/KubevirtWorkerNode.json
index 78a8687..4db7b1a 100644
--- a/apps/kubevirt-node/app/src/test/resources/org/onosproject/kubevirtnode/codec/KubevirtWorkerNode.json
+++ b/apps/kubevirt-node/app/src/test/resources/org/onosproject/kubevirtnode/codec/KubevirtWorkerNode.json
@@ -8,11 +8,14 @@
   "phyIntfs": [
     {
       "network": "mgmtnetwork",
-      "intf": "eth3"
+      "intf": "eth3",
+      "physBridgeId": "of:00000000000000a3"
+
     },
     {
       "network": "oamnetwork",
-      "intf": "eth4"
+      "intf": "eth4",
+      "physBridgeId": "of:00000000000000a4"
     }
   ]
 }
\ No newline at end of file