[ONOS-7863] Initial support GENEVE tunnel at SONA

Change-Id: Ia85d32e8068c22d59082dceccc0d911f8acb5f02
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
index 98bd413..e5301e5 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackNetworkManager.java
@@ -434,26 +434,31 @@
         Set<String> networkIds = Sets.newConcurrentHashSet();
 
         switch (type.toUpperCase()) {
-            case "FLAT" :
+            case Constants.FLAT :
                 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
                         .filter(e -> e.getValue().type() == FLAT)
                         .map(Map.Entry::getKey).collect(Collectors.toSet());
                 break;
-            case "VXLAN" :
+            case Constants.VXLAN :
                 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
-                        .filter(e -> e.getValue().type() == Type.VXLAN)
+                        .filter(e -> e.getValue().type() == VXLAN)
                         .map(Map.Entry::getKey).collect(Collectors.toSet());
                 break;
-            case "GRE" :
+            case Constants.GRE :
                 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
-                        .filter(e -> e.getValue().type() == Type.GRE)
+                        .filter(e -> e.getValue().type() == GRE)
                         .map(Map.Entry::getKey).collect(Collectors.toSet());
                 break;
-            case "VLAN" :
+            case Constants.VLAN :
                 networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
                         .filter(e -> e.getValue().type() == VLAN)
                         .map(Map.Entry::getKey).collect(Collectors.toSet());
                 break;
+            case Constants.GENEVE :
+                networkIds = augmentedNetworkMap.asJavaMap().entrySet().stream()
+                        .filter(e -> e.getValue().type() == GENEVE)
+                        .map(Map.Entry::getKey).collect(Collectors.toSet());
+                break;
             default:
                 break;
         }
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
index 5a324ee..a9eef09 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
@@ -83,6 +83,7 @@
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
+import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetworkEvent.Type.OPENSTACK_PORT_PRE_REMOVE;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.associatedFloatingIp;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.externalPeerRouterForNetwork;
@@ -341,9 +342,12 @@
             return;
         }
 
-        switch (osNet.getNetworkType()) {
+        Type netType = osNetworkService.networkType(osNet.getId());
+
+        switch (netType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
                         osNetworkService, osNodeService.node(instPort.deviceId()));
 
@@ -406,6 +410,11 @@
             final String error = String.format(errorFormat, floatingIp, cNode.hostname());
             throw new IllegalStateException(error);
         }
+        if (netType == GENEVE && cNode.dataIp() == null) {
+            final String errorFormat = ERR_FLOW + "GENEVE mode is not ready for %s";
+            final String error = String.format(errorFormat, floatingIp, cNode.hostname());
+            throw new IllegalStateException(error);
+        }
         if (netType == VLAN && cNode.vlanIntf() == null) {
             final String errorFormat = ERR_FLOW + "VLAN mode is not ready for %s";
             final String error = String.format(errorFormat, floatingIp, cNode.hostname());
@@ -436,9 +445,10 @@
             externalTreatmentBuilder.popVlan();
         }
 
-        switch (osNet.getNetworkType()) {
+        switch (netType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 PortNumber portNum = tunnelPortNumByNetId(instPort.networkId(),
                         osNetworkService, selectedGatewayNode);
                 externalTreatmentBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
@@ -479,9 +489,12 @@
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPSrc(instPort.ipAddress().toIpPrefix());
 
-        switch (osNet.getNetworkType()) {
+        Type netType = osNetworkService.networkType(osNet.getId());
+
+        switch (netType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
                 break;
             case VLAN:
@@ -494,7 +507,6 @@
         }
 
         TrafficSelector selector = sBuilder.build();
-        Type netType = osNetworkService.networkType(osNet.getId());
 
         osNodeService.completeNodes(GATEWAY).forEach(gNode -> {
             TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
index bc02119..d1864d7 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
@@ -96,7 +96,10 @@
 import static org.onosproject.openstacknetworking.api.Constants.STAT_OUTBOUND_TABLE;
 import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
+import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
+import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
+import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
 import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT;
 import static org.onosproject.openstacknetworking.impl.OsgiPropertyConstants.USE_STATEFUL_SNAT_DEFAULT;
 import static org.onosproject.openstacknetworking.util.OpenstackNetworkingUtil.tunnelPortNumByNetType;
@@ -460,21 +463,25 @@
 
         // take ICMP request to a subnet gateway through gateway node group
         Network net = osNetworkAdminService.network(osSubnet.getNetworkId());
+        Type netType = osNetworkAdminService.networkType(osSubnet.getNetworkId());
         Set<Subnet> routableSubnets = routableSubnets(osRouter, osSubnet.getId());
 
-        switch (net.getNetworkType()) {
+        switch (netType) {
             case VXLAN:
                 setGatewayIcmpForVxlan(osSubnet, srcNatGw, net, routableSubnets, install);
                 break;
             case GRE:
                 setGatewayIcmpForGre(osSubnet, srcNatGw, net, routableSubnets, install);
                 break;
+            case GENEVE:
+                setGatewayIcmpForGeneve(osSubnet, srcNatGw, net, routableSubnets, install);
+                break;
             case VLAN:
                 setGatewayIcmpForVlan(osSubnet, srcNatGw, net, routableSubnets, install);
                 break;
             default:
                 final String error = String.format("%s %s", ERR_UNSUPPORTED_NET_TYPE,
-                                                            net.getNetworkType().toString());
+                                                            netType.toString());
                 throw new IllegalStateException(error);
         }
 
@@ -502,7 +509,7 @@
                         network.getProviderSegID(),
                         osSubnet,
                         routableSubnets,
-                        Type.VXLAN,
+                        VXLAN,
                         install));
     }
 
@@ -519,7 +526,24 @@
                         network.getProviderSegID(),
                         osSubnet,
                         routableSubnets,
-                        Type.GRE,
+                        GRE,
+                        install));
+    }
+
+    private void setGatewayIcmpForGeneve(Subnet osSubnet,
+                                         OpenstackNode srcNatGw,
+                                         Network network,
+                                         Set<Subnet> routableSubnets,
+                                         boolean install) {
+        osNodeService.completeNodes(COMPUTE).stream()
+                .filter(cNode -> cNode.dataIp() != null)
+                .forEach(cNode -> setRulesToGatewayWithRoutableSubnets(
+                        cNode,
+                        srcNatGw,
+                        network.getProviderSegID(),
+                        osSubnet,
+                        routableSubnets,
+                        GENEVE,
                         install));
     }
 
@@ -629,6 +653,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 setInternalRouterRulesForTunnel(deviceId, srcSegId, dstSegId,
                                                 srcSubnet, dstSubnet, install);
                 break;
@@ -766,6 +791,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 sBuilder.matchTunnelId(Long.parseLong(segmentId));
                 break;
             case VLAN:
@@ -783,6 +809,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
                 tBuilder.extension(buildExtension(
                                 deviceService,
@@ -883,6 +910,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 sBuilder.matchTunnelId(Long.parseLong(segmentId));
 
                 PortNumber portNum = tunnelPortNumByNetType(networkType, osNode);
@@ -994,6 +1022,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 sBuilder.matchTunnelId(Long.parseLong(segmentId));
                 break;
             case VLAN:
@@ -1034,6 +1063,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 sBuilder.matchTunnelId(Long.parseLong(segmentId));
                 break;
             case VLAN:
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
index d1072cb..9ee5f3d 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
@@ -280,6 +280,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 tBuilder.setTunnelId(Long.parseLong(segmentId));
                 break;
             case VLAN:
@@ -334,6 +335,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 PortNumber portNum = tunnelPortNumByNetType(networkType, gNode);
                 tmpBuilder.extension(RulePopulatorUtil.buildExtension(
                         deviceService,
@@ -372,6 +374,7 @@
         switch (networkType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 sBuilder.matchTunnelId(Long.parseLong(segmentId));
                 break;
             case VLAN:
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
index 15920fe..140facf 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSecurityGroupHandler.java
@@ -107,6 +107,7 @@
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_DROP_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_HOOK_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_CT_RULE;
+import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
@@ -585,7 +586,7 @@
 
         if (netType == VLAN) {
             sBuilder.matchVlanId(VlanId.vlanId(segId));
-        } else if (netType == VXLAN || netType == GRE) {
+        } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
             sBuilder.matchTunnelId(Long.valueOf(segId));
         } else {
             log.warn("Cannot tag the VID due to lack of support of virtual network type {}", netType);
@@ -912,6 +913,7 @@
             switch (netType) {
                 case VXLAN:
                 case GRE:
+                case GENEVE:
                     sBuilder.matchTunnelId(Long.valueOf(segId));
                     break;
                 case VLAN:
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
index 3ac0c0d..0e09b03 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingArpHandler.java
@@ -86,6 +86,7 @@
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ARP_REQUEST_RULE;
 import static org.onosproject.openstacknetworking.api.InstancePort.State.ACTIVE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.FLAT;
+import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GENEVE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.GRE;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VLAN;
 import static org.onosproject.openstacknetworking.api.OpenstackNetwork.Type.VXLAN;
@@ -316,7 +317,7 @@
             if (netType == VLAN) {
                 sBuilder.matchVlanId(VlanId.vlanId(network.getProviderSegID()));
                 tBuilder.popVlan();
-            } else if (netType == VXLAN || netType == GRE) {
+            } else if (netType == VXLAN || netType == GRE || netType == GENEVE) {
                 // do not remove fake gateway ARP rules, if there is another gateway
                 // which has the same subnet that to be removed
                 // this only occurs if we have duplicated subnets associated with
@@ -381,6 +382,7 @@
         switch (netType) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 setRemoteArpRequestRuleForTunnel(port, install);
                 break;
             case VLAN:
@@ -407,6 +409,9 @@
             case GRE:
                 setArpReplyRuleForGre(port, install);
                 break;
+            case GENEVE:
+                setArpReplyRuleForGeneve(port, install);
+                break;
             case VLAN:
                 setArpReplyRuleForVlan(port, install);
                 break;
@@ -500,6 +505,22 @@
     }
 
     /**
+     * Installs flow rules to match ARP reply packets only for GENEVE.
+     *
+     * @param port      instance port
+     * @param install   installation flag
+     */
+    private void setArpReplyRuleForGeneve(InstancePort port, boolean install) {
+
+        OpenstackNode localNode = osNodeService.node(port.deviceId());
+
+        TrafficSelector selector = getArpReplySelectorForGeneve(port);
+
+        setLocalArpReplyTreatmentForGeneve(selector, port, install);
+        setRemoteArpTreatmentForTunnel(selector, port, localNode, install);
+    }
+
+    /**
      * Installs flow rules to match ARP reply packets only for VLAN.
      *
      * @param port      instance port
@@ -524,6 +545,11 @@
     }
 
     // a helper method
+    private TrafficSelector getArpReplySelectorForGeneve(InstancePort port) {
+        return getArpReplySelectorForVnet(port, GENEVE);
+    }
+
+    // a helper method
     private TrafficSelector getArpReplySelectorForVlan(InstancePort port) {
         return getArpReplySelectorForVnet(port, VLAN);
     }
@@ -562,6 +588,13 @@
     }
 
     // a helper method
+    private void setLocalArpReplyTreatmentForGeneve(TrafficSelector selector,
+                                                    InstancePort port,
+                                                    boolean install) {
+        setLocalArpReplyTreatmentForVnet(selector, port, GENEVE, install);
+    }
+
+    // a helper method
     private void setLocalArpReplyTreatmentForVlan(TrafficSelector selector,
                                                   InstancePort port,
                                                   boolean install) {
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
index e4b22b5..0fab37e 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHandler.java
@@ -500,6 +500,7 @@
         switch (type) {
             case VXLAN:
             case GRE:
+            case GENEVE:
                 setNetworkBlockRulesForTunnel(network.getProviderSegID(), install);
                 break;
             case VLAN:
@@ -734,7 +735,7 @@
 
         /**
          * Configures L2 forwarding rules.
-         * Currently, SONA supports Flat, VXLAN, GRE and VLAN modes.
+         * Currently, SONA supports Flat, VXLAN, GRE, GENEVE and VLAN modes.
          *
          * @param instPort instance port object
          * @param install install flag, add the rule if true, remove it otherwise
@@ -745,6 +746,7 @@
             switch (type) {
                 case VXLAN:
                 case GRE:
+                case GENEVE:
                     setNetworkRulesForTunnel(instPort, install);
                     break;
                 case VLAN:
@@ -794,6 +796,7 @@
             switch (type) {
                 case VXLAN:
                 case GRE:
+                case GENEVE:
                     removeVportRulesForTunnel(instPort);
                     break;
                 case VLAN:
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
index c4e3803..ce12d77 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/util/OpenstackNetworkingUtil.java
@@ -156,9 +156,6 @@
 
     private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
 
-    private static final String VXLAN = "VXLAN";
-    private static final String GRE = "GRE";
-    private static final String VLAN = "VLAN";
     private static final String DL_DST = "dl_dst=";
     private static final String NW_DST = "nw_dst=";
     private static final String DEFAULT_REQUEST_STRING = "sudo ovs-appctl ofproto/trace br-int ip";
@@ -770,9 +767,9 @@
                     .append(COMMA);
 
             String modifiedDstIp = dstIp;
-            if (osNetService.networkType(srcInstancePort.networkId()) == Type.VXLAN ||
-                    osNetService.networkType(srcInstancePort.networkId()) == Type.GRE ||
-                    osNetService.networkType(srcInstancePort.networkId()) == Type.VLAN) {
+            Type netType = osNetService.networkType(srcInstancePort.networkId());
+            if (netType == Type.VXLAN || netType == Type.GRE ||
+                    netType == Type.VLAN || netType == Type.GENEVE) {
                 if (srcIp.equals(dstIp)) {
                     modifiedDstIp = osNetService.gatewayIp(srcInstancePort.portId());
                     requestStringBuilder.append(DL_DST)
@@ -798,9 +795,10 @@
                     .append(dstIp)
                     .append(COMMA);
 
-            if (osNetService.networkType(srcInstancePort.networkId()) == Type.VXLAN ||
-                    osNetService.networkType(srcInstancePort.networkId()) == Type.GRE ||
-                    osNetService.networkType(srcInstancePort.networkId()) == Type.VLAN) {
+            Type netType = osNetService.networkType(srcInstancePort.networkId());
+
+            if (netType == Type.VXLAN || netType == Type.GRE ||
+                    netType == Type.VLAN || netType == Type.GENEVE) {
                 requestStringBuilder.append(TUN_ID)
                         .append(osNetService.segmentId(srcInstancePort.networkId()))
                         .append(COMMA);
@@ -1083,6 +1081,8 @@
                 return osNode.vxlanTunnelPortNum();
             case GRE:
                 return osNode.greTunnelPortNum();
+            case GENEVE:
+                return osNode.geneveTunnelPortNum();
             default:
                 return null;
         }