[ONOS-3697] Remove flow rules and dhcp mapping for router when it is removed.

Change-Id: I24e7c6d3fa0731822250c84ac5807f6192d371bf
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackPortInfo.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackPortInfo.java
index 6207228..1b6250e 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackPortInfo.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackPortInfo.java
@@ -16,6 +16,7 @@
 package org.onosproject.openstackswitching.impl;
 
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -27,11 +28,13 @@
 
     private final Ip4Address hostIp;
     private final DeviceId deviceId;
+    private final MacAddress hostMac;
     private final long vni;
 
-    public OpenstackPortInfo(Ip4Address hostIp, DeviceId deviceId,
+    public OpenstackPortInfo(Ip4Address hostIp, MacAddress hostMac, DeviceId deviceId,
                              long vni) {
         this.hostIp = hostIp;
+        this.hostMac = hostMac;
         this.deviceId = deviceId;
         this.vni = vni;
     }
@@ -40,6 +43,10 @@
         return hostIp;
     }
 
+    public MacAddress mac() {
+        return hostMac;
+    }
+
     public DeviceId deviceId() {
         return deviceId;
     }
@@ -54,6 +61,7 @@
 
     public static final class Builder {
         private Ip4Address hostIp;
+        private MacAddress hostMac;
         private DeviceId deviceId;
         private long vni;
 
@@ -62,6 +70,11 @@
             return this;
         }
 
+        public Builder setHostMac(MacAddress hostMac) {
+            this.hostMac = checkNotNull(hostMac, "hostMac cannot be bull");
+            return this;
+        }
+
         public Builder setDeviceId(DeviceId deviceId) {
             this.deviceId = checkNotNull(deviceId, "deviceId cannot be null");
             return this;
@@ -78,6 +91,7 @@
 
     private OpenstackPortInfo(Builder builder) {
         hostIp = builder.hostIp;
+        hostMac = builder.hostMac;
         deviceId = builder.deviceId;
         vni = builder.vni;
     }
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingManager.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingManager.java
index a1b2f06..49dff3f 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingManager.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingManager.java
@@ -104,10 +104,12 @@
     protected DriverService driverService;
 
     public static final String PORTNAME_PREFIX_VM = "tap";
-    public static final String PORTNAME_PREFIX_ROUTER = "qr";
+    public static final String PORTNAME_PREFIX_ROUTER = "qr-";
     public static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
     public static final String PORTNAME = "portName";
 
+    public static final String DEVICE_OWNER_GATEWAY = "network:router_gateway";
+
     private ApplicationId appId;
     private boolean doNotPushFlows;
     private Ip4Address neutronServer;
@@ -170,14 +172,38 @@
 
     @Override
     public void createPorts(OpenstackPort openstackPort) {
-        if (!openstackPort.fixedIps().isEmpty()) {
+        if (!openstackPort.fixedIps().isEmpty()
+                && !openstackPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
             registerDhcpInfo(openstackPort);
         }
     }
 
     @Override
     public void deletePort(String uuid) {
+        // When VMs are remvoed, the flow rules for the VMs are removed using ONOS port update event.
+        // But, when router is removed, no ONOS port event occurs and we need to use Neutron port event.
+        // Here we should not touch any rules for VMs.
+        log.debug("port {} was removed", uuid);
 
+        String routerPortName = PORTNAME_PREFIX_ROUTER + uuid.substring(0, 11);
+        OpenstackPortInfo routerPortInfo = openstackPortInfoMap.get(routerPortName);
+        if (routerPortInfo != null) {
+            dhcpService.removeStaticMapping(routerPortInfo.mac());
+            if (!doNotPushFlows) {
+                deviceService.getPorts(routerPortInfo.deviceId()).forEach(port -> {
+                    String pName = port.annotations().value("portName");
+                    if (pName.equals(routerPortName)) {
+                        OpenstackSwitchingRulePopulator rulePopulator =
+                                new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
+                                        deviceService, restHandler, driverService);
+
+                        rulePopulator.removeSwitchingRules(doNotPushFlows, port, openstackPortInfoMap);
+                        openstackPortInfoMap.remove(routerPortName);
+                        return;
+                    }
+                });
+            }
+        }
     }
 
     @Override
@@ -268,17 +294,17 @@
                 OpenstackSwitchingRulePopulator rulePopulator =
                         new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
                                 deviceService, restHandler, driverService);
-                rulePopulator.populateSwitchingRules(device, port);
+                rulePopulator.populateSwitchingRules(doNotPushFlows, device, port);
                 updatePortMap(device.id(), port, restHandler.getNetworks(), rulePopulator.openstackPort(port));
-
                 //In case portupdate event is driven by vm shutoff from openstack
             } else if (!port.isEnabled() && openstackPortInfoMap.containsKey(port.annotations().value(PORTNAME))) {
                 log.debug("Flowrules according to the port {} were removed", port.number().toString());
                 OpenstackSwitchingRulePopulator rulePopulator =
                         new OpenstackSwitchingRulePopulator(appId, flowObjectiveService,
                                 deviceService, restHandler, driverService);
-                openstackPortInfoMap.get(port.annotations().value(PORTNAME));
-                rulePopulator.removeSwitchingRules(port, openstackPortInfoMap);
+
+                rulePopulator.removeSwitchingRules(doNotPushFlows, port, openstackPortInfoMap);
+                dhcpService.removeStaticMapping(openstackPortInfoMap.get(port.annotations().value(PORTNAME)).mac());
                 openstackPortInfoMap.remove(port.annotations().value(PORTNAME));
             }
         }
@@ -303,9 +329,9 @@
                                     port.annotations().value(PORTNAME).startsWith(PORTNAME_PREFIX_ROUTER))
                             .forEach(vmPort -> {
                                         OpenstackPort osPort = rulePopulator.openstackPort(vmPort);
-                                        if (osPort != null) {
+                                        if (osPort != null && !osPort.deviceOwner().equals(DEVICE_OWNER_GATEWAY)) {
                                             if (!doNotPushFlows) {
-                                                rulePopulator.populateSwitchingRules(device, vmPort);
+                                                rulePopulator.populateSwitchingRules(doNotPushFlows, device, vmPort);
                                                 updatePortMap(device.id(), vmPort, networks, osPort);
                                             }
                                             registerDhcpInfo(osPort);
@@ -327,6 +353,7 @@
         OpenstackPortInfo.Builder portBuilder = OpenstackPortInfo.builder()
                 .setDeviceId(deviceId)
                 .setHostIp((Ip4Address) openstackPort.fixedIps().values().stream().findFirst().orElse(null))
+                .setHostMac(openstackPort.macAddress())
                 .setVni(vni);
 
         openstackPortInfoMap.putIfAbsent(port.annotations().value(PORTNAME),
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingRulePopulator.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingRulePopulator.java
index 119e0ff..cc94c93 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingRulePopulator.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/impl/OpenstackSwitchingRulePopulator.java
@@ -99,7 +99,10 @@
      * @param device device to populate rules to
      * @param port port for the VM created
      */
-    public void populateSwitchingRules(Device device, Port port) {
+    public void populateSwitchingRules(boolean doNotPushFlow, Device device, Port port) {
+        if (doNotPushFlow) {
+            return;
+        }
         populateFlowRulesForTunnelTag(device, port);
         populateFlowRulesForTrafficToSameCnode(device, port);
         populateFlowRulesForTrafficToDifferentCnode(device, port);
@@ -271,8 +274,11 @@
      * @param removedPort removedport info
      * @param openstackPortInfoMap openstackPortInfoMap
      */
-    public void removeSwitchingRules(Port removedPort, Map<String, OpenstackPortInfo> openstackPortInfoMap) {
-
+    public void removeSwitchingRules(boolean doNotPushFlows, Port removedPort, Map<String,
+            OpenstackPortInfo> openstackPortInfoMap) {
+        if (doNotPushFlows) {
+            return;
+        }
         OpenstackPortInfo openstackPortInfo = openstackPortInfoMap
                 .get(removedPort.annotations().value("portName"));
 
diff --git a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java
index 261128d..4e23753 100644
--- a/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java
+++ b/apps/openstackswitching/app/src/main/java/org/onosproject/openstackswitching/web/OpenstackPortWebResource.java
@@ -72,6 +72,9 @@
     @Path("{portUUID}")
     @DELETE
     public Response deletePorts(@PathParam("portUUID") String id) {
+        OpenstackSwitchingService switchingService =
+                getService(OpenstackSwitchingService.class);
+        switchingService.deletePort(id);
         return Response.status(Response.Status.OK).build();
     }