Notify kubevirt router internal and external network related events

1. Add networkName attribute into FloatingIp class.

Change-Id: I4aeb8031ef4c86d7ae9a6423276b024c05fe0649
(cherry picked from commit 4acd4543cf7e6d48883ed0f7d9813b69f0d2c414)
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtFloatingIp.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtFloatingIp.java
index 6dc98e2..213fa4e 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtFloatingIp.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtFloatingIp.java
@@ -32,6 +32,7 @@
     private final String id;
     private final String routerName;
     private final String podName;
+    private final String networkName;
     private final IpAddress floatingIp;
     private final IpAddress fixedIp;
 
@@ -41,14 +42,16 @@
      * @param id            floating IP identifier
      * @param routerName    router name
      * @param podName       POD name
+     * @param networkName   network name
      * @param floatingIp    floating IP address
      * @param fixedIp       fixed IP address
      */
     public DefaultKubevirtFloatingIp(String id, String routerName, String podName,
-                                     IpAddress floatingIp, IpAddress fixedIp) {
+                                     String networkName, IpAddress floatingIp, IpAddress fixedIp) {
         this.id = id;
         this.routerName = routerName;
         this.podName = podName;
+        this.networkName = networkName;
         this.floatingIp = floatingIp;
         this.fixedIp = fixedIp;
     }
@@ -64,6 +67,11 @@
     }
 
     @Override
+    public String networkName() {
+        return networkName;
+    }
+
+    @Override
     public IpAddress floatingIp() {
         return floatingIp;
     }
@@ -82,6 +90,7 @@
     public KubevirtFloatingIp updateFixedIp(IpAddress ip) {
         return DefaultKubevirtFloatingIp.builder()
                 .id(id)
+                .networkName(networkName)
                 .routerName(routerName)
                 .floatingIp(floatingIp)
                 .fixedIp(ip)
@@ -93,6 +102,7 @@
     public KubevirtFloatingIp updatePodName(String name) {
         return DefaultKubevirtFloatingIp.builder()
                 .id(id)
+                .networkName(networkName)
                 .routerName(routerName)
                 .floatingIp(floatingIp)
                 .fixedIp(fixedIp)
@@ -111,6 +121,7 @@
         DefaultKubevirtFloatingIp that = (DefaultKubevirtFloatingIp) o;
         return id.equals(that.id) && routerName.equals(that.routerName) &&
                 Objects.equals(podName, that.podName) &&
+                networkName.equals(that.networkName) &&
                 floatingIp.equals(that.floatingIp) &&
                 Objects.equals(fixedIp, that.fixedIp);
     }
@@ -126,6 +137,7 @@
                 .add("id", id)
                 .add("routerName", routerName)
                 .add("podName", podName)
+                .add("networkName", networkName)
                 .add("floatingIp", floatingIp)
                 .add("fixedIp", fixedIp)
                 .toString();
@@ -145,16 +157,18 @@
         private String id;
         private String routerName;
         private String podName;
+        private String networkName;
         private IpAddress floatingIp;
         private IpAddress fixedIp;
 
         @Override
         public KubevirtFloatingIp build() {
             checkArgument(id != null, NOT_NULL_MSG, "id");
+            checkArgument(networkName != null, NOT_NULL_MSG, "networkName");
             checkArgument(routerName != null, NOT_NULL_MSG, "routerName");
             checkArgument(floatingIp != null, NOT_NULL_MSG, "floatingIp");
 
-            return new DefaultKubevirtFloatingIp(id, routerName, podName, floatingIp, fixedIp);
+            return new DefaultKubevirtFloatingIp(id, routerName, podName, networkName, floatingIp, fixedIp);
         }
 
         @Override
@@ -170,6 +184,12 @@
         }
 
         @Override
+        public Builder networkName(String name) {
+            this.networkName = name;
+            return this;
+        }
+
+        @Override
         public Builder floatingIp(IpAddress ip) {
             this.floatingIp = ip;
             return this;
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtRouter.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtRouter.java
index 4bf04a2..98653d9 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtRouter.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtRouter.java
@@ -80,12 +80,20 @@
 
     @Override
     public Set<String> internal() {
-        return ImmutableSet.copyOf(internal);
+        if (internal == null) {
+            return ImmutableSet.of();
+        } else {
+            return ImmutableSet.copyOf(internal);
+        }
     }
 
     @Override
     public Map<String, String> external() {
-        return ImmutableMap.copyOf(external);
+        if (external == null) {
+            return ImmutableMap.of();
+        } else {
+            return ImmutableMap.copyOf(external);
+        }
     }
 
     @Override
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtFloatingIp.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtFloatingIp.java
index f879d2b..27019b8 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtFloatingIp.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtFloatingIp.java
@@ -37,6 +37,13 @@
     String routerName();
 
     /**
+     * Returns the name of network where the floating IPs are belong to.
+     *
+     * @return name of network
+     */
+    String networkName();
+
+    /**
      * Returns the floating IP address.
      *
      * @return floating IP address
@@ -98,6 +105,14 @@
         Builder routerName(String name);
 
         /**
+         * Returns kubevirt floating IP builder with supplied network name.
+         *
+         * @param name network name
+         * @return floating IP builder
+         */
+        Builder networkName(String name);
+
+        /**
          * Returns kubevirt floating IP builder with supplied floating IP address.
          *
          * @param ip floating IP address
diff --git a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtRouterEvent.java b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtRouterEvent.java
index c9e1f16..7fd8958 100644
--- a/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtRouterEvent.java
+++ b/apps/kubevirt-networking/api/src/main/java/org/onosproject/kubevirtnetworking/api/KubevirtRouterEvent.java
@@ -17,6 +17,8 @@
 
 import org.onosproject.event.AbstractEvent;
 
+import java.util.Set;
+
 import static com.google.common.base.MoreObjects.toStringHelper;
 
 /**
@@ -26,6 +28,10 @@
 
     private final KubevirtFloatingIp floatingIp;
     private final String podName;
+    private final Set<String> internal;
+    private final String externalIp;
+    private final String externalNet;
+    private final String peerRouterIp;
 
     /**
      * Creates an event of a given type for the specified kubevirt router.
@@ -37,6 +43,10 @@
         super(type, subject);
         this.floatingIp = null;
         this.podName = null;
+        this.internal = null;
+        this.externalIp = null;
+        this.externalNet = null;
+        this.peerRouterIp = null;
     }
 
     /**
@@ -50,6 +60,10 @@
         super(type, subject);
         this.floatingIp = floatingIp;
         this.podName = null;
+        this.internal = null;
+        this.externalIp = null;
+        this.externalNet = null;
+        this.peerRouterIp = null;
     }
 
     /**
@@ -64,6 +78,48 @@
         super(type, subject);
         this.floatingIp = floatingIp;
         this.podName = podName;
+        this.internal = null;
+        this.externalIp = null;
+        this.externalNet = null;
+        this.peerRouterIp = null;
+    }
+
+    /**
+     * Creates an event of a given type for the specified kubevirt router.
+     *
+     * @param type        kubevirt router event type
+     * @param subject     kubevirt router
+     * @param internal    internal networks attached to the router
+     */
+    public KubevirtRouterEvent(Type type, KubevirtRouter subject, Set<String> internal) {
+        super(type, subject);
+        this.internal = internal;
+        this.podName = null;
+        this.floatingIp = null;
+        this.externalIp = null;
+        this.externalNet = null;
+        this.peerRouterIp = null;
+    }
+
+    /**
+     * Creates an event of a given type for the specified kubevirt router.
+     *
+     * @param type          kubevirt router event type
+     * @param subject       kubevirt router
+     * @param externalIp    virtual router's IP address included in external network
+     * @param externalNet   external network name
+     * @param peerRouterIp  external peer router IP address
+     */
+    public KubevirtRouterEvent(Type type, KubevirtRouter subject,
+                               String externalIp, String externalNet,
+                               String peerRouterIp) {
+        super(type, subject);
+        this.internal = null;
+        this.podName = null;
+        this.floatingIp = null;
+        this.externalIp = externalIp;
+        this.externalNet = externalNet;
+        this.peerRouterIp = peerRouterIp;
     }
 
     public enum Type {
@@ -83,6 +139,26 @@
         KUBEVIRT_ROUTER_REMOVED,
 
         /**
+         * Signifies that a new external network is added to the router.
+         */
+        KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED,
+
+        /**
+         * Signifies that the existing external network is removed from the router.
+         */
+        KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED,
+
+        /**
+         * Signifies that a new internal network is added to the router.
+         */
+        KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED,
+
+        /**
+         * Signifies that the existing internal network is removed from the router.
+         */
+        KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED,
+
+        /**
          * Signifies that a new kubevirt floating IP is created.
          */
         KUBEVIRT_FLOATING_IP_CREATED,
@@ -136,6 +212,10 @@
                 .add("router", subject())
                 .add("floatingIp", floatingIp)
                 .add("podName", podName)
+                .add("internal", internal)
+                .add("externalIp", externalIp)
+                .add("externalNet", externalNet)
+                .add("peerRouterIp", peerRouterIp)
                 .toString();
     }
 }
diff --git a/apps/kubevirt-networking/api/src/test/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtFloatingIpTest.java b/apps/kubevirt-networking/api/src/test/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtFloatingIpTest.java
index f5f400e..b63cf00 100644
--- a/apps/kubevirt-networking/api/src/test/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtFloatingIpTest.java
+++ b/apps/kubevirt-networking/api/src/test/java/org/onosproject/kubevirtnetworking/api/DefaultKubevirtFloatingIpTest.java
@@ -32,6 +32,8 @@
     private static final String ID_2 = "fip_id_2";
     private static final String ROUTER_NAME_1 = "router-1";
     private static final String ROUTER_NAME_2 = "router-2";
+    private static final String NETWORK_NAME_1 = "flat-1";
+    private static final String NETWORK_NAME_2 = "flat-2";
     private static final IpAddress FLOATING_IP_1 = IpAddress.valueOf("10.10.10.10");
     private static final IpAddress FLOATING_IP_2 = IpAddress.valueOf("20.20.20.20");
     private static final String POD_NAME_1 = "pod-1";
@@ -59,6 +61,7 @@
         fip1 = DefaultKubevirtFloatingIp.builder()
                 .id(ID_1)
                 .routerName(ROUTER_NAME_1)
+                .networkName(NETWORK_NAME_1)
                 .floatingIp(FLOATING_IP_1)
                 .podName(POD_NAME_1)
                 .fixedIp(FIXED_IP_1)
@@ -67,6 +70,7 @@
         sameAsFip1 = DefaultKubevirtFloatingIp.builder()
                 .id(ID_1)
                 .routerName(ROUTER_NAME_1)
+                .networkName(NETWORK_NAME_1)
                 .floatingIp(FLOATING_IP_1)
                 .podName(POD_NAME_1)
                 .fixedIp(FIXED_IP_1)
@@ -75,6 +79,7 @@
         fip2 = DefaultKubevirtFloatingIp.builder()
                 .id(ID_2)
                 .routerName(ROUTER_NAME_2)
+                .networkName(NETWORK_NAME_2)
                 .floatingIp(FLOATING_IP_2)
                 .podName(POD_NAME_2)
                 .fixedIp(FIXED_IP_2)
@@ -100,6 +105,7 @@
 
         assertEquals(ID_1, fip.id());
         assertEquals(ROUTER_NAME_1, fip.routerName());
+        assertEquals(NETWORK_NAME_1, fip.networkName());
         assertEquals(FLOATING_IP_1, fip.floatingIp());
         assertEquals(POD_NAME_1, fip.podName());
         assertEquals(FIXED_IP_1, fip.fixedIp());
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/cli/KubevirtListFloatingIpCommand.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/cli/KubevirtListFloatingIpCommand.java
index 574bba5..20ab17e 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/cli/KubevirtListFloatingIpCommand.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/cli/KubevirtListFloatingIpCommand.java
@@ -47,7 +47,7 @@
     protected void doExecute() throws Exception {
         KubevirtRouterService service = get(KubevirtRouterService.class);
         List<KubevirtFloatingIp> fips = Lists.newArrayList(service.floatingIps());
-        fips.sort(Comparator.comparing(KubevirtFloatingIp::routerName));
+        fips.sort(Comparator.comparing(KubevirtFloatingIp::networkName));
 
         String format = genFormatString(ImmutableList.of(CLI_NAME_LENGTH,
                 CLI_IP_ADDRESS_LENGTH, CLI_NAME_LENGTH, CLI_IP_ADDRESS_LENGTH));
@@ -55,13 +55,13 @@
         if (outputJson()) {
             print("%s", json(fips));
         } else {
-            print(format, "Router Name", "Floating IP", "POD Name", "Fixed IP");
+            print(format, "Network Name", "Floating IP", "POD Name", "Fixed IP");
             for (KubevirtFloatingIp fip : fips) {
 
                 String fixedIp = fip.fixedIp() == null ? "N/A" : fip.fixedIp().toString();
                 String podName = fip.podName() == null ? "N/A" : fip.podName();
 
-                print(format, StringUtils.substring(fip.routerName(), 0,
+                print(format, StringUtils.substring(fip.networkName(), 0,
                         CLI_NAME_LENGTH - CLI_MARGIN_LENGTH),
                         StringUtils.substring(fip.floatingIp().toString(), 0,
                                 CLI_IP_ADDRESS_LENGTH - CLI_MARGIN_LENGTH),
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodec.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodec.java
index 16fd082..f2a3505 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodec.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodec.java
@@ -38,6 +38,7 @@
     private static final String ID = "id";
     private static final String ROUTER_NAME = "routerName";
     private static final String POD_NAME = "podName";
+    private static final String NETWORK_NAME = "networkName";
     private static final String FLOATING_IP = "floatingIp";
     private static final String FIXED_IP = "fixedIp";
 
@@ -50,6 +51,7 @@
         ObjectNode result = context.mapper().createObjectNode()
                 .put(ID, fip.id())
                 .put(ROUTER_NAME, fip.routerName())
+                .put(NETWORK_NAME, fip.networkName())
                 .put(FLOATING_IP, fip.floatingIp().toString());
 
         if (fip.podName() != null) {
@@ -74,10 +76,13 @@
                 ROUTER_NAME + MISSING_MESSAGE);
         String floatingIp = nullIsIllegal(json.get(FLOATING_IP).asText(),
                 FLOATING_IP + MISSING_MESSAGE);
+        String networkName = nullIsIllegal(json.get(NETWORK_NAME).asText(),
+                NETWORK_NAME + MISSING_MESSAGE);
 
         KubevirtFloatingIp.Builder builder = DefaultKubevirtFloatingIp.builder()
                 .id(id)
                 .routerName(routerName)
+                .networkName(networkName)
                 .floatingIp(IpAddress.valueOf(floatingIp));
 
         JsonNode podName = json.get(POD_NAME);
diff --git a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/DistributedKubevirtRouterStore.java b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/DistributedKubevirtRouterStore.java
index 2d566fc..c11fb2d 100644
--- a/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/DistributedKubevirtRouterStore.java
+++ b/apps/kubevirt-networking/app/src/main/java/org/onosproject/kubevirtnetworking/impl/DistributedKubevirtRouterStore.java
@@ -44,6 +44,7 @@
 import org.slf4j.Logger;
 
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
 
@@ -56,6 +57,10 @@
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_REMOVED;
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_UPDATED;
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_CREATED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED;
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_REMOVED;
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_UPDATED;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -72,6 +77,10 @@
 
     private static final String ERR_NOT_FOUND = " does not exist";
     private static final String ERR_DUPLICATE = " already exists";
+    private static final String MSG_FLOATING_IP = "Kubevirt floating IP %s %s with %s";
+    private static final String MSG_ASSOCIATED = "associated";
+    private static final String MSG_DISASSOCIATED = "disassociated";
+
     private static final String APP_ID = "org.onosproject.kubevirtnetwork";
 
     private static final KryoNamespace
@@ -223,10 +232,7 @@
                                     KUBEVIRT_ROUTER_CREATED, event.newValue().value())));
                     break;
                 case UPDATE:
-                    log.debug("Kubevirt router updated");
-                    eventExecutor.execute(() ->
-                            notifyDelegate(new KubevirtRouterEvent(
-                                    KUBEVIRT_ROUTER_UPDATED, event.newValue().value())));
+                    eventExecutor.execute(() -> processRouterMapUpdate(event));
                     break;
                 case REMOVE:
                     log.debug("Kubevirt router removed");
@@ -239,6 +245,59 @@
                     break;
             }
         }
+
+        private void processRouterMapUpdate(MapEvent<String, KubevirtRouter> event) {
+            log.debug("Kubevirt router updated");
+            eventExecutor.execute(() ->
+                    notifyDelegate(new KubevirtRouterEvent(
+                            KUBEVIRT_ROUTER_UPDATED, event.newValue().value())));
+
+            KubevirtRouter router = Strings.isNullOrEmpty(
+                    event.newValue().value().name()) ?
+                    null :
+                    router(event.newValue().value().name());
+
+            KubevirtRouter oldValue = event.oldValue().value();
+            KubevirtRouter newValue = event.newValue().value();
+
+            if (oldValue.external().size() == 0 && newValue.external().size() > 0) {
+                newValue.external().entrySet().stream().findAny()
+                        .ifPresent(entry ->
+                            notifyDelegate(new KubevirtRouterEvent(
+                            KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED,
+                            router, entry.getKey(), entry.getValue(),
+                            newValue.peerRouter().ipAddress().toString())));
+            }
+
+            if (oldValue.external().size() > 0 && newValue.external().size() == 0) {
+                oldValue.external().entrySet().stream().findAny()
+                        .ifPresent(entry ->
+                            notifyDelegate(new KubevirtRouterEvent(
+                            KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED,
+                            router, entry.getKey(), entry.getValue(),
+                            oldValue.peerRouter().ipAddress().toString())));
+            }
+
+            Set<String> added = new HashSet<>(newValue.internal());
+            Set<String> oldset = oldValue.internal();
+            added.removeAll(oldset);
+
+            Set<String> removed = new HashSet<>(oldValue.internal());
+            Set<String> newset = newValue.internal();
+            removed.removeAll(newset);
+
+            if (added.size() > 0) {
+                notifyDelegate(new KubevirtRouterEvent(
+                        KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED,
+                        router, added));
+            }
+
+            if (removed.size() > 0) {
+                notifyDelegate(new KubevirtRouterEvent(
+                        KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED,
+                        router, removed));
+            }
+        }
     }
 
     private class KubevirtFloatingIpMapListener implements MapEventListener<String, KubevirtFloatingIp> {
@@ -307,6 +366,8 @@
                         KUBEVIRT_FLOATING_IP_ASSOCIATED,
                         router,
                         event.newValue().value(), newPodName));
+                log.info(String.format(MSG_FLOATING_IP,
+                        event.newValue().value().floatingIp(), MSG_ASSOCIATED, newPodName));
             }
 
             if (!Strings.isNullOrEmpty(oldPodName) && Strings.isNullOrEmpty(newPodName)) {
@@ -314,6 +375,8 @@
                         KUBEVIRT_FLOATING_IP_DISASSOCIATED,
                         router,
                         event.newValue().value(), oldPodName));
+                log.info(String.format(MSG_FLOATING_IP,
+                        event.newValue().value().floatingIp(), MSG_DISASSOCIATED, oldPodName));
             }
         }
     }
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 18caff1..7f539de 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
@@ -394,6 +394,7 @@
         KubevirtNode electedGateway = gatewayNodeForSpecifiedNetwork(network);
         if (electedGateway == null) {
             log.warn("There's no elected gateway for the network {}", network.name());
+            return;
         }
 
         setGatewayArpRule(network, PRE_FLAT_TABLE, electedGateway.intgBridge(), install);
diff --git a/apps/kubevirt-networking/app/src/main/resources/definitions/KubevirtFloatingIps.json b/apps/kubevirt-networking/app/src/main/resources/definitions/KubevirtFloatingIps.json
index bffb67d..07a45e2 100644
--- a/apps/kubevirt-networking/app/src/main/resources/definitions/KubevirtFloatingIps.json
+++ b/apps/kubevirt-networking/app/src/main/resources/definitions/KubevirtFloatingIps.json
@@ -17,6 +17,7 @@
         "required": [
           "id",
           "routerName",
+          "networkName",
           "floatingIp",
           "podName",
           "fixedIp"
@@ -32,6 +33,11 @@
             "example": "router-1",
             "description": "Name of router."
           },
+          "networkName": {
+            "type": "string",
+            "example": "flat-1",
+            "description": "Name of network."
+          },
           "floatingIp": {
             "type": "string",
             "example": "10.10.10.5",
diff --git a/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodecTest.java b/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodecTest.java
index 79182da..f8b5d14 100644
--- a/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodecTest.java
+++ b/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpCodecTest.java
@@ -71,6 +71,7 @@
         KubevirtFloatingIp floatingIp = DefaultKubevirtFloatingIp.builder()
                 .id("fip-id")
                 .routerName("router-1")
+                .networkName("flat-1")
                 .floatingIp(IpAddress.valueOf("10.10.10.10"))
                 .podName("pod-1")
                 .fixedIp(IpAddress.valueOf("20.20.20.20"))
@@ -86,6 +87,7 @@
 
         assertEquals("fip-1", floatingIp.id());
         assertEquals("router-1", floatingIp.routerName());
+        assertEquals("flat-1", floatingIp.networkName());
         assertEquals("10.10.10.10", floatingIp.floatingIp().toString());
         assertEquals("pod-1", floatingIp.podName());
         assertEquals("20.20.20.20", floatingIp.fixedIp().toString());
diff --git a/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpJsonMatcher.java b/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpJsonMatcher.java
index 0bcfa0a..ccfb76c 100644
--- a/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpJsonMatcher.java
+++ b/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIpJsonMatcher.java
@@ -28,6 +28,7 @@
     private final KubevirtFloatingIp floatingIp;
     private static final String ID = "id";
     private static final String ROUTER_NAME = "routerName";
+    private static final String NETWORK_NAME = "networkName";
     private static final String POD_NAME = "podName";
     private static final String FLOATING_IP = "floatingIp";
     private static final String FIXED_IP = "fixedIp";
@@ -55,6 +56,14 @@
             return false;
         }
 
+        // check network name
+        String jsonNetworkName = jsonNode.get(NETWORK_NAME).asText();
+        String networkName = floatingIp.networkName();
+        if (!jsonNetworkName.equals(networkName)) {
+            description.appendText("Network name was " + jsonNetworkName);
+            return false;
+        }
+
         // check floating IP
         String jsonFip = jsonNode.get(FLOATING_IP).asText();
         String fip = floatingIp.floatingIp().toString();
diff --git a/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/impl/KubevirtRouterManagerTest.java b/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/impl/KubevirtRouterManagerTest.java
index 2bc222e..2b90712 100644
--- a/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/impl/KubevirtRouterManagerTest.java
+++ b/apps/kubevirt-networking/app/src/test/java/org/onosproject/kubevirtnetworking/impl/KubevirtRouterManagerTest.java
@@ -49,6 +49,10 @@
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_REMOVED;
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_FLOATING_IP_UPDATED;
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_CREATED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED;
+import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED;
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_REMOVED;
 import static org.onosproject.kubevirtnetworking.api.KubevirtRouterEvent.Type.KUBEVIRT_ROUTER_UPDATED;
 
@@ -61,6 +65,7 @@
 
     private static final String ROUTER_NAME = "router-1";
     private static final String POD_NAME = "pod-1";
+    private static final String NETWORK_NAME = "flat-1";
     private static final String UPDATED_DESCRIPTION = "router-updated";
     private static final MacAddress UPDATED_MAC = MacAddress.valueOf("FF:FF:FF:FF:FF:FF");
 
@@ -70,17 +75,31 @@
     private static final KubevirtRouter ROUTER = DefaultKubevirtRouter.builder()
             .name(ROUTER_NAME)
             .description(ROUTER_NAME)
-            .internal(ImmutableSet.of("vxlan-1", "vxlan-2"))
-            .external(ImmutableMap.of("10.10.10.10", "flat"))
+            .internal(ImmutableSet.of())
+            .external(ImmutableMap.of())
             .enableSnat(true)
-            .peerRouter(new KubevirtPeerRouter(IpAddress.valueOf("20.20.20.20"),
-                    MacAddress.valueOf("11:22:33:44:55:66")))
             .build();
 
     private static final KubevirtRouter ROUTER_UPDATED = DefaultKubevirtRouter.builder()
             .name(ROUTER_NAME)
             .description(UPDATED_DESCRIPTION)
+            .internal(ImmutableSet.of())
+            .external(ImmutableMap.of())
+            .enableSnat(true)
+            .build();
+
+    private static final KubevirtRouter ROUTER_WITH_INTERNAL = DefaultKubevirtRouter.builder()
+            .name(ROUTER_NAME)
+            .description(ROUTER_NAME)
             .internal(ImmutableSet.of("vxlan-1", "vxlan-2"))
+            .external(ImmutableMap.of())
+            .enableSnat(true)
+            .build();
+
+    private static final KubevirtRouter ROUTER_WITH_EXTERNAL = DefaultKubevirtRouter.builder()
+            .name(ROUTER_NAME)
+            .description(ROUTER_NAME)
+            .internal(ImmutableSet.of())
             .external(ImmutableMap.of("10.10.10.10", "flat"))
             .enableSnat(true)
             .peerRouter(new KubevirtPeerRouter(IpAddress.valueOf("20.20.20.20"),
@@ -90,12 +109,14 @@
     private static final KubevirtFloatingIp FLOATING_IP_DISASSOCIATED = DefaultKubevirtFloatingIp.builder()
             .id(FLOATING_IP_ID)
             .routerName(ROUTER_NAME)
+            .networkName(NETWORK_NAME)
             .floatingIp(IpAddress.valueOf("10.10.10.10"))
             .build();
 
     private static final KubevirtFloatingIp FLOATING_IP_ASSOCIATED = DefaultKubevirtFloatingIp.builder()
             .id(FLOATING_IP_ID)
             .routerName(ROUTER_NAME)
+            .networkName(NETWORK_NAME)
             .floatingIp(IpAddress.valueOf("10.10.10.10"))
             .fixedIp(IpAddress.valueOf("20.20.20.20"))
             .podName(POD_NAME)
@@ -184,7 +205,7 @@
      */
     @Test
     public void testPeerRouterMacUpdate() {
-        target.createRouter(ROUTER);
+        target.createRouter(ROUTER_WITH_EXTERNAL);
 
         target.updatePeerRouterMac(ROUTER_NAME, UPDATED_MAC);
         assertEquals("MAC address was not updated", UPDATED_MAC,
@@ -194,6 +215,53 @@
     }
 
     /**
+     * Tests router's internal networks attached and detached.
+     */
+    @Test
+    public void testRouterInternalAttachedAndDetached() {
+        target.createRouter(ROUTER);
+        assertEquals("Number of router did not match", 1, target.routers().size());
+        assertEquals("Router internal did not match", 0, target.router(ROUTER_NAME).internal().size());
+
+        target.updateRouter(ROUTER_WITH_INTERNAL);
+        assertEquals("Number of router did not match", 1, target.routers().size());
+        assertEquals("Router internal did not match", 2, target.router(ROUTER_NAME).internal().size());
+
+        target.updateRouter(ROUTER);
+        assertEquals("Number of router did not match", 1, target.routers().size());
+        assertEquals("Router internal did not match", 0, target.router(ROUTER_NAME).internal().size());
+
+        validateEvents(KUBEVIRT_ROUTER_CREATED, KUBEVIRT_ROUTER_UPDATED,
+                KUBEVIRT_ROUTER_INTERNAL_NETWORKS_ATTACHED, KUBEVIRT_ROUTER_UPDATED,
+                KUBEVIRT_ROUTER_INTERNAL_NETWORKS_DETACHED);
+    }
+
+    /**
+     * Tests router's external networks attached and detached.
+     */
+    @Test
+    public void testRouterExternalAttachedAndDetached() {
+        target.createRouter(ROUTER);
+        assertEquals("Number of router did not match", 1, target.routers().size());
+        assertNull(target.router(ROUTER_NAME).peerRouter());
+        assertEquals(0, target.router(ROUTER_NAME).external().size());
+
+        target.updateRouter(ROUTER_WITH_EXTERNAL);
+        assertEquals("Number of router did not match", 1, target.routers().size());
+        assertNotNull(target.router(ROUTER_NAME).peerRouter());
+        assertEquals(1, target.router(ROUTER_NAME).external().size());
+
+        target.updateRouter(ROUTER);
+        assertEquals("Number of router did not match", 1, target.routers().size());
+        assertNull(target.router(ROUTER_NAME).peerRouter());
+        assertEquals(0, target.router(ROUTER_NAME).external().size());
+
+        validateEvents(KUBEVIRT_ROUTER_CREATED, KUBEVIRT_ROUTER_UPDATED,
+                KUBEVIRT_ROUTER_EXTERNAL_NETWORK_ATTACHED, KUBEVIRT_ROUTER_UPDATED,
+                KUBEVIRT_ROUTER_EXTERNAL_NETWORK_DETACHED);
+    }
+
+    /**
      * Tests if creating a null router fails with an exception.
      */
     @Test(expected = NullPointerException.class)
diff --git a/apps/kubevirt-networking/app/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIp.json b/apps/kubevirt-networking/app/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIp.json
index fa85c53..1424d48 100644
--- a/apps/kubevirt-networking/app/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIp.json
+++ b/apps/kubevirt-networking/app/src/test/resources/org/onosproject/kubevirtnetworking/codec/KubevirtFloatingIp.json
@@ -1,6 +1,7 @@
 {
   "id": "fip-1",
   "routerName": "router-1",
+  "networkName": "flat-1",
   "floatingIp": "10.10.10.10",
   "podName": "pod-1",
   "fixedIp": "20.20.20.20"