[ONOS-6168, ONOS-6436] Implement multiple gateway nodes support for VLAN mode and implement VLAN based Logical Routing

Change-Id: Ifd1c26375abdf84603f28184e9cb9ad6c88648dd
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
index f3e8363..90f32c3 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingFloatingIpHandler.java
@@ -24,6 +24,7 @@
 import org.onlab.packet.Ethernet;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.LeadershipService;
 import org.onosproject.cluster.NodeId;
@@ -49,6 +50,7 @@
 import org.onosproject.openstacknode.OpenstackNodeService;
 import org.openstack4j.model.network.NetFloatingIP;
 import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -72,6 +74,7 @@
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     private static final String ERR_FLOW = "Failed set flows for floating IP %s: ";
+    private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
@@ -167,25 +170,39 @@
                 .build();
 
         osNodeService.gatewayDeviceIds().forEach(gnodeId -> {
-            TrafficTreatment externalTreatment = DefaultTrafficTreatment.builder()
+            TrafficTreatment.Builder externalBuilder = DefaultTrafficTreatment.builder()
                     .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
                     .setEthDst(instPort.macAddress())
-                    .setIpDst(instPort.ipAddress().getIp4Address())
-                    .setTunnelId(Long.valueOf(osNet.getProviderSegID()))
-                    .extension(buildExtension(
-                            deviceService,
-                            gnodeId,
-                            dataIp.get().getIp4Address()),
-                            gnodeId)
-                    .setOutput(osNodeService.tunnelPort(gnodeId).get())
-                    .build();
+                    .setIpDst(instPort.ipAddress().getIp4Address());
+
+            switch (osNet.getNetworkType()) {
+                case VXLAN:
+                    externalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
+                            .extension(buildExtension(
+                                    deviceService,
+                                    gnodeId,
+                                    dataIp.get().getIp4Address()),
+                                    gnodeId)
+                            .setOutput(osNodeService.tunnelPort(gnodeId).get());
+                    break;
+                case VLAN:
+                    externalBuilder.pushVlan()
+                            .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
+                            .setOutput(osNodeService.vlanPort(gnodeId).get());
+                    break;
+                default:
+                    final String error = String.format(
+                            ERR_UNSUPPORTED_NET_TYPE + "%s",
+                            osNet.getNetworkType().toString());
+                    throw new IllegalStateException(error);
+            }
 
             RulePopulatorUtil.setRule(
                     flowObjectiveService,
                     appId,
                     gnodeId,
                     externalSelector,
-                    externalTreatment,
+                    externalBuilder.build(),
                     ForwardingObjective.Flag.VERSATILE,
                     PRIORITY_FLOATING_EXTERNAL,
                     install);
@@ -197,25 +214,39 @@
                     .matchInPort(osNodeService.tunnelPort(gnodeId).get())
                     .build();
 
-            TrafficTreatment internalTreatment = DefaultTrafficTreatment.builder()
+            TrafficTreatment.Builder internalBuilder = DefaultTrafficTreatment.builder()
                     .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
                     .setEthDst(instPort.macAddress())
-                    .setIpDst(instPort.ipAddress().getIp4Address())
-                    .setTunnelId(Long.valueOf(osNet.getProviderSegID()))
-                    .extension(buildExtension(
-                            deviceService,
-                            gnodeId,
-                            dataIp.get().getIp4Address()),
-                            gnodeId)
-                    .setOutput(PortNumber.IN_PORT)
-                    .build();
+                    .setIpDst(instPort.ipAddress().getIp4Address());
+
+            switch (osNet.getNetworkType()) {
+                case VXLAN:
+                    internalBuilder.setTunnelId(Long.valueOf(osNet.getProviderSegID()))
+                            .extension(buildExtension(
+                                    deviceService,
+                                    gnodeId,
+                                    dataIp.get().getIp4Address()),
+                                    gnodeId)
+                            .setOutput(PortNumber.IN_PORT);
+                    break;
+                case VLAN:
+                    internalBuilder.pushVlan()
+                            .setVlanId(VlanId.vlanId(osNet.getProviderSegID()))
+                            .setOutput(PortNumber.IN_PORT);
+                    break;
+                default:
+                    final String error = String.format(
+                            ERR_UNSUPPORTED_NET_TYPE + "%s",
+                            osNet.getNetworkType().toString());
+                    throw new IllegalStateException(error);
+            }
 
             RulePopulatorUtil.setRule(
                     flowObjectiveService,
                     appId,
                     gnodeId,
                     internalSelector,
-                    internalTreatment,
+                    internalBuilder.build(),
                     ForwardingObjective.Flag.VERSATILE,
                     PRIORITY_FLOATING_INTERNAL,
                     install);
@@ -225,26 +256,41 @@
     private void setUpstreamRules(NetFloatingIP floatingIp, Network osNet,
                                   InstancePort instPort, boolean install) {
         IpAddress floating = IpAddress.valueOf(floatingIp.getFloatingIpAddress());
-        TrafficSelector selector = DefaultTrafficSelector.builder()
+
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(Long.valueOf(osNet.getProviderSegID()))
-                .matchIPSrc(instPort.ipAddress().toIpPrefix())
-                .build();
+                .matchIPSrc(instPort.ipAddress().toIpPrefix());
+
+        switch (osNet.getNetworkType()) {
+            case VXLAN:
+                sBuilder.matchTunnelId(Long.valueOf(osNet.getProviderSegID()));
+                break;
+            case VLAN:
+                sBuilder.matchVlanId(VlanId.vlanId(osNet.getProviderSegID()));
+                break;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        osNet.getNetworkType().toString());
+                throw new IllegalStateException(error);
+        }
 
         osNodeService.gatewayDeviceIds().forEach(gnodeId -> {
-            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+            TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
                     .setIpSrc(floating.getIp4Address())
                     .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
-                    .setEthDst(Constants.DEFAULT_EXTERNAL_ROUTER_MAC)
-                    .setOutput(osNodeService.externalPort(gnodeId).get())
-                    .build();
+                    .setEthDst(Constants.DEFAULT_EXTERNAL_ROUTER_MAC);
+
+            if (osNet.getNetworkType().equals(NetworkType.VLAN)) {
+                tBuilder.popVlan();
+            }
 
             RulePopulatorUtil.setRule(
                     flowObjectiveService,
                     appId,
                     gnodeId,
-                    selector,
-                    treatment,
+                    sBuilder.build(),
+                    tBuilder.setOutput(osNodeService.externalPort(gnodeId).get()).build(),
                     ForwardingObjective.Flag.VERSATILE,
                     PRIORITY_FLOATING_EXTERNAL,
                     install);
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
index c5d5f29..b004ee7 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingHandler.java
@@ -26,6 +26,8 @@
 import org.onlab.packet.IPv4;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
 import org.onosproject.cluster.ClusterService;
 import org.onosproject.cluster.LeadershipService;
 import org.onosproject.cluster.NodeId;
@@ -34,6 +36,7 @@
 import org.onosproject.core.GroupId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.TrafficSelector;
@@ -49,8 +52,11 @@
 import org.onosproject.openstacknode.OpenstackNodeEvent;
 import org.onosproject.openstacknode.OpenstackNodeListener;
 import org.onosproject.openstacknode.OpenstackNodeService;
+import org.onosproject.openstacknode.OpenstackNodeService.NetworkMode;
+
 import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Router;
 import org.openstack4j.model.network.RouterInterface;
 import org.openstack4j.model.network.Subnet;
@@ -64,6 +70,8 @@
 
 import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
 import static org.onlab.util.Tools.groupedThreads;
+import static org.onosproject.net.AnnotationKeys.PORT_MAC;
+import static org.onosproject.net.AnnotationKeys.PORT_NAME;
 import static org.onosproject.openstacknetworking.api.Constants.*;
 import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
 
@@ -78,6 +86,7 @@
     private static final String MSG_ENABLED = "Enabled ";
     private static final String MSG_DISABLED = "Disabled ";
     private static final String ERR_SET_FLOWS = "Failed to set flows for router %s:";
+    private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
@@ -100,6 +109,9 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenstackRouterService osRouterService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
     private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
             groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
     private final OpenstackNodeListener osNodeListener = new InternalNodeEventListener();
@@ -151,7 +163,6 @@
                     osRouterIface.getSubnetId());
             throw new IllegalStateException(error);
         }
-
         setInternalRoutes(osRouter, osSubnet, true);
         setGatewayIcmp(osSubnet, true);
         ExternalGateway exGateway = osRouter.getExternalGatewayInfo();
@@ -189,20 +200,18 @@
         osNodeService.completeNodes().stream()
                 .filter(osNode -> osNode.type() == COMPUTE)
                 .forEach(osNode -> {
-                    setRulesToGateway(
-                            osNode.intBridge(),
-                            osNodeService.gatewayGroupId(osNode.intBridge()),
-                            Long.valueOf(osNet.getProviderSegID()),
-                            IpPrefix.valueOf(osSubnet.getCidr()),
-                            install);
+                        setRulesToGateway(osNode.intBridge(), osNet.getProviderSegID(),
+                                IpPrefix.valueOf(osSubnet.getCidr()), osNet.getNetworkType(),
+                                install);
                 });
 
         // take the first outgoing packet to controller for source NAT
         osNodeService.gatewayDeviceIds()
                 .forEach(gwDeviceId -> setRulesToController(
                         gwDeviceId,
-                        Long.valueOf(osNet.getProviderSegID()),
+                        osNet.getProviderSegID(),
                         IpPrefix.valueOf(osSubnet.getCidr()),
+                        osNet.getNetworkType(),
                         install));
 
         final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
@@ -217,14 +226,37 @@
 
         // take ICMP request to a subnet gateway through gateway node group
         Network network = osNetworkService.network(osSubnet.getNetworkId());
-        osNodeService.completeNodes().stream()
-                .filter(osNode -> osNode.type() == COMPUTE)
-                .forEach(osNode -> setRulesToGatewayWithDstIp(
-                        osNode.intBridge(),
-                        osNodeService.gatewayGroupId(osNode.intBridge()),
-                        Long.valueOf(network.getProviderSegID()),
-                        IpAddress.valueOf(osSubnet.getGateway()),
-                        install));
+        switch (network.getNetworkType()) {
+            case VXLAN:
+                osNodeService.completeNodes().stream()
+                        .filter(osNode -> osNode.type() == COMPUTE)
+                        .filter(osNode -> osNode.dataIp().isPresent())
+                        .forEach(osNode -> setRulesToGatewayWithDstIp(
+                                osNode.intBridge(),
+                                osNodeService.gatewayGroupId(osNode.intBridge(), NetworkMode.VXLAN),
+                                network.getProviderSegID(),
+                                IpAddress.valueOf(osSubnet.getGateway()),
+                                NetworkMode.VXLAN,
+                                install));
+                break;
+            case VLAN:
+                osNodeService.completeNodes().stream()
+                        .filter(osNode -> osNode.type() == COMPUTE)
+                        .filter(osNode -> osNode.vlanPort().isPresent())
+                        .forEach(osNode -> setRulesToGatewayWithDstIp(
+                                osNode.intBridge(),
+                                osNodeService.gatewayGroupId(osNode.intBridge(), NetworkMode.VLAN),
+                                network.getProviderSegID(),
+                                IpAddress.valueOf(osSubnet.getGateway()),
+                                NetworkMode.VLAN,
+                                install));
+                break;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        network.getNetworkType().toString());
+                throw new IllegalStateException(error);
+        }
 
         IpAddress gatewayIp = IpAddress.valueOf(osSubnet.getGateway());
         osNodeService.gatewayDeviceIds()
@@ -239,8 +271,9 @@
     }
 
     private void setInternalRoutes(Router osRouter, Subnet updatedSubnet, boolean install) {
+        Network updatedNetwork = osNetworkService.network(updatedSubnet.getNetworkId());
         Set<Subnet> routableSubnets = routableSubnets(osRouter, updatedSubnet.getId());
-        Long updatedVni = getVni(updatedSubnet);
+        String updatedSegmendId = getSegmentId(updatedSubnet);
 
         // installs rule from/to my subnet intentionally to fix ICMP failure
         // to my subnet gateway if no external gateway added to the router
@@ -249,33 +282,37 @@
                 .forEach(osNode -> {
                     setInternalRouterRules(
                             osNode.intBridge(),
-                            updatedVni,
-                            updatedVni,
+                            updatedSegmendId,
+                            updatedSegmendId,
                             IpPrefix.valueOf(updatedSubnet.getCidr()),
                             IpPrefix.valueOf(updatedSubnet.getCidr()),
+                            updatedNetwork.getNetworkType(),
                             install
                     );
 
                     routableSubnets.forEach(subnet -> {
                         setInternalRouterRules(
                                 osNode.intBridge(),
-                                updatedVni,
-                                getVni(subnet),
+                                updatedSegmendId,
+                                getSegmentId(subnet),
                                 IpPrefix.valueOf(updatedSubnet.getCidr()),
                                 IpPrefix.valueOf(subnet.getCidr()),
+                                updatedNetwork.getNetworkType(),
                                 install
                         );
                         setInternalRouterRules(
                                 osNode.intBridge(),
-                                getVni(subnet),
-                                updatedVni,
+                                getSegmentId(subnet),
+                                updatedSegmendId,
                                 IpPrefix.valueOf(subnet.getCidr()),
                                 IpPrefix.valueOf(updatedSubnet.getCidr()),
+                                updatedNetwork.getNetworkType(),
                                 install
                         );
                     });
                 });
 
+
         final String updateStr = install ? MSG_ENABLED : MSG_DISABLED;
         routableSubnets.forEach(subnet -> log.debug(
                 updateStr + "route between subnet:{} and subnet:{}",
@@ -292,9 +329,8 @@
         return ImmutableSet.copyOf(osSubnets);
     }
 
-    private Long getVni(Subnet osSubnet) {
-        return Long.parseLong(osNetworkService.network(
-                osSubnet.getNetworkId()).getProviderSegID());
+    private String getSegmentId(Subnet osSubnet) {
+        return osNetworkService.network(osSubnet.getNetworkId()).getProviderSegID();
     }
 
     private void setGatewayIcmpRule(IpAddress gatewayIp, DeviceId deviceId, boolean install) {
@@ -319,61 +355,136 @@
                 install);
     }
 
-    private void setInternalRouterRules(DeviceId deviceId, Long srcVni, Long dstVni,
-                                        IpPrefix srcSubnet, IpPrefix dstSubnet, boolean install) {
-        TrafficSelector selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(srcVni)
-                .matchIPSrc(srcSubnet)
-                .matchIPDst(dstSubnet)
-                .build();
+    private void setInternalRouterRules(DeviceId deviceId, String srcSegmentId, String dstSegmentId,
+                                        IpPrefix srcSubnet, IpPrefix dstSubnet,
+                                        NetworkType networkType, boolean install) {
+        TrafficSelector selector;
+        TrafficTreatment treatment;
+        switch (networkType) {
+            case VXLAN:
+                selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchTunnelId(Long.parseLong(srcSegmentId))
+                        .matchIPSrc(srcSubnet)
+                        .matchIPDst(dstSubnet)
+                        .build();
 
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setTunnelId(dstVni)
-                .build();
+                treatment = DefaultTrafficTreatment.builder()
+                        .setTunnelId(Long.parseLong(dstSegmentId))
+                        .build();
 
-        RulePopulatorUtil.setRule(
-                flowObjectiveService,
-                appId,
-                deviceId,
-                selector,
-                treatment,
-                ForwardingObjective.Flag.SPECIFIC,
-                PRIORITY_INTERNAL_ROUTING_RULE,
-                install);
+                RulePopulatorUtil.setRule(
+                        flowObjectiveService,
+                        appId,
+                        deviceId,
+                        selector,
+                        treatment,
+                        ForwardingObjective.Flag.SPECIFIC,
+                        PRIORITY_INTERNAL_ROUTING_RULE,
+                        install);
 
-        selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(dstVni)
-                .matchIPSrc(srcSubnet)
-                .matchIPDst(dstSubnet)
-                .build();
+                selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchTunnelId(Long.parseLong(dstSegmentId))
+                        .matchIPSrc(srcSubnet)
+                        .matchIPDst(dstSubnet)
+                        .build();
 
-        treatment = DefaultTrafficTreatment.builder()
-                .setTunnelId(dstVni)
-                .build();
+                treatment = DefaultTrafficTreatment.builder()
+                        .setTunnelId(Long.parseLong(dstSegmentId))
+                        .build();
 
-        RulePopulatorUtil.setRule(
-                flowObjectiveService,
-                appId,
-                deviceId,
-                selector,
-                treatment,
-                ForwardingObjective.Flag.SPECIFIC,
-                PRIORITY_INTERNAL_ROUTING_RULE,
-                install);
+                RulePopulatorUtil.setRule(
+                        flowObjectiveService,
+                        appId,
+                        deviceId,
+                        selector,
+                        treatment,
+                        ForwardingObjective.Flag.SPECIFIC,
+                        PRIORITY_INTERNAL_ROUTING_RULE,
+                        install);
+                break;
+            case VLAN:
+                selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchVlanId(VlanId.vlanId(srcSegmentId))
+                        .matchIPSrc(srcSubnet)
+                        .matchIPDst(dstSubnet)
+                        .build();
+
+                treatment = DefaultTrafficTreatment.builder()
+                        .setVlanId(VlanId.vlanId(dstSegmentId))
+                        .build();
+
+                RulePopulatorUtil.setRule(
+                        flowObjectiveService,
+                        appId,
+                        deviceId,
+                        selector,
+                        treatment,
+                        ForwardingObjective.Flag.SPECIFIC,
+                        PRIORITY_INTERNAL_ROUTING_RULE,
+                        install);
+
+                selector = DefaultTrafficSelector.builder()
+                        .matchEthType(Ethernet.TYPE_IPV4)
+                        .matchVlanId(VlanId.vlanId(dstSegmentId))
+                        .matchIPSrc(srcSubnet)
+                        .matchIPDst(dstSubnet)
+                        .build();
+
+                treatment = DefaultTrafficTreatment.builder()
+                        .setVlanId(VlanId.vlanId(dstSegmentId))
+                        .build();
+
+                RulePopulatorUtil.setRule(
+                        flowObjectiveService,
+                        appId,
+                        deviceId,
+                        selector,
+                        treatment,
+                        ForwardingObjective.Flag.SPECIFIC,
+                        PRIORITY_INTERNAL_ROUTING_RULE,
+                        install);
+                break;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        networkType.toString());
+                throw new IllegalStateException(error);
+        }
+
     }
 
-    private void setRulesToGateway(DeviceId deviceId, GroupId groupId, Long vni,
-                                   IpPrefix srcSubnet, boolean install) {
-        TrafficSelector selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(vni)
-                .matchIPSrc(srcSubnet)
-                .matchEthDst(Constants.DEFAULT_GATEWAY_MAC)
-                .build();
+    private void setRulesToGateway(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
+                                   NetworkType networkType, boolean install) {
+        TrafficTreatment treatment;
+        GroupId groupId;
 
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
+                .matchEthType(Ethernet.TYPE_IPV4)
+                .matchIPSrc(srcSubnet)
+                .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
+
+        switch (networkType) {
+            case VXLAN:
+                sBuilder.matchTunnelId(Long.parseLong(segmentId));
+
+                groupId = osNodeService.gatewayGroupId(deviceId, NetworkMode.VXLAN);
+                break;
+            case VLAN:
+                sBuilder.matchVlanId(VlanId.vlanId(segmentId));
+
+                groupId = osNodeService.gatewayGroupId(deviceId, NetworkMode.VLAN);
+                break;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        networkType.toString());
+                throw new IllegalStateException(error);
+        }
+
+        treatment = DefaultTrafficTreatment.builder()
                 .group(groupId)
                 .build();
 
@@ -381,43 +492,78 @@
                 flowObjectiveService,
                 appId,
                 deviceId,
-                selector,
+                sBuilder.build(),
                 treatment,
                 ForwardingObjective.Flag.SPECIFIC,
                 PRIORITY_EXTERNAL_ROUTING_RULE,
                 install);
     }
 
-    private void setRulesToController(DeviceId deviceId, Long vni, IpPrefix srcSubnet, boolean install) {
-        TrafficSelector selector = DefaultTrafficSelector.builder()
+    private void setRulesToController(DeviceId deviceId, String segmentId, IpPrefix srcSubnet,
+                                      NetworkType networkType, boolean install) {
+        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(vni)
-                .matchIPSrc(srcSubnet)
-                .matchEthDst(Constants.DEFAULT_GATEWAY_MAC)
-                .build();
+                .matchIPSrc(srcSubnet);
 
-        TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(PortNumber.CONTROLLER)
-                .build();
+        switch (networkType) {
+            case VXLAN:
+                sBuilder.matchTunnelId(Long.parseLong(segmentId))
+                        .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
+                break;
+            case VLAN:
+                sBuilder.matchVlanId(VlanId.vlanId(segmentId))
+                        .matchEthDst(MacAddress.valueOf(vlanPortMac(deviceId)));
+                break;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        networkType.toString());
+                throw new IllegalStateException(error);
+        }
+
+        TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
+                .setEthDst(Constants.DEFAULT_GATEWAY_MAC);
+
+        if (networkType.equals(NetworkType.VLAN)) {
+            tBuilder.popVlan();
+        }
+
+        tBuilder.setOutput(PortNumber.CONTROLLER);
 
         RulePopulatorUtil.setRule(
                 flowObjectiveService,
                 appId,
                 deviceId,
-                selector,
-                treatment,
+                sBuilder.build(),
+                tBuilder.build(),
                 ForwardingObjective.Flag.VERSATILE,
                 PRIORITY_EXTERNAL_ROUTING_RULE,
                 install);
     }
 
-    private void setRulesToGatewayWithDstIp(DeviceId deviceId, GroupId groupId, Long vni,
-                                            IpAddress dstIp, boolean install) {
-        TrafficSelector selector = DefaultTrafficSelector.builder()
-                .matchEthType(Ethernet.TYPE_IPV4)
-                .matchTunnelId(vni)
-                .matchIPDst(dstIp.toIpPrefix())
-                .build();
+    private String vlanPortMac(DeviceId deviceId) {
+        return deviceService.getPorts(deviceId).stream()
+                .filter(p -> p.annotations()
+                        .value(PORT_NAME).equals(osNodeService.gatewayNode(deviceId).vlanPort().get()) && p.isEnabled())
+                .findFirst().get().annotations().value(PORT_MAC);
+    }
+
+    private void setRulesToGatewayWithDstIp(DeviceId deviceId, GroupId groupId, String segmentId,
+                                            IpAddress dstIp, NetworkMode networkMode, boolean install) {
+        TrafficSelector selector;
+        if (networkMode.equals(NetworkMode.VXLAN)) {
+            selector = DefaultTrafficSelector.builder()
+                    .matchEthType(Ethernet.TYPE_IPV4)
+                    .matchTunnelId(Long.valueOf(segmentId))
+                    .matchIPDst(dstIp.toIpPrefix())
+                    .build();
+        } else {
+            selector = DefaultTrafficSelector.builder()
+                    .matchEthType(Ethernet.TYPE_IPV4)
+                    .matchVlanId(VlanId.vlanId(segmentId))
+                    .matchIPDst(dstIp.toIpPrefix())
+                    .build();
+        }
 
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
                 .group(groupId)
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
index bd6eeb2..ab8f92c 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackRoutingSnatHandler.java
@@ -27,6 +27,7 @@
 import org.onlab.packet.TCP;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.UDP;
+import org.onlab.packet.VlanId;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
@@ -57,6 +58,7 @@
 import org.openstack4j.model.network.ExternalGateway;
 import org.openstack4j.model.network.IP;
 import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
 import org.openstack4j.model.network.Port;
 import org.openstack4j.model.network.Router;
 import org.openstack4j.model.network.RouterInterface;
@@ -81,6 +83,7 @@
     private final Logger log = getLogger(getClass());
 
     private static final String ERR_PACKETIN = "Failed to handle packet in: ";
+    private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
     private static final int TIME_OUT_SNAT_RULE = 120;
     private static final long TIME_OUT_SNAT_PORT_MS = 120 * 1000;
     private static final int TP_PORT_MINIMUM_NUM = 1024;
@@ -168,10 +171,6 @@
         InboundPacket packetIn = context.inPacket();
 
         int patPort = getPortNum();
-        if (patPort == 0) {
-            log.error("There's no unused port for PAT. Drop this packet");
-            return;
-        }
 
         InstancePort srcInstPort = instancePortService.instancePort(eth.getSourceMAC());
         if (srcInstPort == null) {
@@ -260,18 +259,20 @@
         }
 
         setDownstreamRules(srcInstPort,
-                Long.parseLong(osNet.getProviderSegID()),
+                osNet.getProviderSegID(),
+                osNet.getNetworkType(),
                 externalIp,
                 patPort,
                 packetIn);
 
-        setUpstreamRules(Long.parseLong(osNet.getProviderSegID()),
+        setUpstreamRules(osNet.getProviderSegID(),
+                osNet.getNetworkType(),
                 externalIp,
                 patPort,
                 packetIn);
     }
 
-    private void setDownstreamRules(InstancePort srcInstPort, Long srcVni,
+    private void setDownstreamRules(InstancePort srcInstPort, String segmentId, NetworkType networkType,
                                     IpAddress externalIp, TpPort patPort,
                                     InboundPacket packetIn) {
         IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
@@ -284,10 +285,26 @@
                 .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
 
         TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder()
-                .setTunnelId(srcVni)
                 .setEthDst(packetIn.parsed().getSourceMAC())
                 .setIpDst(internalIp);
 
+        switch (networkType) {
+            case VXLAN:
+                tBuilder.setTunnelId(Long.parseLong(segmentId));
+                break;
+            case VLAN:
+                tBuilder.pushVlan()
+                        .setVlanId(VlanId.vlanId(segmentId))
+                        .setEthSrc(DEFAULT_GATEWAY_MAC);
+                break;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        networkType.toString());
+                throw new IllegalStateException(error);
+        }
+
+
         switch (iPacket.getProtocol()) {
             case IPv4.PROTOCOL_TCP:
                 TCP tcpPacket = (TCP) iPacket.getPayload();
@@ -309,11 +326,23 @@
             DeviceId srcDeviceId = srcInstPort.deviceId();
             TrafficTreatment.Builder tmpBuilder =
                     DefaultTrafficTreatment.builder(tBuilder.build());
-            tmpBuilder.extension(RulePopulatorUtil.buildExtension(
-                    deviceService,
-                    deviceId,
-                    osNodeService.dataIp(srcDeviceId).get().getIp4Address()), deviceId)
-                    .setOutput(osNodeService.tunnelPort(deviceId).get());
+            switch (networkType) {
+                case VXLAN:
+                    tmpBuilder.extension(RulePopulatorUtil.buildExtension(
+                            deviceService,
+                            deviceId,
+                            osNodeService.dataIp(srcDeviceId).get().getIp4Address()), deviceId)
+                            .setOutput(osNodeService.tunnelPort(deviceId).get());
+                    break;
+                case VLAN:
+                    tmpBuilder.setOutput(osNodeService.vlanPort(deviceId).get());
+                    break;
+                default:
+                    final String error = String.format(
+                            ERR_UNSUPPORTED_NET_TYPE + "%s",
+                            networkType.toString());
+                    throw new IllegalStateException(error);
+            }
 
             ForwardingObjective fo = DefaultForwardingObjective.builder()
                     .withSelector(sBuilder.build())
@@ -328,17 +357,33 @@
         });
     }
 
-    private void setUpstreamRules(Long srcVni, IpAddress externalIp, TpPort patPort,
+    private void setUpstreamRules(String segmentId, NetworkType networkType, IpAddress externalIp, TpPort patPort,
                                   InboundPacket packetIn) {
         IPv4 iPacket = (IPv4) packetIn.parsed().getPayload();
-        TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder()
+
+        TrafficSelector.Builder sBuilder =  DefaultTrafficSelector.builder()
                 .matchEthType(Ethernet.TYPE_IPV4)
                 .matchIPProtocol(iPacket.getProtocol())
-                .matchTunnelId(srcVni)
                 .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
                 .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
 
         TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+
+        switch (networkType) {
+            case VXLAN:
+                sBuilder.matchTunnelId(Long.parseLong(segmentId));
+                break;
+            case VLAN:
+                sBuilder.matchVlanId(VlanId.vlanId(segmentId));
+                tBuilder.popVlan();
+                break;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        networkType.toString());
+                throw new IllegalStateException(error);
+        }
+
         switch (iPacket.getProtocol()) {
             case IPv4.PROTOCOL_TCP:
                 TCP tcpPacket = (TCP) iPacket.getPayload();
@@ -407,11 +452,11 @@
         iPacket.setParent(ethPacketIn);
         ethPacketIn.setDestinationMACAddress(DEFAULT_EXTERNAL_ROUTER_MAC);
         ethPacketIn.setPayload(iPacket);
+        ethPacketIn.resetChecksum();
 
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(osNodeService.externalPort(srcDevice).get())
-                .build();
-        ethPacketIn.resetChecksum();
+                .setOutput(osNodeService.externalPort(srcDevice).get()).build();
+
         packetService.emit(new DefaultOutboundPacket(
                 srcDevice,
                 treatment,