[ONOS-4703,4704] SONA : Floating IP handling in SONA initialization

Generates flow rules for existing Floating IPs when SONA is initialized.

Change-Id: I0cb86345600c3cf3ee72fca176ae6d82e7a8cc36
diff --git a/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackInterfaceService.java b/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackInterfaceService.java
index 21c8515..fd6f953 100644
--- a/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackInterfaceService.java
+++ b/apps/openstackinterface/api/src/main/java/org/onosproject/openstackinterface/OpenstackInterfaceService.java
@@ -105,6 +105,15 @@
      * @param id security group id
      * @return security group information
      */
-    OpenstackSecurityGroup getSecurityGroup(String id);
+    OpenstackSecurityGroup securityGroup(String id);
+
+    /**
+     * Returns collection of OpenStack floating IP information.
+     *
+     * @return collection of OpenStack floating IP information
+     */
+    Collection<OpenstackFloatingIP> floatingIps();
+
+
 
 }
diff --git a/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/impl/OpenstackInterfaceManager.java b/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/impl/OpenstackInterfaceManager.java
index 722305c..f320330 100644
--- a/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/impl/OpenstackInterfaceManager.java
+++ b/apps/openstackinterface/app/src/main/java/org/onosproject/openstackinterface/impl/OpenstackInterfaceManager.java
@@ -33,6 +33,7 @@
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.openstackinterface.OpenstackFloatingIP;
 import org.onosproject.openstackinterface.OpenstackInterfaceService;
 import org.onosproject.openstackinterface.OpenstackNetwork;
 import org.onosproject.openstackinterface.OpenstackInterfaceConfig;
@@ -40,6 +41,7 @@
 import org.onosproject.openstackinterface.OpenstackRouter;
 import org.onosproject.openstackinterface.OpenstackSecurityGroup;
 import org.onosproject.openstackinterface.OpenstackSubnet;
+import org.onosproject.openstackinterface.web.OpenstackFloatingIpCodec;
 import org.onosproject.openstackinterface.web.OpenstackNetworkCodec;
 import org.onosproject.openstackinterface.web.OpenstackPortCodec;
 import org.onosproject.openstackinterface.web.OpenstackRouterCodec;
@@ -84,12 +86,14 @@
     private static final String URI_PORTS = "ports";
     private static final String URI_SUBNETS = "subnets";
     private static final String URI_SECURITY_GROUPS = "security-groups";
+    private static final String URI_FLOATINGIPS = "floatingips";
     private static final String URI_TOKENS = "tokens";
 
     private static final String PATH_ROUTERS = "routers";
     private static final String PATH_NETWORKS = "networks";
     private static final String PATH_PORTS = "ports";
     private static final String PATH_SUBNETS = "subnets";
+    private static final String PATH_FLOATINGIPS = "floatingips";
     private static final String PATH_ACCESS = "access";
     private static final String PATH_TOKEN = "token";
     private static final String PATH_ID = "id";
@@ -265,7 +269,7 @@
      * @param id Security Group ID
      * @return OpenstackSecurityGroup object or null if fails
      */
-    public OpenstackSecurityGroup getSecurityGroup(String id) {
+    public OpenstackSecurityGroup securityGroup(String id) {
         Invocation.Builder builder = getClientBuilder(neutronUrl + URI_SECURITY_GROUPS + "/" + id);
         String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
                 header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
@@ -277,7 +281,7 @@
             OpenstackSecurityGroupCodec sgCodec = new OpenstackSecurityGroupCodec();
             securityGroup = sgCodec.decode(node, null);
         } catch (IOException e) {
-            log.warn("getSecurityGroup()", e);
+            log.warn("securityGroup()", e);
         }
 
         return securityGroup;
@@ -414,6 +418,30 @@
                 .findAny().orElse(null);
     }
 
+    @Override
+    public Collection<OpenstackFloatingIP> floatingIps() {
+        Invocation.Builder builder = getClientBuilder(neutronUrl + URI_FLOATINGIPS);
+        String response = builder.accept(MediaType.APPLICATION_JSON_TYPE).
+                header(HEADER_AUTH_TOKEN, getToken()).get(String.class);
+
+        log.debug("floatingIps response:" + response);
+
+        ObjectMapper mapper = new ObjectMapper();
+        List<OpenstackFloatingIP> openstackFloatingIPs = Lists.newArrayList();
+        try {
+            ObjectNode node = (ObjectNode) mapper.readTree(response);
+            ArrayNode floatingIpList = (ArrayNode) node.path(PATH_FLOATINGIPS);
+            OpenstackFloatingIpCodec fipCodec = new OpenstackFloatingIpCodec();
+            floatingIpList.forEach(f -> openstackFloatingIPs.add(fipCodec.decode((ObjectNode) f, null)));
+        } catch (IOException e) {
+            log.warn("floatingIps()", e);
+        }
+
+        openstackFloatingIPs.removeAll(Collections.singleton(null));
+
+        return openstackFloatingIPs;
+    }
+
     private class InternalConfigListener implements NetworkConfigListener {
 
         public void configureNetwork() {
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 1a11552..406179a 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
@@ -295,8 +295,16 @@
         routerInterfaceMap.put(routerInterface.portId(), openstackService.port(routerInterface.portId()).networkId());
     }
 
+    /**
+     * Set flow rules for traffic between two different subnets when more than one subnets
+     * connected to a router.
+     *
+     * @param openstackRouter OpenstackRouter Info
+     * @param openstackPort OpenstackPort Info
+     */
     private void setL3Connection(OpenstackRouter openstackRouter, OpenstackPort openstackPort) {
         Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(openstackRouter);
+
         if (interfaceList.size() < 2) {
             return;
         }
@@ -308,7 +316,8 @@
                         .filter(p -> p.networkId().equals(interfacePort.networkId())
                                 && !p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
                         .forEach(p -> rulePopulator.populateL3Rules(p,
-                                getL3ConnectionList(p.networkId(), interfaceList)));
+                                    getL3ConnectionList(p.networkId(), interfaceList)));
+
             });
         } else {
             rulePopulator.populateL3Rules(openstackPort, getL3ConnectionList(openstackPort.networkId(), interfaceList));
@@ -397,13 +406,25 @@
     }
 
     private void reloadInitL3Rules() {
-        l3EventExecutorService.execute(() ->
-                        openstackService.ports()
-                                .stream()
-                                .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
-                                .forEach(p -> updateRouterInterface(portToRouterInterface(p)))
-        );
 
+        l3EventExecutorService.execute(() ->
+                openstackService.ports()
+                        .stream()
+                        .forEach(p ->
+                        {
+                            if (p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)) {
+                                updateRouterInterface(portToRouterInterface(p));
+                            } else {
+                                Optional<Ip4Address> vmIp = p.fixedIps().values().stream().findAny();
+                                if (vmIp.isPresent()) {
+                                    OpenstackFloatingIP floatingIP = getOpenstackFloatingIp(vmIp.get());
+                                    if (floatingIP != null) {
+                                        updateFloatingIP(floatingIP);
+                                    }
+                                }
+                            }
+                        })
+        );
     }
 
     private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
@@ -559,6 +580,19 @@
                 ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
     }
 
+    private OpenstackFloatingIP getOpenstackFloatingIp(Ip4Address vmIp) {
+        Optional<OpenstackFloatingIP> floatingIp = floatingIpMap.asJavaMap().values().stream()
+                .filter(f -> f.portId() != null && f.fixedIpAddress().equals(vmIp))
+                .findAny();
+
+        if (floatingIp.isPresent()) {
+            return floatingIp.get();
+        }
+        log.debug("There is no floating IP information for VM IP {}", vmIp);
+
+        return null;
+    }
+
     private void readConfiguration() {
         config = configService.getConfig("openstacknetworking", OpenstackNetworkingConfig.class);
         if (config == null) {
@@ -583,6 +617,10 @@
 
         openstackIcmpHandler.requestPacket(appId);
         openstackArpHandler.requestPacket(appId);
+
+        openstackService.floatingIps().stream()
+                .forEach(f -> floatingIpMap.put(f.id(), f));
+
         reloadInitL3Rules();
 
         log.info("OpenstackRouting configured");
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
index 5b132e8..dcc1c52 100644
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
+++ b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSecurityGroupRulePopulator.java
@@ -89,7 +89,7 @@
      */
     public void populateSecurityGroupRules(DeviceId id, String sgId, Ip4Address vmIp,
                                            Map<String, OpenstackPortInfo> portInfoMap) {
-        OpenstackSecurityGroup securityGroup = openstackService.getSecurityGroup(sgId);
+        OpenstackSecurityGroup securityGroup = openstackService.securityGroup(sgId);
         if (securityGroup != null) {
             securityGroup.rules().stream().forEach(sgRule -> {
                 if (sgRule.remoteGroupId() != null && !sgRule.remoteGroupId().equals("null")) {
@@ -105,7 +105,7 @@
 
             openstackService.ports().stream().forEach(osPort ->
                 osPort.securityGroups().stream().forEach(remoteVmSgId -> {
-                    OpenstackSecurityGroup remoteVmSg = openstackService.getSecurityGroup(remoteVmSgId);
+                    OpenstackSecurityGroup remoteVmSg = openstackService.securityGroup(remoteVmSgId);
                     remoteVmSg.rules().stream()
                         .filter(remoteVmSgRule -> remoteVmSgRule.remoteGroupId().equals(sgId))
                         .forEach(remoteVmSgRule -> {
diff --git a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
index b37df09..7f543a0 100644
--- a/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
+++ b/apps/openstacknetworking/openstackswitching/src/main/java/org/onosproject/openstacknetworking/switching/OpenstackSwitchingManager.java
@@ -374,7 +374,7 @@
 
         openstackPort.securityGroups().stream().forEach(sgId -> {
             if (!securityGroupMap.containsKey(sgId)) {
-                securityGroupMap.put(sgId, openstackService.getSecurityGroup(sgId));
+                securityGroupMap.put(sgId, openstackService.securityGroup(sgId));
             }
         });
     }