[ONOS-7444] Optimize SONA gw doesn't use vrouter app and quagga anymore
- Done: Deriving MAC address from external peer router, SNAT, Floating IP-based routing
- Todo: Vlan, GW loadbalancing

Change-Id: I0cc2a61295c28fa6a796046ca142c4ef525b70d3
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/Constants.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
index 824ae6b..8a7a2bb 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
@@ -38,6 +38,7 @@
     public static final int PRIORITY_ICMP_RULE = 43000;
     public static final int PRIORITY_INTERNAL_ROUTING_RULE = 28000;
     public static final int PRIORITY_EXTERNAL_ROUTING_RULE = 25000;
+    public static final int PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE = 26000;
     public static final int PRIORITY_SNAT_RULE = 26000;
     public static final int PRIORITY_SWITCHING_RULE = 30000;
     public static final int PRIORITY_ADMIN_RULE = 32000;
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkService.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkService.java
index a297b83..2974c47 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkService.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/api/OpenstackNetworkService.java
@@ -117,6 +117,13 @@
     void deleteExternalPeerRouter(ExternalGateway externalGateway);
 
     /**
+     * Deletes external router with supplied ip address.
+     *
+     * @param ipAddress ip address
+     */
+    void deleteExternalPeerRouter(String ipAddress);
+
+    /**
      * Updates external router mac address with supplied ip address.
      *
      * @param ipAddress ip address
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/DeleteExternalPeerRouterCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/DeleteExternalPeerRouterCommand.java
new file mode 100644
index 0000000..efda0ae
--- /dev/null
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/DeleteExternalPeerRouterCommand.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.openstacknetworking.cli;
+
+import com.google.common.collect.Lists;
+import org.apache.karaf.shell.commands.Argument;
+import org.apache.karaf.shell.commands.Command;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.openstacknetworking.api.ExternalPeerRouter;
+import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
+
+import java.util.List;
+
+/**
+ * Deletes external peer router.
+ */
+@Command(scope = "onos", name = "openstack-delete-peer-router",
+        description = "Delete external peer router")
+public class DeleteExternalPeerRouterCommand extends AbstractShellCommand {
+    @Argument(index = 0, name = "ip address", description = "ip address",
+            required = true, multiValued = false)
+    private String ipAddress = null;
+
+    private static final String FORMAT = "%-20s%-20s%-20s";
+    private static final String NO_ELEMENT = "There's no external peer router information with given ip address";
+
+    @Override
+    protected void execute() {
+        OpenstackNetworkService service = AbstractShellCommand.get(OpenstackNetworkService.class);
+
+        if (service.externalPeerRouters().stream()
+                .noneMatch(router -> router.externalPeerRouterIp().toString().equals(ipAddress))) {
+            print(NO_ELEMENT);
+            return;
+        }
+
+        try {
+            service.deleteExternalPeerRouter(ipAddress);
+        } catch (IllegalArgumentException e) {
+            log.error("Exception occurred because of {}", e.toString());
+        }
+        print(FORMAT, "Router IP", "Mac Address", "VLAN ID");
+        List<ExternalPeerRouter> routers = Lists.newArrayList(service.externalPeerRouters());
+
+        for (ExternalPeerRouter router: routers) {
+            print(FORMAT, router.externalPeerRouterIp(),
+                    router.externalPeerRouterMac().toString(),
+                    router.externalPeerRouterVlanId());
+        }
+
+    }
+}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
index e89141b..a297ca0 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/cli/OpenstackSyncStateCommand.java
@@ -259,7 +259,7 @@
     private void printFloatingIp(NetFloatingIP floatingIp) {
         final String strFloating = String.format(FLOATING_IP_FORMAT,
                 floatingIp.getId(),
-                floatingIp.getFixedIpAddress(),
+                floatingIp.getFloatingIpAddress(),
                 Strings.isNullOrEmpty(floatingIp.getFixedIpAddress()) ?
                         "" : floatingIp.getFixedIpAddress());
         print(strFloating);
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
index 8d16bce..230e740 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
@@ -418,6 +418,17 @@
         }
     }
 
+    @Override
+    public void deleteExternalPeerRouter(String ipAddress) {
+        if (ipAddress == null) {
+            return;
+        }
+
+        if (externalPeerRouterMap.containsKey(ipAddress)) {
+            externalPeerRouterMap.remove(ipAddress);
+        }
+
+    }
     private IpAddress getExternalGatewaySourceIp(ExternalGateway externalGateway, Router router) {
         Port exGatewayPort = ports(externalGateway.getNetworkId())
                 .stream()
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
index 98fdbd9..5dee134 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingArpHandler.java
@@ -36,8 +36,10 @@
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.Constants;
+import org.onosproject.openstacknetworking.api.OpenstackRouterService;
 import org.onosproject.openstacknode.api.OpenstackNode;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.openstack4j.model.network.NetFloatingIP;
 import org.slf4j.Logger;
 
 import java.nio.ByteBuffer;
@@ -69,6 +71,10 @@
     protected OpenstackNetworkService osNetworkService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackRouterService osRouterService;
+
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenstackNodeService osNodeService;
 
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
@@ -99,12 +105,26 @@
             }
 
             IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
-            if (!isServiceIp(targetIp.getIp4Address())) {
+
+            MacAddress targetMac = null;
+
+            NetFloatingIP floatingIP = osRouterService.floatingIps().stream()
+                    .filter(ip -> ip.getFloatingIpAddress().equals(targetIp.toString()))
+                    .findAny().orElse(null);
+
+            if (floatingIP != null && floatingIP.getPortId() != null) {
+                targetMac = MacAddress.valueOf(osNetworkService.port(floatingIP.getPortId()).getMacAddress());
+            }
+
+            if (isExternalGatewaySourceIp(targetIp.getIp4Address())) {
+                targetMac = Constants.DEFAULT_GATEWAY_MAC;
+            }
+
+            if (targetMac == null) {
                 log.trace("Unknown target ARP request for {}, ignore it", targetIp);
                 return;
             }
 
-            MacAddress targetMac = Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
             Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
                     targetMac, ethernet);
 
@@ -163,14 +183,10 @@
         }
     }
 
-    private boolean isServiceIp(IpAddress targetIp) {
-        // FIXME use floating IP and external gateway information of router instead
-        // once openstack4j fixed
+    private boolean isExternalGatewaySourceIp(IpAddress targetIp) {
         return osNetworkService.ports().stream()
                 .filter(osPort -> Objects.equals(osPort.getDeviceOwner(),
-                        DEVICE_OWNER_ROUTER_GW) ||
-                        Objects.equals(osPort.getDeviceOwner(),
-                                DEVICE_OWNER_FLOATING_IP))
+                        DEVICE_OWNER_ROUTER_GW))
                 .flatMap(osPort -> osPort.getFixedIps().stream())
                 .anyMatch(ip -> IpAddress.valueOf(ip.getIpAddress()).equals(targetIp));
     }
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
index 9f8cdf02..8a45968 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
@@ -48,10 +48,14 @@
 import org.onosproject.openstacknode.api.OpenstackNodeEvent;
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
+import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
 import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
+import org.openstack4j.model.network.Router;
+import org.openstack4j.model.network.RouterInterface;
+import org.openstack4j.model.network.Subnet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,8 +66,10 @@
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
+import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_EXTERNAL;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLOATING_INTERNAL;
+import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
 import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 
@@ -152,10 +158,61 @@
             throw new IllegalStateException(error);
         }
 
+        setComputeNodeToGateway(instPort, osNet, install);
         setDownstreamRules(floatingIp, osNet, instPort, install);
         setUpstreamRules(floatingIp, osNet, instPort, install);
     }
 
+    private void setComputeNodeToGateway(InstancePort instPort, Network osNet, boolean install) {
+        TrafficTreatment treatment;
+
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPSrc(instPort.ipAddress().toIpPrefix())
+                .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
+
+        switch (osNet.getNetworkType()) {
+            case VXLAN:
+                sBuilder.matchTunnelId(Long.parseLong(osNet.getProviderSegID()));
+                break;
+            case VLAN:
+                sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
+                break;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        osNet.getNetworkType().toString());
+                throw new IllegalStateException(error);
+        }
+
+        OpenstackNode selectedGatewayNode = selectGatewayNode();
+        if (selectedGatewayNode == null) {
+            return;
+        }
+        treatment = DefaultTrafficTreatment.builder()
+                .extension(buildExtension(
+                        deviceService,
+                        instPort.deviceId(),
+                        selectedGatewayNode.dataIp().getIp4Address()),
+                        instPort.deviceId())
+                .setOutput(osNodeService.node(instPort.deviceId()).tunnelPortNum())
+                .build();
+
+        osFlowRuleService.setRule(
+                appId,
+                instPort.deviceId(),
+                sBuilder.build(),
+                treatment,
+                PRIORITY_EXTERNAL_FLOATING_ROUTING_RULE,
+                ROUTING_TABLE,
+                install);
+    }
+
+    private OpenstackNode selectGatewayNode() {
+        //TODO support multiple loadbalancing options.
+        return osNodeService.completeNodes(GATEWAY).stream().findAny().orElse(null);
+    }
+
     private void setDownstreamRules(NetFloatingIP floatingIp, Network osNet,
                                     InstancePort instPort, boolean install) {
         OpenstackNode cNode = osNodeService.node(instPort.deviceId());
@@ -281,11 +338,17 @@
                 throw new IllegalStateException(error);
         }
 
+        MacAddress externalPeerRouterMac = externalPeerRouterMac(osNet);
+        if (externalPeerRouterMac == null) {
+            return;
+        }
+
+
         osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
             TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
                     .setIpSrc(floating.getIp4Address())
-                    .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
-                    .setEthDst(Constants.DEFAULT_EXTERNAL_ROUTER_MAC);
+                    .setEthSrc(instPort.macAddress())
+                    .setEthDst(externalPeerRouterMac);
 
             if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
                 tBuilder.popVlan();
@@ -295,13 +358,43 @@
                     appId,
                     gNode.intgBridge(),
                     sBuilder.build(),
-                    tBuilder.setOutput(gNode.patchPortNum()).build(),
+                    tBuilder.setOutput(gNode.uplinkPortNum()).build(),
                     PRIORITY_FLOATING_EXTERNAL,
                     GW_COMMON_TABLE,
                     install);
         });
     }
 
+    private MacAddress externalPeerRouterMac(Network network) {
+        if (network == null) {
+            return null;
+        }
+
+        Subnet subnet = osNetworkService.subnets(network.getId()).stream().findAny().orElse(null);
+
+        if (subnet == null) {
+            return null;
+        }
+
+        RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
+                .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
+                .findAny().orElse(null);
+        if (osRouterIface == null) {
+            return null;
+        }
+
+        Router osRouter = osRouterService.router(osRouterIface.getId());
+        if (osRouter == null) {
+            return null;
+        }
+        if (osRouter.getExternalGatewayInfo() == null) {
+            return null;
+        }
+
+        ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
+
+        return osNetworkService.externalPeerRouterMac(exGatewayInfo);
+    }
     private class InternalFloatingIpListener implements OpenstackRouterListener {
 
         @Override
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
index d833c41..13c9e18 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingIcmpHandler.java
@@ -68,7 +68,6 @@
 import static com.google.common.base.Preconditions.checkArgument;
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
 import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
 import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
@@ -194,6 +193,12 @@
             return;
         }
 
+        MacAddress externalPeerRouterMac = externalPeerRouterMac(srcSubnet);
+        if (externalPeerRouterMac == null) {
+            log.trace(ERR_REQ + "failed to get external peer router mac");
+            return;
+        }
+
         if (isForSubnetGateway(IpAddress.valueOf(ipPacket.getDestinationAddress()),
                 srcSubnet)) {
             // this is a request for the subnet gateway
@@ -204,17 +209,44 @@
             if (externalIp == null) {
                 return;
             }
-            sendRequestForExternal(ipPacket, srcDevice, externalIp);
+
+            sendRequestForExternal(ipPacket, srcDevice, externalIp, externalPeerRouterMac(srcSubnet));
             String icmpInfoKey = String.valueOf(getIcmpId(icmp))
                     .concat(String.valueOf(externalIp.getIp4Address().toInt()))
                     .concat(String.valueOf(ipPacket.getDestinationAddress()));
-            icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
-                checkArgument(existing == null, ERR_DUPLICATE);
-                return instPort;
-            });
+            try {
+                icmpInfoMap.compute(icmpInfoKey, (id, existing) -> {
+                    checkArgument(existing == null, ERR_DUPLICATE);
+                    return instPort;
+                });
+            } catch (IllegalArgumentException e) {
+                log.warn("Exception occurred because of {}", e.toString());
+            }
+
         }
     }
 
+    private MacAddress externalPeerRouterMac(Subnet subnet) {
+        RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
+                .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
+                .findAny().orElse(null);
+        if (osRouterIface == null) {
+            return null;
+        }
+
+        Router osRouter = osRouterService.router(osRouterIface.getId());
+        if (osRouter == null) {
+            return null;
+        }
+        if (osRouter.getExternalGatewayInfo() == null) {
+            return null;
+        }
+
+        ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
+
+        return osNetworkService.externalPeerRouterMac(exGatewayInfo);
+    }
+
     private void handleEchoReply(IPv4 ipPacket, ICMP icmp) {
         String icmpInfoKey = String.valueOf(getIcmpId(icmp))
                 .concat(String.valueOf(ipPacket.getDestinationAddress()))
@@ -322,7 +354,8 @@
         sendReply(icmpReply, instPort);
     }
 
-    private void sendRequestForExternal(IPv4 ipPacket, DeviceId srcDevice, IpAddress srcNatIp) {
+    private void sendRequestForExternal(IPv4 ipPacket, DeviceId srcDevice,
+                                        IpAddress srcNatIp, MacAddress externalRouterMac) {
         ICMP icmpReq = (ICMP) ipPacket.getPayload();
         icmpReq.resetChecksum();
         ipPacket.setSourceAddress(srcNatIp.getIp4Address().toInt()).resetChecksum();
@@ -331,7 +364,7 @@
         Ethernet icmpRequestEth = new Ethernet();
         icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
                 .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
-                .setDestinationMACAddress(DEFAULT_EXTERNAL_ROUTER_MAC)
+                .setDestinationMACAddress(externalRouterMac)
                 .setPayload(ipPacket);
 
         OpenstackNode osNode = osNodeService.node(srcDevice);
@@ -341,7 +374,7 @@
             throw new IllegalStateException(error);
         }
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(osNode.patchPortNum())
+                .setOutput(osNode.uplinkPortNum())
                 .build();
 
         OutboundPacket packet = new DefaultOutboundPacket(
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
index 7beb11d..5ea8442 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
@@ -73,7 +73,10 @@
 
 import static java.util.concurrent.Executors.newSingleThreadExecutor;
 import static org.onlab.util.Tools.groupedThreads;
-import static org.onosproject.openstacknetworking.api.Constants.*;
+import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC;
+import static org.onosproject.openstacknetworking.api.Constants.GW_COMMON_TABLE;
+import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
+import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SNAT_RULE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -189,7 +192,7 @@
             return;
         }
 
-        MacAddress externalPeerRouterMac = getExternalPeerRouterMac(srcSubnet);
+        MacAddress externalPeerRouterMac = externalPeerRouterMac(srcSubnet);
         if (externalPeerRouterMac == null) {
             return;
         }
@@ -205,6 +208,27 @@
                 externalGatewayIp, externalPeerRouterMac);
     }
 
+    private MacAddress externalPeerRouterMac(Subnet subnet) {
+        RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
+                .filter(i -> Objects.equals(i.getSubnetId(), subnet.getId()))
+                .findAny().orElse(null);
+        if (osRouterIface == null) {
+            return null;
+        }
+
+        Router osRouter = osRouterService.router(osRouterIface.getId());
+        if (osRouter == null) {
+            return null;
+        }
+        if (osRouter.getExternalGatewayInfo() == null) {
+            return null;
+        }
+
+        ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
+
+        return osNetworkService.externalPeerRouterMac(exGatewayInfo);
+    }
+
     private Subnet getSourceSubnet(InstancePort instance, IpAddress srcIp) {
         Port osPort = osNetworkService.port(instance.portId());
         IP fixedIp = osPort.getFixedIps().stream()
@@ -216,32 +240,6 @@
         return osNetworkService.subnet(fixedIp.getSubnetId());
     }
 
-    private MacAddress getExternalPeerRouterMac(Subnet srcSubnet) {
-        RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
-                .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
-                .findAny().orElse(null);
-        if (osRouterIface == null) {
-            // this subnet is not connected to the router
-            log.trace(ERR_PACKETIN + "source subnet(ID:{}, CIDR:{}) has no router",
-                    srcSubnet.getId(), srcSubnet.getCidr());
-            return null;
-        }
-
-        Router osRouter = osRouterService.router(osRouterIface.getId());
-        if (osRouter == null) {
-            return null;
-        }
-        if (osRouter.getExternalGatewayInfo() == null) {
-            // this router does not have external connectivity
-            log.trace(ERR_PACKETIN + "router({}) has no external gateway",
-                    osRouter.getName());
-            return null;
-        }
-
-        ExternalGateway exGatewayInfo = osRouter.getExternalGatewayInfo();
-
-        return osNetworkService.externalPeerRouterMac(exGatewayInfo);
-    }
     private IpAddress getExternalIp(Subnet srcSubnet) {
         RouterInterface osRouterIface = osRouterService.routerInterfaces().stream()
                 .filter(i -> Objects.equals(i.getSubnetId(), srcSubnet.getId()))
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
index 2e40769..37cabf4 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
@@ -40,8 +40,6 @@
 import org.onosproject.openstacknetworking.api.InstancePortListener;
 import org.onosproject.openstacknetworking.api.InstancePortService;
 import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
-import org.onosproject.openstacknetworking.api.OpenstackNetworkEvent;
-import org.onosproject.openstacknetworking.api.OpenstackNetworkListener;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
 import org.onosproject.openstacknetworking.api.OpenstackSecurityGroupService;
 import org.onosproject.openstacknode.api.OpenstackNode;
@@ -62,12 +60,6 @@
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_TUNNEL_TAG_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.SRC_VNI_TABLE;
-import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_CREATED;
-import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_REMOVED;
-import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_NETWORK_UPDATED;
-import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_CREATED;
-import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_REMOVED;
-import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_UPDATED;
 import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -114,15 +106,12 @@
     private final ExecutorService eventExecutor = newSingleThreadExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler"));
     private final InstancePortListener instancePortListener = new InternalInstancePortListener();
-    private final InternalOpenstackNetworkListener osNetworkListener =
-            new InternalOpenstackNetworkListener();
     private ApplicationId appId;
 
     @Activate
     void activate() {
         appId = coreService.registerApplication(OPENSTACK_NETWORKING_APP_ID);
         instancePortService.addListener(instancePortListener);
-        osNetworkService.addListener(osNetworkListener);
 
         log.info("Started");
     }
@@ -130,7 +119,6 @@
     @Deactivate
     void deactivate() {
         instancePortService.removeListener(instancePortListener);
-        osNetworkService.removeListener(osNetworkListener);
         eventExecutor.shutdown();
 
         log.info("Stopped");
@@ -418,35 +406,4 @@
             // TODO add something else if needed
         }
     }
-
-    private class InternalOpenstackNetworkListener implements OpenstackNetworkListener {
-
-        @Override
-        public boolean isRelevant(OpenstackNetworkEvent event) {
-            return !(event.subject() == null && event.port() == null);
-        }
-
-        @Override
-        public void event(OpenstackNetworkEvent event) {
-            try {
-                if ((event.type() == OPENSTACK_NETWORK_CREATED ||
-                        event.type() == OPENSTACK_NETWORK_UPDATED) && !event.subject().isAdminStateUp()) {
-                    setNetworkAdminRules(event.subject(), true);
-                } else if ((event.type() == OPENSTACK_NETWORK_UPDATED && event.subject().isAdminStateUp()) ||
-                        (event.type() == OPENSTACK_NETWORK_REMOVED && !event.subject().isAdminStateUp())) {
-                    setNetworkAdminRules(event.subject(), false);
-                }
-
-                if ((event.type() == OPENSTACK_PORT_CREATED ||
-                        event.type() == OPENSTACK_PORT_UPDATED) && !event.port().isAdminStateUp()) {
-                    setPortAdminRules(event.port(), true);
-                } else if ((event.type() == OPENSTACK_PORT_UPDATED && event.port().isAdminStateUp()) ||
-                        (event.type() == OPENSTACK_PORT_REMOVED && !event.port().isAdminStateUp())) {
-                    setPortAdminRules(event.port(), false);
-                }
-            } catch (Exception e) {
-                log.error("Exception occurred while processing OpenstackNetworkEvent because of {}", e.toString());
-            }
-        }
-    }
 }
diff --git a/apps/openstacknetworking/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/openstacknetworking/src/main/resources/OSGI-INF/blueprint/shell-config.xml
index 179c3ff..d3884df 100644
--- a/apps/openstacknetworking/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/openstacknetworking/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -55,6 +55,15 @@
         </command>
         <command>
             <action class="org.onosproject.openstacknetworking.cli.UpdateExternalPeerRouterVlanCommand"/>
+            <completers>
+                <ref component-id="ipAddressCompleter"/>
+            </completers>
+        </command>
+        <command>
+            <action class="org.onosproject.openstacknetworking.cli.DeleteExternalPeerRouterCommand" />
+            <completers>
+                <ref component-id="ipAddressCompleter"/>
+            </completers>
         </command>
     </command-bundle>