[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,
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/Constants.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/Constants.java
index b4074f7..8bb75a1 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/Constants.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/Constants.java
@@ -26,6 +26,7 @@
     public static final String INTEGRATION_BRIDGE = "br-int";
     public static final String ROUTER_BRIDGE = "br-router";
     public static final String DEFAULT_TUNNEL = "vxlan";
+    public static final String VLAN = "vlan";
     public static final String PATCH_INTG_BRIDGE = "patch-intg";
     public static final String PATCH_ROUT_BRIDGE = "patch-rout";
 
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java
index 4f3e5e7..bea3a41 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeManager.java
@@ -297,7 +297,7 @@
         process(new OpenstackNodeEvent(COMPLETE, node));
         switch (node.type()) {
             case COMPUTE:
-                selectGroupHandler.createGatewayGroup(node.intBridge(), gatewayNodes());
+                selectGroupHandler.createGatewayGroup(node, gatewayNodes());
                 break;
             case GATEWAY:
                 updateGatewayGroup(node, true);
@@ -386,12 +386,15 @@
     }
 
     @Override
-    public synchronized GroupId gatewayGroupId(DeviceId srcDeviceId) {
-        GroupKey groupKey = selectGroupHandler.getGroupKey(srcDeviceId);
+    public synchronized GroupId gatewayGroupId(DeviceId srcDeviceId, NetworkMode networkMode) {
+        GroupKey groupKey = selectGroupHandler.groupKey(srcDeviceId, networkMode);
         Group group = groupService.getGroup(srcDeviceId, groupKey);
+
         if (group == null) {
             log.info("Created gateway group for {}", srcDeviceId);
-            return selectGroupHandler.createGatewayGroup(srcDeviceId, gatewayNodes());
+            selectGroupHandler.createGatewayGroup(nodeByDeviceId(srcDeviceId), gatewayNodes());
+
+            return groupService.getGroup(srcDeviceId, selectGroupHandler.groupKey(srcDeviceId, networkMode)).id();
         } else {
             return group.id();
         }
@@ -425,13 +428,26 @@
                 .stream()
                 .map(Versioned::value)
                 .filter(node -> node.type().equals(NodeType.COMPUTE))
+                .filter(node -> node.dataIp().isPresent())
                 .filter(node -> node.state().equals(COMPLETE))
-                .forEach(node -> {
-                    selectGroupHandler.updateGatewayGroupBuckets(node.intBridge(),
-                            ImmutableList.of(gatewayNode),
-                            isInsert);
-                    log.trace("Updated gateway group on {}", node.intBridge());
+                .forEach(computeNode -> {
+                    selectGroupHandler.updateGatewayGroupBuckets(computeNode,
+                            ImmutableList.of(gatewayNode), NetworkMode.VXLAN, isInsert);
+                    log.trace("Updated gateway group on {} for vxlan mode", computeNode.intBridge());
                 });
+
+        nodeStore.values()
+                .stream()
+                .map(Versioned::value)
+                .filter(node -> node.type().equals(NodeType.COMPUTE))
+                .filter(node -> node.vlanPort().isPresent())
+                .filter(node -> node.state().equals(COMPLETE))
+                .forEach(computeNode -> {
+                    selectGroupHandler.updateGatewayGroupBuckets(computeNode,
+                            ImmutableList.of(gatewayNode), NetworkMode.VLAN, isInsert);
+                    log.trace("Updated gateway group on {} for vlan mode", computeNode.intBridge());
+                });
+
     }
 
     private void initNode(OpenstackNode node) {
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeService.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeService.java
index 7362893..9600280 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeService.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/OpenstackNodeService.java
@@ -39,6 +39,14 @@
         GATEWAY
     }
 
+    enum NetworkMode {
+        /**
+         * VxLAN or VLAN mode.
+         */
+        VXLAN,
+        VLAN
+    }
+
     /**
      * Adds or updates a new node to the service.
      *
@@ -150,9 +158,10 @@
      * If the group does not exist in the supplied source device, creates one.
      *
      * @param srcDeviceId source device id
-     * @return The group id
+     * @param networkMode network mode
+     * @return group id
      */
-    GroupId gatewayGroupId(DeviceId srcDeviceId);
+    GroupId gatewayGroupId(DeviceId srcDeviceId, NetworkMode networkMode);
 
     /**
      * Returns the list of gateway node information with the given device identifier.
diff --git a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/SelectGroupHandler.java b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/SelectGroupHandler.java
index df963db..5f8e065 100644
--- a/apps/openstacknode/src/main/java/org/onosproject/openstacknode/SelectGroupHandler.java
+++ b/apps/openstacknode/src/main/java/org/onosproject/openstacknode/SelectGroupHandler.java
@@ -18,8 +18,10 @@
 
 import com.google.common.collect.Lists;
 import org.onlab.packet.Ip4Address;
+import org.onlab.packet.MacAddress;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.GroupId;
+import org.onosproject.openstacknode.OpenstackNodeService.NetworkMode;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Port;
 import org.onosproject.net.PortNumber;
@@ -47,7 +49,9 @@
 
 import java.util.List;
 
+import static org.onosproject.net.AnnotationKeys.PORT_MAC;
 import static org.onosproject.net.AnnotationKeys.PORT_NAME;
+import static org.onosproject.openstacknode.Constants.*;
 import static org.onosproject.net.group.DefaultGroupBucket.createSelectGroupBucket;
 
 /**
@@ -57,7 +61,7 @@
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     private static final String TUNNEL_DESTINATION = "tunnelDst";
-    private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
+    private static final String ERR_UNSUPPORTED_NET_TYPE = "Unsupported network type";
 
     private final GroupService groupService;
     private final DeviceService deviceService;
@@ -83,81 +87,139 @@
     /**
      * Creates select type group description according to given deviceId.
      *
-     * @param srcDeviceId target device id for group description
+     * @param computeNode target device id for group description
      * @param gatewayNodeList gateway node list for bucket action
-     * @return created select type group description
      */
-    public GroupId createGatewayGroup(DeviceId srcDeviceId, List<OpenstackNode> gatewayNodeList) {
-        List<GroupBucket> bucketList = generateBucketsForSelectGroup(srcDeviceId, gatewayNodeList);
-        GroupId groupId = getGroupId(srcDeviceId);
-        GroupDescription groupDescription = new DefaultGroupDescription(
-                srcDeviceId,
-                GroupDescription.Type.SELECT,
-                new GroupBuckets(bucketList),
-                getGroupKey(srcDeviceId),
-                groupId.id(),
-                appId);
+    public void createGatewayGroup(OpenstackNode computeNode, List<OpenstackNode> gatewayNodeList) {
+        List<GroupBucket> bucketList;
+        GroupId groupId;
 
-        groupService.addGroup(groupDescription);
-        return groupId;
+        if (computeNode.dataIp().isPresent()) {
+            bucketList = generateBucketsForSelectGroup(computeNode, gatewayNodeList, NetworkMode.VXLAN);
+            groupId = groupId(computeNode.intBridge(), NetworkMode.VXLAN);
+
+            GroupDescription groupDescription = new DefaultGroupDescription(
+                    computeNode.intBridge(),
+                    GroupDescription.Type.SELECT,
+                    new GroupBuckets(bucketList),
+                    groupKey(computeNode.intBridge(), NetworkMode.VXLAN),
+                    groupId.id(),
+                    appId);
+
+            groupService.addGroup(groupDescription);
+        }
+
+        if (computeNode.vlanPort().isPresent()) {
+            bucketList = generateBucketsForSelectGroup(computeNode, gatewayNodeList, NetworkMode.VLAN);
+            groupId = groupId(computeNode.intBridge(), NetworkMode.VLAN);
+
+            GroupDescription groupDescription = new DefaultGroupDescription(
+                    computeNode.intBridge(),
+                    GroupDescription.Type.SELECT,
+                    new GroupBuckets(bucketList),
+                    groupKey(computeNode.intBridge(), NetworkMode.VLAN),
+                    groupId.id(),
+                    appId);
+
+            groupService.addGroup(groupDescription);
+        }
     }
 
     /**
-     * Returns unique group key with supplied source device ID as a hash.
-     *
+     * Returns unique group key with supplied source device ID and network mode as a hash.
      * @param srcDeviceId source device id
+     * @param networkMode network mode
      * @return group key
      */
-    public GroupKey getGroupKey(DeviceId srcDeviceId) {
-        return new DefaultGroupKey(srcDeviceId.toString().getBytes());
+    public GroupKey groupKey(DeviceId srcDeviceId, NetworkMode networkMode) {
+        if (networkMode.equals(NetworkMode.VXLAN)) {
+            return new DefaultGroupKey(srcDeviceId.toString().concat(DEFAULT_TUNNEL).getBytes());
+        } else {
+            return new DefaultGroupKey(srcDeviceId.toString().concat(VLAN).getBytes());
+        }
     }
 
-    private GroupId getGroupId(DeviceId srcDeviceId) {
-        return new GroupId(srcDeviceId.toString().hashCode());
+    private GroupId groupId(DeviceId srcDeviceId, NetworkMode networkMode) {
+        if (networkMode.equals(NetworkMode.VXLAN)) {
+            return new GroupId(srcDeviceId.toString().concat(DEFAULT_TUNNEL).hashCode());
+        } else {
+            return new GroupId(srcDeviceId.toString().concat(VLAN).hashCode());
+        }
     }
 
+
     /**
      * Updates groupBuckets in select type group.
      *
-     * @param deviceId target device id to update the group
+     * @param computeNode compute node
      * @param gatewayNodeList updated gateway node list for bucket action
+     * @param networkMode network mode
      * @param isInsert update type(add or remove)
      */
-    public void updateGatewayGroupBuckets(DeviceId deviceId,
+    public void updateGatewayGroupBuckets(OpenstackNode computeNode,
                                           List<OpenstackNode> gatewayNodeList,
+                                          NetworkMode networkMode,
                                           boolean isInsert) {
-        List<GroupBucket> bucketList = generateBucketsForSelectGroup(deviceId, gatewayNodeList);
-        GroupKey groupKey = getGroupKey(deviceId);
-        if (groupService.getGroup(deviceId, groupKey) == null) {
-            log.error("There's no group in compute node {}", deviceId);
+        List<GroupBucket> bucketList = generateBucketsForSelectGroup(computeNode, gatewayNodeList, networkMode);
+        GroupKey groupKey = groupKey(computeNode.intBridge(), networkMode);
+        if (groupService.getGroup(computeNode.intBridge(), groupKey) == null) {
+            log.error("There's no group in compute node {}", computeNode.intBridge());
             return;
         }
 
         if (isInsert) {
             groupService.addBucketsToGroup(
-                    deviceId,
+                    computeNode.intBridge(),
                     groupKey,
                     new GroupBuckets(bucketList),
                     groupKey, appId);
         } else {
             groupService.removeBucketsFromGroup(
-                    deviceId,
+                    computeNode.intBridge(),
                     groupKey,
                     new GroupBuckets(bucketList),
                     groupKey, appId);
         }
     }
 
-    private List<GroupBucket> generateBucketsForSelectGroup(DeviceId deviceId, List<OpenstackNode> gatewayNodeList) {
+
+
+    private List<GroupBucket> generateBucketsForSelectGroup(OpenstackNode computeNode,
+                                                         List<OpenstackNode> gatewayNodeList,
+                                                         NetworkMode networkMode) {
         List<GroupBucket> bucketList = Lists.newArrayList();
-        gatewayNodeList.forEach(node -> {
-            TrafficTreatment tBuilder = DefaultTrafficTreatment.builder()
-                    .extension(buildNiciraExtenstion(deviceId, node.dataIp().get().getIp4Address()), deviceId)
-                    .setOutput(getTunnelPort(deviceId))
-                    .build();
-            bucketList.add(createSelectGroupBucket(tBuilder));
-        });
-        return bucketList;
+
+        switch (networkMode) {
+            case VXLAN:
+                gatewayNodeList.stream()
+                        .filter(node -> node.dataIp().isPresent())
+                        .forEach(node -> {
+                            TrafficTreatment tBuilder = DefaultTrafficTreatment.builder()
+                                    .extension(buildNiciraExtenstion(computeNode.intBridge(),
+                                            node.dataIp().get().getIp4Address()),
+                                            computeNode.intBridge())
+                                    .setOutput(getTunnelPort(computeNode.intBridge()))
+                                    .build();
+                            bucketList.add(createSelectGroupBucket(tBuilder));
+                        });
+                return bucketList;
+            case VLAN:
+                gatewayNodeList.stream()
+                        .filter(node -> node.vlanPort().isPresent())
+                        .forEach(node -> {
+                            TrafficTreatment tBuilder = DefaultTrafficTreatment.builder()
+                                    .setEthDst(MacAddress.valueOf(vlanPortMac(node)))
+                                    .setOutput(vlanPortNum(computeNode))
+                                    .build();
+                            bucketList.add(createSelectGroupBucket(tBuilder));
+                        });
+                return bucketList;
+            default:
+                final String error = String.format(
+                        ERR_UNSUPPORTED_NET_TYPE + "%s",
+                        networkMode.toString());
+                throw new IllegalStateException(error);
+        }
     }
 
     /**
@@ -193,7 +255,7 @@
      */
     private PortNumber getTunnelPort(DeviceId deviceId) {
         Port port = deviceService.getPorts(deviceId).stream()
-                .filter(p -> p.annotations().value(PORT_NAME).equals(PORTNAME_PREFIX_TUNNEL))
+                .filter(p -> p.annotations().value(PORT_NAME).equals(DEFAULT_TUNNEL))
                 .findAny().orElse(null);
 
         if (port == null) {
@@ -201,6 +263,18 @@
             return null;
         }
         return port.number();
+    }
 
+    private PortNumber vlanPortNum(OpenstackNode node) {
+        return deviceService.getPorts(node.intBridge()).stream()
+                .filter(p -> p.annotations().value(PORT_NAME).equals(node.vlanPort().get()) &&
+                        p.isEnabled())
+                .map(Port::number).findFirst().get();
+
+    }
+    private String vlanPortMac(OpenstackNode node) {
+        return deviceService.getPorts(node.intBridge()).stream()
+                .filter(p -> p.annotations().value(PORT_NAME).equals(node.vlanPort().get()) && p.isEnabled())
+                .findFirst().get().annotations().value(PORT_MAC);
     }
 }