[ONOS-3952] Implement FloatingIP Handler for OpenstackRoutingService

 - Implements floatingIp REST interfaces & event handler
 - Implements rulePopulate method for floatingIp handler
 - Fixes minor logics
 - Changes app structure
 - exports configuration
 - Implements case issue.
   when openstack deletes vm w/o deassociating floatingIp,
   openstack doesn`t send floatingIp deassociation event.

Change-Id: If4d8ac3fecfed1957d84139f94ae31f593a9097b
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackRoutingService.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackRoutingService.java
index c6627af..0d4e7d6 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackRoutingService.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/OpenstackRoutingService.java
@@ -80,5 +80,11 @@
      */
     void removeRouterInterface(OpenstackRouterInterface openstackRouterInterface);
 
-
+    /**
+     * Checks floatingIp deassociation when corresponding deleted vm.
+     *
+     * @param portId Deleted vm
+     * @param portInfo
+     */
+    void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo);
 }
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java
index 8f861a9..9367ea5 100644
--- a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackFloatingIPHandler.java
@@ -15,20 +15,34 @@
  */
 package org.onosproject.openstacknetworking.routing;
 
-        import org.onosproject.event.AbstractEvent;
+import org.onosproject.openstackinterface.OpenstackFloatingIP;
+import org.onosproject.openstacknetworking.OpenstackPortInfo;
 
 /**
  * Handle FloatingIP Event for Managing Flow Rules In Openstack Nodes.
  */
 public class OpenstackFloatingIPHandler implements Runnable {
 
-    volatile AbstractEvent event;
-    OpenstackFloatingIPHandler(AbstractEvent event) {
-        this.event = event;
+    private final OpenstackFloatingIP floatingIP;
+    private final OpenstackRoutingRulePopulator rulePopulator;
+    private boolean associate;
+    private final OpenstackPortInfo portInfo;
+
+    OpenstackFloatingIPHandler(OpenstackRoutingRulePopulator rulePopulator,
+                               OpenstackFloatingIP openstackFloatingIP, boolean associate, OpenstackPortInfo portInfo) {
+        this.floatingIP = openstackFloatingIP;
+        this.rulePopulator = rulePopulator;
+        this.associate = associate;
+        this.portInfo = portInfo;
     }
 
     @Override
     public void run() {
+        if (associate) {
+            rulePopulator.populateFloatingIpRules(floatingIP);
+        } else {
+            rulePopulator.removeFloatingIpRules(floatingIP, portInfo);
+        }
 
     }
 }
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
index 4d9b60a..2912d7d 100644
--- a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackPnatHandler.java
@@ -56,19 +56,18 @@
     private final int portNum;
     private final OpenstackPort openstackPort;
     private final Port port;
+    private OpenstackRoutingConfig config;
 
     private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
-    // TODO: This will be replaced to get the information from openstacknetworkingservice.
-    private static final MacAddress GATEWAYMAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
-    private static final MacAddress EXTERNAL_INTERFACE_MAC = MacAddress.valueOf("00:00:00:00:00:11");
 
     OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
-                         int portNum, OpenstackPort openstackPort, Port port) {
+                         int portNum, OpenstackPort openstackPort, Port port, OpenstackRoutingConfig config) {
         this.rulePopulator = checkNotNull(rulePopulator);
         this.context = checkNotNull(context);
         this.portNum = checkNotNull(portNum);
         this.openstackPort = checkNotNull(openstackPort);
         this.port = checkNotNull(port);
+        this.config = checkNotNull(config);
     }
 
     @Override
@@ -85,7 +84,8 @@
         OpenstackRouter router = getOpenstackRouter(openstackPort);
 
         rulePopulator.populatePnatFlowRules(inboundPacket, openstackPort, portNum,
-                getExternalIp(router), getExternalInterfaceMacAddress(), getExternalRouterMacAddress());
+                getExternalIp(router), MacAddress.valueOf(config.gatewayExternalInterfaceMac()),
+                MacAddress.valueOf(config.physicalRouterMac()));
 
         packetOut((Ethernet) ethernet.clone(), inboundPacket.receivedFrom().deviceId(), portNum, router);
     }
@@ -144,8 +144,9 @@
         iPacket.setSourceAddress(getExternalIp(router).toString());
         iPacket.resetChecksum();
         iPacket.setParent(ethernet);
-        ethernet.setSourceMACAddress(getExternalInterfaceMacAddress())
-                .setDestinationMACAddress(getExternalRouterMacAddress());
+        ethernet.setPayload(iPacket);
+        ethernet.setSourceMACAddress(config.gatewayExternalInterfaceMac())
+                .setDestinationMACAddress(config.physicalRouterMac());
         ethernet.resetChecksum();
 
         treatment.setOutput(port.number());
@@ -153,11 +154,4 @@
         packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(),
                 ByteBuffer.wrap(ethernet.serialize())));
     }
-
-    private MacAddress getExternalInterfaceMacAddress() {
-        return EXTERNAL_INTERFACE_MAC;
-    }
-    private MacAddress getExternalRouterMacAddress() {
-        return GATEWAYMAC;
-    }
 }
\ No newline at end of file
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
index 2ab19ac..edc340b 100644
--- a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingManager.java
@@ -16,7 +16,6 @@
 package org.onosproject.openstacknetworking.routing;
 
 import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -28,6 +27,7 @@
 import org.onlab.packet.Ip4Address;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.UDP;
+import org.onlab.util.KryoNamespace;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.DeviceId;
@@ -50,14 +50,18 @@
 import org.onosproject.openstackinterface.OpenstackPort;
 import org.onosproject.openstackinterface.OpenstackRouter;
 import org.onosproject.openstackinterface.OpenstackRouterInterface;
+import org.onosproject.openstacknetworking.OpenstackPortInfo;
 import org.onosproject.openstacknetworking.OpenstackRoutingService;
 import org.onosproject.openstacknetworking.OpenstackSwitchingService;
+import org.onosproject.store.serializers.KryoNamespaces;
+import org.onosproject.store.service.ConsistentMap;
+import org.onosproject.store.service.Serializer;
+import org.onosproject.store.service.StorageService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
 import java.util.List;
-import java.util.Map;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
@@ -101,14 +105,21 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected NetworkConfigRegistry configRegistry;
 
-
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
 
     private ApplicationId appId;
-    private Map<String, OpenstackRouterInterface> routerInterfaceMap = Maps.newHashMap();
-    private Map<Integer, String> portNumMap = initPortNumMap();
+    private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
+    private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
     private static final String APP_ID = "org.onosproject.openstackrouting";
     private static final String PORT_NAME = "portName";
+    private static final String PORTNAME_PREFIX_VM = "tap";
     private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
+    private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
+    private static final String TP_PORT_MAP_NAME = "openstackrouting-portnum";
+    private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
+    private static final int TP_PORT_MINIMUM_NUM = 1024;
+    private static final int TP_PORT_MAXIMUM_NUM = 65535;
     private final ConfigFactory configFactory =
             new ConfigFactory(SubjectFactories.APP_SUBJECT_FACTORY, OpenstackRoutingConfig.class, "openstackrouting") {
                 @Override
@@ -119,16 +130,19 @@
     private final NetworkConfigListener configListener = new InternalConfigListener();
 
     private OpenstackRoutingConfig config;
-    private static final int PNAT_PORT_NUM_START = 1024;
-    private static final int PNAT_PORT_NUM_END = 65535;
+    private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
+            .register(KryoNamespaces.API)
+            .register(KryoNamespaces.MISC)
+            .register(OpenstackFloatingIP.FloatingIpStatus.class)
+            .register(OpenstackFloatingIP.class)
+            .register(Ip4Address.class)
+            .register(String.class);
 
-    private Map<Integer, String> initPortNumMap() {
-        Map<Integer, String> map = Maps.newHashMap();
-        for (int i = PNAT_PORT_NUM_START; i < PNAT_PORT_NUM_END; i++) {
-            map.put(i, "");
-        }
-        return map;
-    }
+    private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
+            .register(KryoNamespaces.API)
+            .register(KryoNamespaces.MISC)
+            .register(Integer.class)
+            .register(String.class);
 
     private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
     private ExecutorService l3EventExecutorService =
@@ -139,6 +153,7 @@
             Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
     private OpenstackIcmpHandler openstackIcmpHandler;
     private OpenstackRoutingArpHandler openstackArpHandler;
+    private OpenstackRoutingRulePopulator rulePopulator;
 
     @Activate
     protected void activate() {
@@ -149,6 +164,17 @@
 
         readConfiguration();
 
+        floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
+                .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
+                .withName(FLOATING_IP_MAP_NAME)
+                .withApplicationId(appId)
+                .build();
+        tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
+                .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
+                .withName(TP_PORT_MAP_NAME)
+                .withApplicationId(appId)
+                .build();
+
         log.info("onos-openstackrouting started");
     }
 
@@ -159,43 +185,92 @@
         icmpEventExecutorService.shutdown();
         arpEventExecutorService.shutdown();
 
+        floatingIpMap.clear();
+        tpPortNumMap.clear();
+
         log.info("onos-openstackrouting stopped");
     }
 
 
     @Override
     public void createFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
-
+        floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
     }
 
     @Override
     public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIP) {
-
+        if (!floatingIpMap.containsKey(openstackFloatingIP.id())) {
+            log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIP.id());
+            return;
+        }
+        if (openstackFloatingIP.portId() == null || openstackFloatingIP.portId().equals("null")) {
+            OpenstackFloatingIP floatingIP = floatingIpMap.get(openstackFloatingIP.id()).value();
+            OpenstackPortInfo portInfo = openstackSwitchingService.openstackPortInfo()
+                    .get(PORTNAME_PREFIX_VM.concat(floatingIP.portId().substring(0, 11)));
+            if (portInfo == null) {
+                log.warn("There`s no portInfo information about portId {}", floatingIP.portId());
+                return;
+            }
+            l3EventExecutorService.execute(
+                    new OpenstackFloatingIPHandler(rulePopulator, floatingIP, false, portInfo));
+            floatingIpMap.replace(floatingIP.id(), openstackFloatingIP);
+        } else {
+            floatingIpMap.put(openstackFloatingIP.id(), openstackFloatingIP);
+            l3EventExecutorService.execute(
+                    new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIP, true, null));
+        }
     }
 
     @Override
     public void deleteFloatingIP(String id) {
-
+        floatingIpMap.remove(id);
     }
 
     @Override
     public void createRouter(OpenstackRouter openstackRouter) {
-        checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
     }
 
     @Override
     public void updateRouter(OpenstackRouter openstackRouter) {
-        checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter));
+        if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
+            Ip4Address externalIp = openstackRouter.gatewayExternalInfo().externalFixedIps()
+                    .values().stream().findFirst().orElse(null);
+            OpenstackRouter router = getRouterfromExternalIp(externalIp);
+            checkExternalConnection(router, getOpenstackRouterInterface(router));
+        } else {
+            unsetExternalConnection();
+        }
+    }
+
+    private void unsetExternalConnection() {
+        Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
+        internalRouters.forEach(r ->
+                getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
+    }
+
+    private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) {
+        List<OpenstackRouter> routers;
+        if (externalConnection) {
+            routers = openstackService.routers()
+                    .stream()
+                    .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
+                    .collect(Collectors.toList());
+        } else {
+            routers = openstackService.routers()
+                    .stream()
+                    .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
+                    .collect(Collectors.toList());
+        }
+        return routers;
     }
 
     @Override
     public void deleteRouter(String id) {
-        //TODO
+        //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
     }
 
     @Override
     public void updateRouterInterface(OpenstackRouterInterface routerInterface) {
-        routerInterfaceMap.putIfAbsent(routerInterface.id(), routerInterface);
         List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList();
         routerInterfaces.add(routerInterface);
         checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces);
@@ -203,20 +278,55 @@
 
     @Override
     public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
-        OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
-                openstackService, flowObjectiveService, deviceService, driverService, config);
         rulePopulator.removeExternalRules(routerInterface);
-        routerInterfaceMap.remove(routerInterface.portId());
+    }
+
+    @Override
+    public void checkDisassociatedFloatingIp(String portId, OpenstackPortInfo portInfo) {
+        if (floatingIpMap.size() < 1) {
+            log.info("No information in FloatingIpMap");
+            return;
+        }
+        OpenstackFloatingIP floatingIp = associatedFloatingIps()
+                .stream()
+                .filter(fIp -> fIp.portId().equals(portId))
+                .findAny()
+                .orElse(null);
+        if (floatingIp != null && portInfo != null) {
+            l3EventExecutorService.execute(
+                    new OpenstackFloatingIPHandler(rulePopulator, floatingIp, false, portInfo));
+            OpenstackFloatingIP.Builder fBuilder = new OpenstackFloatingIP.Builder()
+                    .floatingIpAddress(floatingIp.floatingIpAddress())
+                    .id(floatingIp.id())
+                    .networkId(floatingIp.networkId())
+                    .status(floatingIp.status())
+                    .tenantId(floatingIp.tenantId());
+            floatingIpMap.replace(floatingIp.id(), fBuilder.build());
+        } else if (portInfo == null) {
+            log.warn("portInfo is null as timing issue between ovs port update event and openstack deletePort event");
+        }
+    }
+
+    private Collection<OpenstackFloatingIP> associatedFloatingIps() {
+        List<OpenstackFloatingIP> fIps = Lists.newArrayList();
+        floatingIpMap.values()
+                .stream()
+                .filter(fIp -> fIp.value().portId() != null)
+                .forEach(fIp -> fIps.add(fIp.value()));
+        return fIps;
     }
 
     private void reloadInitL3Rules() {
-        openstackService.ports()
-                .stream()
-                .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
-                .forEach(p -> {
-                    OpenstackRouterInterface routerInterface = portToRouterInterface(p);
-                    updateRouterInterface(routerInterface);
-                });
+        l3EventExecutorService.submit(() ->
+                        openstackService.ports()
+                                .stream()
+                                .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
+                                .forEach(p -> {
+                                    OpenstackRouterInterface routerInterface = portToRouterInterface(p);
+                                    updateRouterInterface(routerInterface);
+                                })
+        );
+
     }
 
     private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
@@ -249,8 +359,6 @@
                 return;
             } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
                 IPv4 iPacket = (IPv4) ethernet.getPayload();
-                OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
-                        openstackService, flowObjectiveService, deviceService, driverService, config);
                 switch (iPacket.getProtocol()) {
                     case IPv4.PROTOCOL_ICMP:
 
@@ -275,7 +383,7 @@
                         OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
                                 Ip4Address.valueOf(iPacket.getSourceAddress()));
                         l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
-                                portNum, openstackPort, port));
+                                portNum, openstackPort, port, config));
                         break;
                 }
             } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
@@ -285,11 +393,32 @@
         }
 
         private int getPortNum(MacAddress sourceMac, int destinationAddress) {
-            int portNum = portNumMap.keySet().stream()
-                    .filter(k -> portNumMap.get(k).equals("")).findFirst().orElse(0);
-            portNumMap.replace(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
+            int portNum = findUnusedPortNum();
+            if (portNum == 0) {
+                clearPortNumMap();
+                portNum = findUnusedPortNum();
+            }
+            tpPortNumMap.put(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
             return portNum;
         }
+
+        private int findUnusedPortNum() {
+            for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
+                if (!tpPortNumMap.containsKey(i)) {
+                    return i;
+                }
+            }
+            return 0;
+        }
+
+    }
+
+    private void clearPortNumMap() {
+        tpPortNumMap.entrySet().forEach(e -> {
+            if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
+                tpPortNumMap.remove(e.getKey());
+            }
+        });
     }
 
     private Port getExternalPort(DeviceId deviceId, String interfaceName) {
@@ -301,29 +430,55 @@
     }
 
     private void checkExternalConnection(OpenstackRouter router,
-                                         Collection<OpenstackRouterInterface> routerInterfaces) {
+                                         Collection<OpenstackRouterInterface> interfaces) {
         checkNotNull(router, "Router can not be null");
-        checkNotNull(routerInterfaces, "routerInterfaces can not be null");
+        checkNotNull(interfaces, "routerInterfaces can not be null");
         Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
                 .values().stream().findFirst().orElse(null);
         if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
             log.debug("Not satisfied to set pnat configuration");
             return;
         }
-        routerInterfaces.forEach(routerInterface -> initiateL3Rule(router, routerInterface));
+        if (router.id() == null) {
+            interfaces.forEach(i -> initiateL3Rule(getRouterfromExternalIp(externalIp), i));
+        } else {
+            interfaces.forEach(i -> initiateL3Rule(router, i));
+        }
+
+    }
+
+    private OpenstackRouter getRouterfromExternalIp(Ip4Address externalIp) {
+        OpenstackRouter router = getExternalRouter(true)
+                .stream()
+                .filter(r -> r.gatewayExternalInfo()
+                        .externalFixedIps()
+                        .values()
+                        .stream()
+                        .findFirst()
+                        .orElse(null)
+                        .equals(externalIp))
+                .findAny()
+                .orElse(null);
+        return checkNotNull(router);
     }
 
     private void initiateL3Rule(OpenstackRouter router, OpenstackRouterInterface routerInterface) {
         long vni = Long.parseLong(openstackService.network(openstackService
                 .port(routerInterface.portId()).networkId()).segmentId());
-        OpenstackRoutingRulePopulator rulePopulator = new OpenstackRoutingRulePopulator(appId,
-                openstackService, flowObjectiveService, deviceService, driverService, config);
         rulePopulator.populateExternalRules(vni, router, routerInterface);
     }
 
     private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) {
-        return routerInterfaceMap.values().stream().filter(i -> i.id().equals(router.id()))
-                .collect(Collectors.toList());
+        List<OpenstackRouterInterface> interfaces = Lists.newArrayList();
+        openstackService.ports()
+                .stream()
+                .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
+                .filter(p -> p.deviceId().equals(router.id()))
+                .forEach(p -> {
+                    OpenstackRouterInterface routerInterface = portToRouterInterface(p);
+                    interfaces.add(routerInterface);
+                });
+        return interfaces;
     }
 
     private OpenstackRouter getOpenstackRouter(String id) {
@@ -334,8 +489,8 @@
     private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) {
         OpenstackPort openstackPort = openstackService.ports().stream()
                 .filter(p -> p.macAddress().equals(sourceMac)).findFirst().orElse(null);
-        return checkNotNull(openstackPort.fixedIps().values().stream().findFirst().orElse(null))
-                .equals(ip4Address) ? openstackPort : null;
+        return openstackPort.fixedIps().values().stream().filter(ip ->
+                ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
     }
 
     private void readConfiguration() {
@@ -353,7 +508,8 @@
         log.debug("Configured info: {}, {}, {}, {}", config.physicalRouterMac(), config.gatewayBridgeId(),
                 config.gatewayExternalInterfaceMac(), config.gatewayExternalInterfaceName());
 
-        reloadInitL3Rules();
+        rulePopulator = new OpenstackRoutingRulePopulator(appId,
+                openstackService, flowObjectiveService, deviceService, driverService, config);
 
         openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService,
                 openstackService, config, openstackSwitchingService);
@@ -361,7 +517,7 @@
 
         openstackIcmpHandler.requestPacket(appId);
         openstackArpHandler.requestPacket(appId);
-
+        reloadInitL3Rules();
         log.info("OpenstackRouting configured");
     }
 
@@ -373,14 +529,12 @@
                 return;
             }
 
-            switch (event.type()) {
-                case CONFIG_ADDED:
-                case CONFIG_UPDATED:
-                    l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
-                    break;
-                default:
-                    log.debug("Unsupported event type {}", event.type().toString());
-                    break;
+            if (event.type().equals(NetworkConfigEvent.Type.CONFIG_ADDED) ||
+                    event.type().equals(NetworkConfigEvent.Type.CONFIG_UPDATED)) {
+                l3EventExecutorService.execute(OpenstackRoutingManager.this::readConfiguration);
+                rulePopulator = new OpenstackRoutingRulePopulator(appId,
+                        openstackService, flowObjectiveService, deviceService, driverService, config);
+
             }
         }
     }
diff --git a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
index ab1d360..1abcb63 100644
--- a/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
+++ b/apps/openstacknetworking/openstackrouting/src/main/java/org/onosproject/openstacknetworking/routing/OpenstackRoutingRulePopulator.java
@@ -52,6 +52,8 @@
 import org.onosproject.openstackinterface.OpenstackRouter;
 import org.onosproject.openstackinterface.OpenstackRouterInterface;
 import org.onosproject.openstackinterface.OpenstackSubnet;
+import org.onosproject.openstackinterface.OpenstackFloatingIP;
+import org.onosproject.openstacknetworking.OpenstackPortInfo;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -73,16 +75,17 @@
     private final DriverService driverService;
     private final OpenstackRoutingConfig config;
 
-    private static final String PORTNAME_PREFIX_VM = "tap";
-    private static final String PORTNAME_PREFIX_ROUTER = "qr";
     private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
     private static final String PORTNAME = "portName";
+    private static final String PORTNAME_PREFIX_VM = "tap";
 
     private static final String PORTNOTNULL = "Port can not be null";
+    private static final String DEVICENOTNULL = "Device can not be null";
     private static final String TUNNEL_DESTINATION = "tunnelDst";
     private static final String DEVICE_ANNOTATION_CHANNELID = "channelId";
     private static final int ROUTING_RULE_PRIORITY = 25000;
-    private static final int PNAT_RULE_PRIORITY = 24000;
+    private static final int FLOATING_RULE_PRIORITY = 42000;
+    private static final int PNAT_RULE_PRIORITY = 26000;
     private static final int PNAT_TIMEOUT = 120;
     private static final MacAddress GATEWAYMAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f");
 
@@ -134,7 +137,7 @@
         this.externalInterface = externalInterfaceMacAddress;
         this.externalRouter = externalRouterMacAddress;
 
-        long vni = getVni(openstackPort);
+        long vni = getVni(openstackPort.networkId());
 
         populatePnatIncomingFlowRules(vni, externalIp);
         populatePnatOutgoingFlowRules(vni, externalIp);
@@ -173,7 +176,7 @@
                 break;
         }
 
-        Port port = checkNotNull(getPortNumOfExternalInterface(), PORTNOTNULL);
+        Port port = checkNotNull(getPortOfExternalInterface(), PORTNOTNULL);
         tBuilder.setOutput(port.number());
 
         ForwardingObjective fo = DefaultForwardingObjective.builder()
@@ -188,8 +191,8 @@
         flowObjectiveService.forward(inboundPacket.receivedFrom().deviceId(), fo);
     }
 
-    private Port getPortNumOfExternalInterface() {
-        return deviceService.getPorts(inboundPacket.receivedFrom().deviceId()).stream()
+    private Port getPortOfExternalInterface() {
+        return deviceService.getPorts(getGatewayNode().id()).stream()
                 .filter(p -> p.annotations().value(PORTNAME).equals(config.gatewayExternalInterfaceName()))
                 .findAny().orElse(null);
     }
@@ -207,6 +210,7 @@
 
         TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
         tBuilder.setTunnelId(vni)
+                .setEthDst(inboundPacket.parsed().getSourceMAC())
                 .setIpDst(IpAddress.valueOf(iPacket.getSourceAddress()));
 
         switch (iPacket.getProtocol()) {
@@ -226,7 +230,7 @@
                 break;
         }
 
-        tBuilder.extension(buildNiciraExtenstion(deviceId, Ip4Address.valueOf(iPacket.getSourceAddress())), deviceId)
+        tBuilder.extension(buildNiciraExtenstion(deviceId, getHostIpfromOpenstackPort(openstackPort)), deviceId)
                 .setOutput(getTunnelPort(deviceId));
 
         ForwardingObjective fo = DefaultForwardingObjective.builder()
@@ -241,14 +245,37 @@
         flowObjectiveService.forward(inboundPacket.receivedFrom().deviceId(), fo);
     }
 
-    /**
-     * Returns NiciraExtension treatment.
-     *
-     * @param id device id
-     * @param hostIp host ip
-     * @return NiciraExtension treatment
-     */
+    private Ip4Address getHostIpfromOpenstackPort(OpenstackPort openstackPort) {
+        Device device = getDevicefromOpenstackPort(openstackPort);
+        return getIPAddressforDevice(device);
+    }
 
+    private Device getDevicefromOpenstackPort(OpenstackPort openstackPort) {
+        String openstackPortName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
+        Device device = StreamSupport.stream(deviceService.getDevices().spliterator(), false)
+                .filter(d -> findPortinDevice(d, openstackPortName))
+                .findAny()
+                .orElse(null);
+        checkNotNull(device, DEVICENOTNULL);
+        return device;
+    }
+
+    private boolean findPortinDevice(Device d, String openstackPortName) {
+        Port port = deviceService.getPorts(d.id())
+                .stream()
+                .filter(p -> p.isEnabled() && p.annotations().value(PORTNAME).equals(openstackPortName))
+                .findAny()
+                .orElse(null);
+        return port != null ? true : false;
+    }
+
+    /**
+     * Builds NiciraExtension for tagging remoteIp of vxlan.
+     *
+     * @param id Device Id of vxlan source device
+     * @param hostIp Remote Ip of vxlan destination device
+     * @return NiciraExtension Treatment
+     */
     public ExtensionTreatment buildNiciraExtenstion(DeviceId id, Ip4Address hostIp) {
         Driver driver = driverService.getDriver(id);
         DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, id));
@@ -270,8 +297,8 @@
     /**
      * Returns port number of vxlan tunnel.
      *
-     * @param deviceId device id
-     * @return port number of vxlan tunnel
+     * @param deviceId Target Device Id
+     * @return PortNumber
      */
     public PortNumber getTunnelPort(DeviceId deviceId) {
         Port port = deviceService.getPorts(deviceId).stream()
@@ -328,7 +355,7 @@
     private void populateComputeNodeRules(long vni) {
         Device gatewayDevice = getGatewayNode();
 
-        StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false)
+        StreamSupport.stream(deviceService.getDevices().spliterator(), false)
                 .filter(d -> !checkGatewayNode(d.id()))
                 .forEach(d -> populateRuleToGateway(d, gatewayDevice, vni));
     }
@@ -366,12 +393,8 @@
         return deviceId.toString().equals(config.gatewayBridgeId());
     }
 
-    private long getVni(OpenstackPort openstackPort) {
-        return Long.parseLong(openstackService.network(openstackPort.networkId()).segmentId());
-    }
-
-    private long getVni(OpenstackSubnet openstackSubnet) {
-        return Long.parseLong(openstackService.network(openstackSubnet.networkId()).segmentId());
+    private long getVni(String netId) {
+        return Long.parseLong(openstackService.network(netId).segmentId());
     }
 
     /**
@@ -383,32 +406,122 @@
         OpenstackSubnet openstackSubnet = openstackService.subnet(routerInterface.subnetId());
         TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
         sBuilder.matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(getVni(openstackSubnet))
+                .matchTunnelId(getVni(openstackSubnet.networkId()))
                 .matchEthDst(GATEWAYMAC);
 
-        StreamSupport.stream(deviceService.getAvailableDevices().spliterator(), false)
+        StreamSupport.stream(deviceService.getDevices().spliterator(), false)
                 .forEach(d -> {
                     if (checkGatewayNode(d.id())) {
-                        removeExternalRule(d.id(), sBuilder, ForwardingObjective.Flag.VERSATILE);
+                        removeRule(d.id(), sBuilder, ForwardingObjective.Flag.VERSATILE, ROUTING_RULE_PRIORITY);
                     } else {
-                        removeExternalRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC);
+                        removeRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC, ROUTING_RULE_PRIORITY);
                     }
                 });
 
     }
 
-    private void removeExternalRule(DeviceId id, TrafficSelector.Builder sBuilder, ForwardingObjective.Flag flag) {
+    private void removeRule(DeviceId id, TrafficSelector.Builder sBuilder,
+                            ForwardingObjective.Flag flag, int priority) {
         TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
 
         ForwardingObjective fo = DefaultForwardingObjective.builder()
                 .withSelector(sBuilder.build())
                 .withTreatment(tBuilder.build())
                 .withFlag(flag)
-                .withPriority(ROUTING_RULE_PRIORITY)
+                .withPriority(priority)
                 .fromApp(appId)
                 .remove();
 
         flowObjectiveService.forward(id, fo);
     }
 
+    /**
+     * Populates flow rules for floatingIp configuration.
+     *
+     * @param floatingIP Corresponding floating ip information
+     */
+    public void populateFloatingIpRules(OpenstackFloatingIP floatingIP) {
+        OpenstackPort port = openstackService.port(floatingIP.portId());
+        //1. incoming rules
+        populateFloatingIpIncomingRules(floatingIP, port);
+        //2. outgoing rules
+        populateFloatingIpOutgoingRules(floatingIP, port);
+    }
+
+    private void populateFloatingIpIncomingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
+        DeviceId portDeviceId = getDevicefromOpenstackPort(port).id();
+        Device gatewayNode = getGatewayNode();
+        Device portNode = deviceService.getDevice(portDeviceId);
+
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), 32));
+
+        tBuilder.setEthSrc(MacAddress.valueOf(config.gatewayExternalInterfaceMac()))
+                .setEthDst(port.macAddress())
+                .setIpDst(floatingIP.fixedIpAddress())
+                .setTunnelId(getVni(port.networkId()))
+                .extension(buildNiciraExtenstion(gatewayNode.id(), getIPAddressforDevice(portNode)), gatewayNode.id())
+                .setOutput(getTunnelPort(gatewayNode.id()));
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .withPriority(FLOATING_RULE_PRIORITY)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(getGatewayNode().id(), fo);
+
+    }
+
+    private void populateFloatingIpOutgoingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
+        Port outputPort = checkNotNull(getPortOfExternalInterface(), PORTNOTNULL);
+
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        sBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchTunnelId(getVni(port.networkId()))
+                .matchIPSrc(IpPrefix.valueOf(floatingIP.fixedIpAddress(), 32));
+
+        tBuilder.setIpSrc(floatingIP.floatingIpAddress())
+                .setEthSrc(MacAddress.valueOf(config.gatewayExternalInterfaceMac()))
+                .setEthDst(MacAddress.valueOf(config.physicalRouterMac()))
+                .setOutput(outputPort.number());
+
+        ForwardingObjective fo = DefaultForwardingObjective.builder()
+                .withSelector(sBuilder.build())
+                .withTreatment(tBuilder.build())
+                .withFlag(ForwardingObjective.Flag.VERSATILE)
+                .withPriority(FLOATING_RULE_PRIORITY)
+                .fromApp(appId)
+                .add();
+
+        flowObjectiveService.forward(getGatewayNode().id(), fo);
+    }
+
+    /**
+     * Removes flow rules for floating ip configuration.
+     *
+     * @param floatingIP Corresponding floating ip information
+     */
+    public void removeFloatingIpRules(OpenstackFloatingIP floatingIP, OpenstackPortInfo portInfo) {
+        TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
+        TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
+
+        sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchTunnelId(portInfo.vni())
+                .matchIPSrc(IpPrefix.valueOf(portInfo.ip(), 32));
+
+        sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), 32));
+
+        removeRule(getGatewayNode().id(), sOutgoingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
+        removeRule(getGatewayNode().id(), sIncomingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
+    }
+
 }
diff --git a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
index ce4fe52..e49ee18 100644
--- a/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
+++ b/apps/openstacknetworking/web/src/main/java/org/onosproject/openstacknetworking/web/OpenstackPortWebResource.java
@@ -19,6 +19,8 @@
 import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.openstackinterface.OpenstackPort;
 import org.onosproject.openstackinterface.web.OpenstackPortCodec;
+import org.onosproject.openstacknetworking.OpenstackPortInfo;
+import org.onosproject.openstacknetworking.OpenstackRoutingService;
 import org.onosproject.openstacknetworking.OpenstackSwitchingService;
 import org.onosproject.rest.AbstractWebResource;
 import org.slf4j.Logger;
@@ -42,7 +44,7 @@
 public class OpenstackPortWebResource extends AbstractWebResource {
 
     private final Logger log = LoggerFactory.getLogger(getClass());
-
+    private static final String PORTNAME_PREFIX_VM = "tap";
     private static final OpenstackPortCodec PORT_CODEC = new OpenstackPortCodec();
 
     @POST
@@ -75,7 +77,14 @@
     public Response deletePorts(@PathParam("portUUID") String id) {
         OpenstackSwitchingService switchingService =
                 getService(OpenstackSwitchingService.class);
+        OpenstackPortInfo portInfo = switchingService.openstackPortInfo()
+                .get(PORTNAME_PREFIX_VM.concat(id.substring(0, 11)));
+        OpenstackRoutingService routingService =
+                getService(OpenstackRoutingService.class);
+        routingService.checkDisassociatedFloatingIp(id, portInfo);
+
         switchingService.removePort(id);
+
         return Response.status(Response.Status.OK).build();
     }