Support flat network type

Change-Id: Idacd79b9799466ac800a689a4700163ce74c3ca1
diff --git a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
index 8a7a2bb..131b339 100644
--- a/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
+++ b/apps/openstacknetworking/api/src/main/java/org/onosproject/openstacknetworking/api/Constants.java
@@ -41,6 +41,8 @@
     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_FLAT_RULE = 41000;
+    public static final int PRIORITY_DHCP_RULE = 42000;
     public static final int PRIORITY_ADMIN_RULE = 32000;
     public static final int PRIORITY_ACL_RULE = 31000;
     public static final int PRIORITY_CT_HOOK_RULE = 30500;
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 e67270c..5dab60f 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
@@ -497,7 +497,6 @@
     public Set<ExternalPeerRouter> externalPeerRouters() {
         return ImmutableSet.copyOf(externalPeerRouterMap.asJavaMap().values());
     }
-
     private boolean isNetworkInUse(String netId) {
         return !subnets(netId).isEmpty() && !ports(netId).isEmpty();
     }
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 94cdd42..b2d90a4 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
@@ -89,13 +89,13 @@
 import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
 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_ADMIN_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_EXTERNAL_ROUTING_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ICMP_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_INTERNAL_ROUTING_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_STATEFUL_SNAT_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_SWITCHING_RULE;
 import static org.onosproject.openstacknetworking.api.Constants.ROUTING_TABLE;
-import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
 import static org.onosproject.openstacknetworking.impl.RulePopulatorUtil.buildExtension;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.GATEWAY;
@@ -310,6 +310,10 @@
         Subnet osSubnet = osNetworkService.subnet(routerIface.getSubnetId());
         Network osNet = osNetworkService.network(osSubnet.getNetworkId());
 
+        if (osNet.getNetworkType() == NetworkType.FLAT) {
+            return;
+        }
+
         Optional<Router> osRouter = osRouterService.routers().stream()
                 .filter(router -> osRouterService.routerInterfaces(routerIface.getId()) != null)
                 .findAny();
@@ -1041,6 +1045,9 @@
         }
 
         private void instPortDetected(InstancePort instPort) {
+            if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
+                return;
+            }
             osNodeService.completeNodes(GATEWAY)
                     .forEach(gwNode -> setRulesForSnatIngressRule(gwNode.intgBridge(),
                                     Long.parseLong(osNetworkService.network(instPort.networkId()).getProviderSegID()),
@@ -1050,6 +1057,9 @@
         }
 
         private void instPortRemoved(InstancePort instPort) {
+            if (osNetworkAdminService.network(instPort.networkId()).getNetworkType() == NetworkType.FLAT) {
+                return;
+            }
             osNodeService.completeNodes(GATEWAY)
                     .forEach(gwNode -> setRulesForSnatIngressRule(gwNode.intgBridge(),
                                     Long.parseLong(osNetworkService.network(instPort.networkId()).getProviderSegID()),
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
index 3192cb4..5e2947f 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
@@ -25,7 +25,6 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.DHCP;
-import org.onlab.packet.dhcp.DhcpOption;
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.Ip4Address;
@@ -33,24 +32,27 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.UDP;
+import org.onlab.packet.dhcp.DhcpOption;
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
 import org.onosproject.net.packet.DefaultOutboundPacket;
 import org.onosproject.net.packet.PacketContext;
-import org.onosproject.net.packet.PacketPriority;
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.openstacknetworking.api.Constants;
 import org.onosproject.openstacknetworking.api.InstancePort;
 import org.onosproject.openstacknetworking.api.InstancePortService;
+import org.onosproject.openstacknetworking.api.OpenstackFlowRuleService;
 import org.onosproject.openstacknetworking.api.OpenstackNetworkService;
+import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.openstack4j.model.network.IP;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Subnet;
@@ -61,10 +63,20 @@
 import java.util.Dictionary;
 import java.util.List;
 
-import static org.onlab.packet.DHCP.DHCPOptionCode.*;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_BroadcastAddress;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DHCPServerIp;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DomainServer;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_END;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_LeaseTime;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RouterAddress;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_SubnetMask;
 import static org.onlab.packet.DHCP.MsgType.DHCPACK;
 import static org.onlab.packet.DHCP.MsgType.DHCPOFFER;
 import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
+import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_DHCP_RULE;
+import static org.onosproject.openstacknetworking.api.Constants.SRC_VNI_TABLE;
+import static org.onosproject.openstacknode.api.OpenstackNode.NodeType.COMPUTE;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -100,6 +112,12 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenstackNetworkService osNetworkService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackNodeService osNodeService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected OpenstackFlowRuleService osFlowRuleService;
+
     @Property(name = DHCP_SERVER_MAC, value = DEFAULT_GATEWAY_MAC_STR,
             label = "Fake MAC address for virtual network subnet gateway")
     private String dhcpServerMac = DEFAULT_GATEWAY_MAC_STR;
@@ -117,14 +135,14 @@
         appId = coreService.registerApplication(Constants.OPENSTACK_NETWORKING_APP_ID);
         configService.registerProperties(getClass());
         packetService.addProcessor(packetProcessor, PacketProcessor.director(0));
-        requestPackets();
+        setDhcpRule(true);
 
         log.info("Started");
     }
 
     @Deactivate
     protected void deactivate() {
-        cancelPackets();
+        setDhcpRule(false);
         packetService.removeProcessor(packetProcessor);
         configService.unregisterProperties(getClass(), false);
 
@@ -151,24 +169,28 @@
         log.info("Modified");
     }
 
-    private void requestPackets() {
+    private void setDhcpRule(boolean install) {
         TrafficSelector selector = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPProtocol(IPv4.PROTOCOL_UDP)
                 .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
                 .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
                 .build();
-        packetService.requestPackets(selector, PacketPriority.CONTROL, appId);
-    }
 
-    private void cancelPackets() {
-        TrafficSelector selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .matchIPProtocol(IPv4.PROTOCOL_UDP)
-                .matchUdpDst(TpPort.tpPort(UDP.DHCP_SERVER_PORT))
-                .matchUdpSrc(TpPort.tpPort(UDP.DHCP_CLIENT_PORT))
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(PortNumber.CONTROLLER)
                 .build();
-        packetService.cancelPackets(selector, PacketPriority.CONTROL, appId);
+
+        osNodeService.completeNodes(COMPUTE).forEach(node -> {
+            osFlowRuleService.setRule(
+                    appId,
+                    node.intgBridge(),
+                    selector,
+                    treatment,
+                    PRIORITY_DHCP_RULE,
+                    SRC_VNI_TABLE,
+                    install);
+        });
     }
 
     private class InternalPacketProcessor implements PacketProcessor {
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 e27b14a..fdc39ad 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
@@ -28,6 +28,7 @@
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.mastership.MastershipService;
+import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.driver.DriverService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
@@ -57,6 +58,7 @@
 import static org.onosproject.openstacknetworking.api.Constants.FORWARDING_TABLE;
 import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
 import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_ADMIN_RULE;
+import static org.onosproject.openstacknetworking.api.Constants.PRIORITY_FLAT_RULE;
 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;
@@ -126,7 +128,7 @@
 
     /**
      * Configures L2 forwarding rules.
-     * Currently, SONA only supports VXLAN and VLAN tunnelled L2 forwarding.
+     * Currently, SONA supports Flat, VXLAN and VLAN modes.
      *
      * @param instPort instance port object
      * @param install install flag, add the rule if true, remove it otherwise
@@ -142,12 +144,84 @@
                 setVlanTagFlowRules(instPort, install);
                 setForwardingRulesForVlan(instPort, install);
                 break;
+            case FLAT:
+                setDownstreamRules(instPort, install);
+                setUpstreamRules(instPort, install);
+                break;
             default:
                 log.warn("Unsupported network tunnel type {}", type.name());
                 break;
         }
     }
 
+    private void setDownstreamRules(InstancePort instPort, boolean install) {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPDst(instPort.ipAddress().toIpPrefix())
+                .build();
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(instPort.portNumber())
+                .build();
+
+        osFlowRuleService.setRule(
+                appId,
+                instPort.deviceId(),
+                selector,
+                treatment,
+                PRIORITY_FLAT_RULE,
+                SRC_VNI_TABLE,
+                install);
+
+        selector = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_ARP)
+                .matchArpTpa(instPort.ipAddress().getIp4Address())
+                .build();
+
+        osFlowRuleService.setRule(
+                appId,
+                instPort.deviceId(),
+                selector,
+                treatment,
+                PRIORITY_FLAT_RULE,
+                SRC_VNI_TABLE,
+                install);
+    }
+
+    private void setUpstreamRules(InstancePort instPort, boolean install) {
+        TrafficSelector selector = DefaultTrafficSelector.builder()
+                .matchInPort(instPort.portNumber())
+                .build();
+
+        Network network = osNetworkService.network(instPort.networkId());
+
+        if (network == null) {
+            log.warn("The network does not exist");
+            return;
+        }
+
+        PortNumber portNumber = osNodeService.node(instPort.deviceId())
+                .phyIntfPortNum(network.getProviderPhyNet());
+
+        if (portNumber == null) {
+            log.warn("The port number does not exist");
+            return;
+        }
+
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                .setOutput(portNumber)
+                .build();
+
+        osFlowRuleService.setRule(
+                appId,
+                instPort.deviceId(),
+                selector,
+                treatment,
+                PRIORITY_FLAT_RULE,
+                SRC_VNI_TABLE,
+                install);
+    }
+
+
     /**
      * Configures the flow rules which are used for L2 packet switching.
      * Note that these rules will be inserted in switching table (table 5).
diff --git a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
index e83cc52..0c2ea39 100644
--- a/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
+++ b/apps/openstacknetworking/app/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingHostProvider.java
@@ -52,6 +52,7 @@
 import org.onosproject.openstacknode.api.OpenstackNodeListener;
 import org.onosproject.openstacknode.api.OpenstackNodeService;
 import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -62,7 +63,7 @@
 
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
-import static org.onosproject.openstacknetworking.api.Constants.*;
+import static org.onosproject.openstacknetworking.api.Constants.OPENSTACK_NETWORKING_APP_ID;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_CREATE_TIME;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_NETWORK_ID;
 import static org.onosproject.openstacknetworking.impl.HostBasedInstancePort.ANNOTATION_PORT_ID;
@@ -176,8 +177,12 @@
         DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
                 .set(ANNOTATION_NETWORK_ID, osPort.getNetworkId())
                 .set(ANNOTATION_PORT_ID, osPort.getId())
-                .set(ANNOTATION_CREATE_TIME, String.valueOf(System.currentTimeMillis()))
-                .set(ANNOTATION_SEGMENT_ID, osNet.getProviderSegID());
+                .set(ANNOTATION_CREATE_TIME, String.valueOf(System.currentTimeMillis()));
+
+        if (osNet.getNetworkType() != NetworkType.FLAT) {
+            annotations.set(ANNOTATION_SEGMENT_ID, osNet.getProviderSegID());
+
+        }
 
         HostDescription hostDesc = new DefaultHostDescription(
                 macAddr,
diff --git a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
index c951041..b25887e 100644
--- a/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
+++ b/apps/openstacknode/api/src/main/java/org/onosproject/openstacknode/api/OpenstackNode.java
@@ -177,6 +177,14 @@
     Collection<OpenstackPhyInterface> phyIntfs();
 
     /**
+     * Returns the port number of given physical interface.
+     *
+     * @param providerPhysnet provider physical network name
+     * @return port number
+     */
+    PortNumber phyIntfPortNum(String providerPhysnet);
+
+    /**
      * Builder of new node entities.
      */
     interface Builder {
diff --git a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
index 50f5d53..c632847 100644
--- a/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
+++ b/apps/openstacknode/app/src/main/java/org/onosproject/openstacknode/impl/DefaultOpenstackNode.java
@@ -34,6 +34,7 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Objects;
+import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static org.onosproject.net.AnnotationKeys.PORT_MAC;
@@ -285,6 +286,24 @@
         return phyIntfs;
     }
 
+    @Override
+    public PortNumber phyIntfPortNum(String providerPhysnet) {
+        Optional<OpenstackPhyInterface> openstackPhyInterface =
+                phyIntfs.stream().filter(p -> p.network().equals(providerPhysnet)).findAny();
+
+        if (openstackPhyInterface.isPresent()) {
+            DeviceService deviceService = DefaultServiceDirectory.getService(DeviceService.class);
+            Port port = deviceService.getPorts(intgBridge).stream()
+                    .filter(p -> p.isEnabled() &&
+                            Objects.equals(p.annotations().value(PORT_NAME), openstackPhyInterface.get().intf()))
+                    .findAny().orElse(null);
+
+            return port != null ? port.number() : null;
+        } else {
+            return null;
+        }
+
+    }
     /**
      * Returns new builder instance.
      *