Add ovsdb vlan support by using OF1.3 50/6150/6
authorHsin-Yi Shen <hshen@redhat.com>
Thu, 17 Apr 2014 18:13:04 +0000 (14:13 -0400)
committerHsin-Yi Shen <hshen@redhat.com>
Mon, 19 May 2014 17:40:29 +0000 (13:40 -0400)
This change is to support vlan tenant isolation using OF1.3
This is using OF1.3 and Sam has the 1.0 change.

The changes of common neutron files are committed by Sam.
Most of the change here is for OF1.3 only.

This commit also has dependency on BUG 1020 "Multiple output actions is not allowed in the action list of apply-action instruction". The vlan and tunnel broadcast is broken due to BUG1020.
We don't want BUG 1020 to block the vlan feature commit and send this change for code review now.
Onve BUG 1020 is fixed, broadcast should work properly.

Change-Id: Ibd16404212cc1c4de21921477e4d1cf335a12b39
Signed-off-by: Hsin-Yi Shen <hshen@redhat.com>
neutron/src/main/java/org/opendaylight/ovsdb/neutron/AdminConfigManager.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/IAdminConfigManager.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/NetworkHandler.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/SouthboundHandler.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF10Provider.java
neutron/src/main/java/org/opendaylight/ovsdb/neutron/provider/OF13Provider.java

index 0f35d3610b52a6968baa3b03e9d3e34024f6f3aa..306c661c58360edd236203782ecdf5156899479c 100644 (file)
@@ -10,6 +10,8 @@
 package org.opendaylight.ovsdb.neutron;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 
 import org.opendaylight.controller.sal.core.Node;
@@ -202,6 +204,57 @@ public class AdminConfigManager implements IAdminConfigManager{
         return phyIf;
     }
 
+    /* Return all physical interfaces configure in bridge mapping
+     * Bridge mappings will be of the following format:
+     * bridge_mappings=physnet1:eth1,physnet2:eth2
+     * Method will return list = {eth1, eth2}
+     */
+    public List<String> getAllPhysicalInterfaceNames(Node node) {
+        List<String> phyIfName = new ArrayList<String>();
+
+        try {
+            OVSDBConfigService ovsdbConfig = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+            Map<String, Table<?>> ovsTable = ovsdbConfig.getRows(node, Open_vSwitch.NAME.getName());
+
+            if (ovsTable == null) {
+                logger.error("Open_vSwitch table is null for Node {} ", node);
+                return null;
+            }
+
+            // While there is only one entry in the HashMap, we can't access it by index...
+            for (Table<?> row : ovsTable.values()) {
+                String bridgeMaps;
+                Open_vSwitch ovsRow = (Open_vSwitch) row;
+                Map<String, String> configs = ovsRow.getOther_config();
+
+                if (configs == null) {
+                    logger.debug("Open_vSwitch table is null for Node {} ", node);
+                    continue;
+                }
+
+                bridgeMaps = configs.get(providerMappingsConfigName);
+                if (bridgeMaps == null) {
+                    bridgeMaps = providerMappings;
+                }
+
+                if (bridgeMaps != null) {
+                    for (String map : bridgeMaps.split(",")) {
+                        String[] pair = map.split(":");
+                        phyIfName.add(pair[1]);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("Unable to find physical interface for Node: {}",
+                    node, e);
+        }
+
+        logger.debug("Physical interface for Node: {}, If: {}",
+                node, phyIfName);
+
+        return phyIfName;
+    }
+
     public boolean isInterested (String tableName) {
         return tableName.equalsIgnoreCase(Open_vSwitch.NAME.getName());
     }
index 31c21a11afcf4dcc4cfa8890e9619e947fd5ef16..8d3cab20d8932c576ce564b26936e1fcc7c1ca2f 100644 (file)
@@ -11,7 +11,9 @@
 package org.opendaylight.ovsdb.neutron;
 
 import org.opendaylight.controller.sal.core.Node;
+
 import java.net.InetAddress;
+import java.util.List;
 
 public interface IAdminConfigManager {
     public String getIntegrationBridgeName();
@@ -25,6 +27,7 @@ public interface IAdminConfigManager {
     public String getPatchToIntegration();
     public void setPatchToIntegration(String patchToIntegration);
     public String getPhysicalInterfaceName (Node node, String physicalNetwork);
+    public List<String> getAllPhysicalInterfaceNames(Node node);
     public InetAddress getTunnelEndPoint(Node node);
     public boolean isInterested (String tableName);
 }
\ No newline at end of file
index 6cf85f29e47673aab8e173a7d8f48572470157ff..80cf8139ad5c57263d8bd5df0f7e0ab03f4168c2 100644 (file)
@@ -43,6 +43,7 @@ public class NetworkHandler extends BaseHandler
 
     // The implementation for each of these services is resolved by the OSGi Service Manager
     private volatile ITenantNetworkManager tenantNetworkManager;
+    private volatile IAdminConfigManager adminConfigManager;
 
     /**
      * Invoked when a network creation is requested
@@ -146,6 +147,7 @@ public class NetworkHandler extends BaseHandler
                 List<Node> nodes = connectionService.getNodes();
 
                 for (Node node : nodes) {
+                    List<String> phyIfName = adminConfigManager.getAllPhysicalInterfaceNames(node);
                     try {
                         ConcurrentMap<String, Table<?>> interfaces = this.ovsdbConfigService.getRows(node, Interface.NAME.getName());
                         if (interfaces != null) {
@@ -156,7 +158,11 @@ public class NetworkHandler extends BaseHandler
                                     /* delete tunnel ports on this node */
                                     logger.trace("Delete tunnel intf {}", intf);
                                     inventoryListener.rowRemoved(node, Interface.NAME.getName(), intfUUID,
-                                                                 intf, null);
+                                            intf, null);
+                                } else if (!phyIfName.isEmpty() && phyIfName.contains(intf.getName())) {
+                                    logger.trace("Delete physical intf {}", intf);
+                                    inventoryListener.rowRemoved(node, Interface.NAME.getName(), intfUUID,
+                                            intf, null);
                                 }
                             }
                         }
index 3504dd2c4326d38d55a686b08abefaf0e6ea4539..5d114870328873ce273ba5b6bc412f7acda247d4 100644 (file)
@@ -76,7 +76,8 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
                         break;
                     case ROW:
                         try {
-                            processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(), ev.getContext(), ev.getAction());
+                            processRowUpdate(ev.getNode(), ev.getTableName(), ev.getUuid(), ev.getRow(),
+                                             ev.getContext(),ev.getAction());
                         } catch (Exception e) {
                             logger.error("Exception caught in ProcessRowUpdate for node " + ev.getNode(), e);
                         }
@@ -141,7 +142,6 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
                 return false;
             }
         } else if (newRow.getTableName().equals(Open_vSwitch.NAME)) {
-    /* print the row for now */
             Open_vSwitch oldOpenvSwitch = (Open_vSwitch) oldRow;
             if (oldOpenvSwitch.getOther_config()== null) {
                 /* we are only interested in other_config field change */
@@ -182,10 +182,13 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
                 } else {
                     network = (NeutronNetwork)context;
                 }
+                List<String> phyIfName = adminConfigManager.getAllPhysicalInterfaceNames(node);
                 logger.info("Delete interface " + deletedIntf.getName());
+
                 if (deletedIntf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
-                    deletedIntf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
-                    /* delete tunnel interfaces */
+                    deletedIntf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
+                    phyIfName.contains(deletedIntf.getName())) {
+                    /* delete tunnel interfaces or physical interfaces */
                     this.handleInterfaceDelete(node, uuid, deletedIntf, false, null);
                 } else if (network != null && !network.getRouterExternal()) {
                     try {
@@ -271,8 +274,11 @@ public class SouthboundHandler extends BaseHandler implements OVSDBInventoryList
         logger.debug("handleInterfaceDelete: node: {}, uuid: {}, isLastInstanceOnNode: {}, interface: {}",
                 node, uuid, isLastInstanceOnNode, intf);
 
-        if (intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) || intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
-            /* delete tunnel interfaces */
+        List<String> phyIfName = adminConfigManager.getAllPhysicalInterfaceNames(node);
+        if (intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) ||
+            intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
+            phyIfName.contains(intf.getName())) {
+            /* delete tunnel or physical interfaces */
             providerNetworkManager.getProvider().handleInterfaceDelete(intf.getType(), null, node, intf, isLastInstanceOnNode);
         } else if (network != null) {
             if (!network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) { /* vlan doesn't need a tunnel endpoint */
index 1ffb83ffe6a0d1b5627010021005f798b4f15591..c506ae32f0de3588638871a95536464646063b02 100644 (file)
@@ -805,6 +805,7 @@ public class OF10Provider implements NetworkProvider {
                 srcNode, (network != null) ? network.getProviderNetworkType() : "",
                 intf.getName(), intf.getType(), isLastInstanceOnNode);
 
+        List<String> phyIfName = adminConfigManager.getAllPhysicalInterfaceNames(srcNode);
         if ((network != null) && network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
             if (isLastInstanceOnNode) {
                 this.removeVlanRules(network, srcNode, intf);
@@ -820,6 +821,8 @@ public class OF10Provider implements NetworkProvider {
             } catch (Exception e) {
                 logger.error(e.getMessage(), e);
             }
+        } else if (phyIfName.contains(intf.getName())) {
+            deletePhysicalPort(srcNode, intf.getName());
         } else {
             /* delete all other interfaces */
             IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
@@ -838,7 +841,6 @@ public class OF10Provider implements NetworkProvider {
                 }
             }
         }
-
         return status;
     }
 
@@ -878,14 +880,14 @@ public class OF10Provider implements NetworkProvider {
         return false;
     }
 
-    private String getTunnelPortUuid(Node node, String tunnelName, String bridgeUUID) throws Exception {
+    private String getPortUuid(Node node, String portName, String bridgeUUID) throws Exception {
         OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
         Bridge bridge = (Bridge)ovsdbTable.getRow(node, Bridge.NAME.getName(), bridgeUUID);
         if (bridge != null) {
             Set<UUID> ports = bridge.getPorts();
             for (UUID portUUID : ports) {
                 Port port = (Port)ovsdbTable.getRow(node, Port.NAME.getName(), portUUID.toString());
-                if (port != null && port.getName().equalsIgnoreCase(tunnelName)) return portUUID.toString();
+                if (port != null && port.getName().equalsIgnoreCase(portName)) return portUUID.toString();
             }
         }
         return null;
@@ -963,34 +965,34 @@ public class OF10Provider implements NetworkProvider {
         }
     }
 
-    private Status deleteTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
+    private Status deletePort(Node node, String bridgeName, String portName) {
         try {
             String bridgeUUID = null;
-            String tunnelBridgeName = adminConfigManager.getNetworkBridgeName();
             OVSDBConfigService ovsdbTable = (OVSDBConfigService)ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
             Map<String, Table<?>> bridgeTable = ovsdbTable.getRows(node, Bridge.NAME.getName());
             if (bridgeTable != null) {
                 for (String uuid : bridgeTable.keySet()) {
                     Bridge bridge = (Bridge)bridgeTable.get(uuid);
-                    if (bridge.getName().equals(tunnelBridgeName)) {
+                    if (bridge.getName().equals(bridgeName)) {
                         bridgeUUID = uuid;
                         break;
                     }
                 }
             }
             if (bridgeUUID == null) {
-                logger.debug("Could not find Bridge {} in {}", tunnelBridgeName, node);
+                logger.debug("Could not find Bridge {} in {}", bridgeName, node);
                 return new Status(StatusCode.SUCCESS);
             }
-            String portName = getTunnelName(tunnelType, key, dst);
-            String tunnelPortUUID = this.getTunnelPortUuid(node, portName, bridgeUUID);
-            Status status = ovsdbTable.deleteRow(node, Port.NAME.getName(), tunnelPortUUID);
-            if (!status.isSuccess()) {
-                logger.error("Failed to delete Tunnel port {} in {} status : {}", portName, bridgeUUID, status);
-                return status;
+            String portUUID = this.getPortUuid(node, portName, bridgeUUID);
+            Status status = new Status(StatusCode.SUCCESS);
+            if (portUUID != null) {
+                status = ovsdbTable.deleteRow(node, Port.NAME.getName(), portUUID);
+                if (!status.isSuccess()) {
+                    logger.error("Failed to delete port {} in {} status : {}", portName, bridgeUUID, status);
+                    return status;
+                }
+                logger.debug("Port {} delete status : {}", portName, status);
             }
-
-            logger.debug("Tunnel {} delete status : {}", portName, status);
             return status;
         } catch (Exception e) {
             logger.error("Exception in deleteTunnelPort", e);
@@ -998,6 +1000,19 @@ public class OF10Provider implements NetworkProvider {
         }
     }
 
+    private Status deleteTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst, String key) {
+        String tunnelBridgeName = adminConfigManager.getNetworkBridgeName();
+        String portName = getTunnelName(tunnelType, key, dst);
+        Status status = deletePort(node, tunnelBridgeName, portName);
+        return status;
+    }
+
+    private Status deletePhysicalPort(Node node, String phyIntfName) {
+        String netBridgeName = adminConfigManager.getNetworkBridgeName();
+        Status status = deletePort(node, netBridgeName, phyIntfName);
+        return status;
+    }
+
     @Override
     public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
         IConnectionServiceInternal connectionService = (IConnectionServiceInternal)ServiceHelper.getGlobalInstance(IConnectionServiceInternal.class, this);
index b656513dd747d8b774e129f4041f08c88870f8ce..8b9348469074aa6e24db846bbf5ea9f5810c6e1a 100644 (file)
@@ -48,24 +48,29 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DecNwTtlCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.DropActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PopVlanActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetFieldCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwDstActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetNwSrcActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.SetVlanIdActionCaseBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.StripVlanActionCaseBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.PushVlanActionCaseBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtl;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.dec.nw.ttl._case.DecNwTtlBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropAction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.drop.action._case.DropActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.push.vlan.action._case.PushVlanActionBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.pop.vlan.action._case.PopVlanActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.field._case.SetFieldBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.dst.action._case.SetNwDstActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.nw.src.action._case.SetNwSrcActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.set.vlan.id.action._case.SetVlanIdActionBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.strip.vlan.action._case.StripVlanAction;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.strip.vlan.action._case.StripVlanActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
@@ -88,6 +93,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instru
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
@@ -126,6 +142,7 @@ public class OF13Provider implements NetworkProvider {
     private static final short TABLE_0_DEFAULT_INGRESS = 0;
     private static final short TABLE_1_ISOLATE_TENANT = 10;
     private static final short TABLE_2_LOCAL_FORWARD = 20;
+    private static Long groupId = 1L;
 
     private IAdminConfigManager adminConfigManager;
     private IInternalNetworkManager internalNetworkManager;
@@ -310,6 +327,12 @@ public class OF13Provider implements NetworkProvider {
         return status;
     }
 
+    private Status deletePhysicalPort(Node node, String phyIntfName) {
+        String intBridgeName = adminConfigManager.getIntegrationBridgeName();
+        Status status = deletePort(node, intBridgeName, phyIntfName);
+        return status;
+    }
+
     private void programLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
          /*
          * Table(0) Rule #3
@@ -376,42 +399,42 @@ public class OF13Provider implements NetworkProvider {
 
     private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
         /*
-         ** Table(0) Rule #3
-         ** ----------------
-         ** Match: VM sMac and Local Ingress Port
-         ** Action:Action: Set Tunnel ID and GOTO Local Table (5)
-         **/
+         * Table(0) Rule #3
+         * ----------------
+         * Match: VM sMac and Local Ingress Port
+         * Action:Action: Set Tunnel ID and GOTO Local Table (5)
+         */
 
-        handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
+         handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
 
         /*
-         ** Table(0) Rule #4
-         ** ----------------
-         ** Match: Drop any remaining Ingress Local VM Packets
-         ** Action: Drop w/ a low priority
-         **/
+         * Table(0) Rule #4
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         */
 
-        handleDropSrcIface(dpid, localPort, false);
+         handleDropSrcIface(dpid, localPort, false);
 
-        /*
-         ** Table(2) Rule #1
-         ** ----------------
-         ** Match: Match TunID and Destination DL/dMAC Addr
-         ** Action: Output Port
-         ** table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
-         **/
+         /*
+          * Table(2) Rule #1
+          * ----------------
+          * Match: Match TunID and Destination DL/dMAC Addr
+          * Action: Output Port
+          * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+          */
 
-        handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
+         handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
 
-        /*
-         ** Table(2) Rule #2
-         ** ----------------
-         ** Match: Tunnel ID and dMAC (::::FF:FF)
-         ** table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
-         ** actions=output:2,3,4,5
-         **/
+         /*
+          * Table(2) Rule #2
+          * ----------------
+          * Match: Tunnel ID and dMAC (::::FF:FF)
+          * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+          * actions=output:2,3,4,5
+          */
 
-        handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
+          handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
     }
 
     private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
@@ -454,66 +477,283 @@ public class OF13Provider implements NetworkProvider {
 
     private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
         /*
-         ** Table(1) Rule #1
-         ** ----------------
-         ** Match: Drop any remaining Ingress Local VM Packets
-         ** Action: Drop w/ a low priority
-         ** -------------------------------------------
-         ** table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
-         ** actions=output:11,goto_table:2
-         **/
+         * Table(1) Rule #1
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         * -------------------------------------------
+         * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
+         * actions=output:11,goto_table:2
+         */
 
-       handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
+        handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
     }
 
     /* Remove tunnel rules if last node in this tenant network */
     private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
         /*
-         ** TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
-         **/
+         * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
+         */
         /*
-         ** Table(1) Rule #3
-         ** ----------------
-         ** Match: Any remaining Ingress Local VM Packets
-         ** Action: Drop w/ a low priority
-         ** -------------------------------------------
-         ** table=1,priority=8192,tun_id=0x5 actions=goto_table:2
-         **/
+         * Table(1) Rule #3
+         * ----------------
+         * Match:  Any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         * -------------------------------------------
+         * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
+         */
 
         handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
 
         /*
-         ** Table(2) Rule #3
-         ** ----------------
-         ** Match: Any Remaining Flows w/a TunID
-         ** Action: Drop w/ a low priority
-         ** table=2,priority=8192,tun_id=0x5 actions=drop
-         **/
+         * Table(2) Rule #3
+         * ----------------
+         * Match: Any Remaining Flows w/a TunID
+         * Action: Drop w/ a low priority
+         * table=2,priority=8192,tun_id=0x5 actions=drop
+         */
 
         handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
 
+        /*
+         * Table(0) Rule #2
+         * ----------------
+         * Match: Ingress Port, Tunnel ID
+         * Action: GOTO Local Table (10)
+         */
+
+        handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
+
+         /*
+          * Table(1) Rule #2
+          * ----------------
+          * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
+          * Action: Flood to selected destination TEPs
+          * -------------------------------------------
+          * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+          * actions=output:10,output:11,goto_table:2
+          */
+
+        handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
+    }
+
+    private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
+        /*
+         * Table(0) Rule #1
+         * ----------------
+         * Match: VM sMac and Local Ingress Port
+         * Action: Set VLAN ID and GOTO Local Table 1
+         */
+
+        handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
+                TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
+                attachedMac, true);
+
+        /*
+         * Table(0) Rule #3
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         */
+
+        handleDropSrcIface(dpid, localPort, true);
+
+        /*
+         * Table(2) Rule #1
+         * ----------------
+         * Match: Match VLAN ID and Destination DL/dMAC Addr
+         * Action: strip vlan, output to local port
+         * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
+         */
+
+        handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+                localPort, attachedMac, true);
+
+        /*
+         * Table(2) Rule #2
+         * ----------------
+         * Match: VLAN ID and dMAC (::::FF:FF)
+         * Action: strip vlan, output to all local ports in this vlan
+         * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions= strip_vlan, output:2,3,4,5
+         */
+
+        handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+                localPort, true);
+
+         /*
+          * Table(2) Rule #3
+          * ----------------
+          * Match: Any Remaining Flows w/a VLAN ID
+          * Action: Drop w/ a low priority
+          * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
+          */
+
+          handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+                                   true);
+   }
+
+    private void removeLocalVlanRules(Node node, Long dpid,
+                                      String segmentationId, String attachedMac,
+                                      long localPort) {
+        /*
+         * Table(0) Rule #1
+         * ----------------
+         * Match: VM sMac and Local Ingress Port
+         * Action: Set VLAN ID and GOTO Local Table 1
+         */
+
+        handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
+                TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
+                attachedMac, false);
+
+        /*
+         * Table(0) Rule #3
+         * ----------------
+         * Match: Drop any remaining Ingress Local VM Packets
+         * Action: Drop w/ a low priority
+         */
+
+        handleDropSrcIface(dpid, localPort, false);
+
+        /*
+         * Table(2) Rule #1
+         * ----------------
+         * Match: Match VLAN ID and Destination DL/dMAC Addr
+         * Action: strip vlan, output to local port
+         * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
+         */
+
+        handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+                localPort, attachedMac, false);
+
+        /*
+         * Table(2) Rule #2
+         * ----------------
+         * Match: VLAN ID and dMAC (::::FF:FF)
+         * Action: strip vlan, output to all local ports in this vlan
+         * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions= strip_vlan, output:2,3,4,5
+         */
+
+        handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+                localPort, false);
+   }
+
+   private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long ethPort) {
        /*
-        ** Table(0) Rule #2
-        ** ----------------
-        ** Match: Ingress Port, Tunnel ID
-        ** Action: GOTO Local Table (10)
-        **/
+        * Table(0) Rule #2
+        * ----------------
+        * Match: Ingress port = physical interface, Vlan ID
+        * Action: GOTO Local Table 2
+        */
 
-       handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
+       handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
+                    segmentationId, ethPort, true);
 
+        /*
+         * Table(1) Rule #2
+         * ----------------
+         * Match: Match VLAN ID and L2 ::::FF:FF Flooding
+         * Action: Flood to local and remote VLAN members
+         * -------------------------------------------
+         * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+         * actions=output:10 (eth port),goto_table:2
+         */
+
+        handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+                           segmentationId, ethPort, true);
+   }
+
+   private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long ethPort) {
        /*
-        ** Table(1) Rule #2
-        ** ----------------
-        ** Match: Match Tunnel ID and L2 ::::FF:FF Flooding
-        ** Action: Flood to selected destination TEPs
-        ** -------------------------------------------
-        ** table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
-        ** actions=output:10,output:11,goto_table:2
-        **/
+        * Table(1) Rule #1
+        * ----------------
+        * Match: Destination MAC is local VM MAC and vlan id
+        * Action: go to table 2
+        * -------------------------------------------
+        * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
+        * actions=goto_table:2
+        */
+
+       handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+                     segmentationId, ethPort, attachedMac, true);
 
-       handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
-    }
+       /*
+        * Table(1) Rule #3
+        * ----------------
+        * Match:  VLAN ID
+        * Action: Go to table 2
+        * -------------------------------------------
+        * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
+        */
+
+       handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+                      segmentationId, ethPort, true);
+   }
+
+   private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long ethPort) {
+       /*
+        * Table(1) Rule #1
+        * ----------------
+        * Match: Destination MAC is local VM MAC and vlan id
+        * Action: go to table 2
+        * -------------------------------------------
+        * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
+        * actions=goto_table:2
+        */
+
+       handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+                     segmentationId, ethPort, attachedMac, false);
+   }
+
+   private void removePerVlanRules(Node node, Long dpid, String segmentationId, long ethPort) {
+       /*
+        * Table(2) Rule #3
+        * ----------------
+        * Match: Any Remaining Flows w/a VLAN ID
+        * Action: Drop w/ a low priority
+        * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
+        */
+
+        handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
+                                 false);
+
+        /*
+         * Table(0) Rule #2
+         * ----------------
+         * Match: Ingress port = physical interface, Vlan ID
+         * Action: GOTO Local Table 2
+         */
+
+        handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
+                     segmentationId, ethPort, false);
+
+         /*
+          * Table(1) Rule #2
+          * ----------------
+          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
+          * Action: Flood to local and remote VLAN members
+          * -------------------------------------------
+          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+          * actions=output:10 (eth port),goto_table:2
+          */
+
+         handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+                            segmentationId, ethPort, false);
 
+         /*
+          * Table(1) Rule #3
+          * ----------------
+          * Match:  VLAN ID
+          * Action: Go to table 2
+          * -------------------------------------------
+          * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
+          */
+
+         handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
+                        segmentationId, ethPort, false);
+   }
     private Long getIntegrationBridgeOFDPID (Node node) {
         try {
             String bridgeName = adminConfigManager.getIntegrationBridgeName();
@@ -533,7 +773,7 @@ public class OF13Provider implements NetworkProvider {
             return 0L;
         }
     }
-    private void programLocalRules (String tunnelType, String segmentationId, Node node, Interface intf) {
+    private void programLocalRules (String networkType, String segmentationId, Node node, Interface intf) {
         try {
             Long dpid = this.getIntegrationBridgeOFDPID(node);
             if (dpid == 0L) {
@@ -560,7 +800,15 @@ public class OF13Provider implements NetworkProvider {
                 return;
             }
 
-            programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
+            /* Program local rules based on network type */
+            if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+                logger.debug("Program local vlan rules for interface {}", intf.getName());
+                programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
+            } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
+                       networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
+                logger.debug("Program local bridge rules for interface {}", intf.getName());
+                programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
+            }
         } catch (Exception e) {
             logger.error("Exception in programming Local Rules for "+intf+" on "+node, e);
         }
@@ -594,8 +842,11 @@ public class OF13Provider implements NetworkProvider {
             }
 
             /* Program local rules based on network type */
-            if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
-              networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
+            if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+                logger.debug("Remove local vlan rules for interface {}", intf.getName());
+                removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
+            } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
+                       networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
                 logger.debug("Remove local bridge rules for interface {}", intf.getName());
                 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
             }
@@ -604,7 +855,6 @@ public class OF13Provider implements NetworkProvider {
         }
     }
 
-
     private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
             Interface intf, boolean local) {
         try {
@@ -732,6 +982,149 @@ public class OF13Provider implements NetworkProvider {
         }
     }
 
+    private void programVlanRules (NeutronNetwork network, Node node, Interface intf) {
+        logger.debug("Program vlan rules for interface {}", intf.getName());
+
+        try {
+
+            Long dpid = this.getIntegrationBridgeOFDPID(node);
+            if (dpid == 0L) {
+                logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
+                return;
+            }
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+
+            Set<BigInteger> of_ports = intf.getOfport();
+            int timeout = 6;
+            while ((of_ports == null) && (timeout > 0)) {
+                of_ports = intf.getOfport();
+                if (of_ports == null || of_ports.size() <= 0) {
+                    // Wait for the OVSDB update to sync up the Local cache.
+                    Thread.sleep(500);
+                    timeout--;
+                    continue;
+                }
+            }
+            if (of_ports == null || of_ports.size() <= 0) {
+                logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
+                return;
+            }
+
+            Map<String, String> externalIds = intf.getExternal_ids();
+            if (externalIds == null) {
+                logger.error("No external_ids seen in {}", intf);
+                return;
+            }
+
+            String attachedMac = externalIds.get(tenantNetworkManager.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                logger.error("No AttachedMac seen in {}", intf);
+                return;
+            }
+
+            Map<String, org.opendaylight.ovsdb.lib.table.internal.Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
+            if (intfs != null) {
+                for (org.opendaylight.ovsdb.lib.table.internal.Table<?> row : intfs.values()) {
+                    Interface ethIntf = (Interface)row;
+                    if (ethIntf.getName().equalsIgnoreCase(adminConfigManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork()))) {
+                        of_ports = ethIntf.getOfport();
+                        timeout = 6;
+                        while ((of_ports == null) && (timeout > 0)) {
+                            of_ports = ethIntf.getOfport();
+                            if (of_ports == null || of_ports.size() <= 0) {
+                                // Wait for the OVSDB update to sync up the Local cache.
+                                Thread.sleep(500);
+                                timeout--;
+                                continue;
+                            }
+                        }
+
+                        if (of_ports == null || of_ports.size() <= 0) {
+                            logger.error("Could NOT Identify eth port {} on {}", ethIntf.getName(), node);
+                            continue;
+                        }
+                        long ethOFPort = ((BigInteger)of_ports.toArray()[0]).longValue();
+
+                        if (ethOFPort == -1) {
+                            logger.error("Could NOT Identify eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
+                            throw new Exception("port number < 0");
+                        }
+                        logger.debug("Identified eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
+
+                        programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, ethOFPort);
+                        programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, ethOFPort);
+                        return;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("", e);
+        }
+    }
+
+    private void removeVlanRules (NeutronNetwork network, Node node,
+                      Interface intf, boolean isLastInstanceOnNode) {
+        logger.debug("Remove vlan rules for interface {}", intf.getName());
+
+        try {
+
+            Long dpid = this.getIntegrationBridgeOFDPID(node);
+            if (dpid == 0L) {
+                logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
+                return;
+            }
+            OVSDBConfigService ovsdbTable = (OVSDBConfigService) ServiceHelper.getGlobalInstance(OVSDBConfigService.class, this);
+
+            Set<BigInteger> of_ports = intf.getOfport();
+            if (of_ports == null || of_ports.size() <= 0) {
+                logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
+                return;
+            }
+
+            Map<String, String> externalIds = intf.getExternal_ids();
+            if (externalIds == null) {
+                logger.error("No external_ids seen in {}", intf);
+                return;
+            }
+
+            String attachedMac = externalIds.get(tenantNetworkManager.EXTERNAL_ID_VM_MAC);
+            if (attachedMac == null) {
+                logger.error("No AttachedMac seen in {}", intf);
+                return;
+            }
+
+            Map<String, org.opendaylight.ovsdb.lib.table.internal.Table<?>> intfs = ovsdbTable.getRows(node, Interface.NAME.getName());
+            if (intfs != null) {
+                for (org.opendaylight.ovsdb.lib.table.internal.Table<?> row : intfs.values()) {
+                    Interface ethIntf = (Interface)row;
+                    if (ethIntf.getName().equalsIgnoreCase(adminConfigManager.getPhysicalInterfaceName(node,
+                                                                   network.getProviderPhysicalNetwork()))) {
+                        of_ports = ethIntf.getOfport();
+                        if (of_ports == null || of_ports.size() <= 0) {
+                            logger.error("Could NOT Identify eth port {} on {}", ethIntf.getName(), node);
+                            continue;
+                        }
+                        long ethOFPort = ((BigInteger)of_ports.toArray()[0]).longValue();
+
+                        if (ethOFPort == -1) {
+                            logger.error("Could NOT Identify eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
+                            throw new Exception("port number < 0");
+                        }
+                        logger.debug("Identified eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
+
+                        removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, ethOFPort);
+                        if (isLastInstanceOnNode) {
+                            removePerVlanRules(node, dpid, network.getProviderSegmentationID(), ethOFPort);
+                        }
+                        return;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("", e);
+        }
+    }
+
     @Override
     public Status handleInterfaceUpdate(NeutronNetwork network, Node srcNode, Interface intf) {
         ISwitchManager switchManager = (ISwitchManager) ServiceHelper.getInstance(ISwitchManager.class, "default", this);
@@ -767,16 +1160,21 @@ public class OF13Provider implements NetworkProvider {
         nodes.remove(srcNode);
         this.programLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), srcNode, intf);
 
-        for (Node dstNode : nodes) {
-            InetAddress src = adminConfigManager.getTunnelEndPoint(srcNode);
-            InetAddress dst = adminConfigManager.getTunnelEndPoint(dstNode);
-            Status status = addTunnelPort(srcNode, network.getProviderNetworkType(), src, dst);
-            if (status.isSuccess()) {
-                this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, intf, true);
-            }
-            addTunnelPort(dstNode, network.getProviderNetworkType(), dst, src);
-            if (status.isSuccess()) {
-                this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, intf, false);
+        if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+            this.programVlanRules(network, srcNode, intf);
+        } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
+                   || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)){
+            for (Node dstNode : nodes) {
+                InetAddress src = adminConfigManager.getTunnelEndPoint(srcNode);
+                InetAddress dst = adminConfigManager.getTunnelEndPoint(dstNode);
+                Status status = addTunnelPort(srcNode, network.getProviderNetworkType(), src, dst);
+                if (status.isSuccess()) {
+                    this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, intf, true);
+                }
+                addTunnelPort(dstNode, network.getProviderNetworkType(), dst, src);
+                if (status.isSuccess()) {
+                    this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, intf, false);
+                }
             }
         }
 
@@ -818,8 +1216,10 @@ public class OF13Provider implements NetworkProvider {
         nodes.remove(srcNode);
 
         logger.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
-        if (intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) || intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
-        /* Delete tunnel port */
+        List<String> phyIfName = adminConfigManager.getAllPhysicalInterfaceNames(srcNode);
+        if (intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)
+            || intf.getType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
+            /* Delete tunnel port */
             try {
                 OvsDBMap<String, String> options = intf.getOptions();
                 InetAddress src = InetAddress.getByName(options.get("local_ip"));
@@ -827,14 +1227,20 @@ public class OF13Provider implements NetworkProvider {
                 status = deleteTunnelPort(srcNode, intf.getType(), src, dst);
             } catch (Exception e) {
                 logger.error(e.getMessage(), e);
-             }
+            }
+        } else if (phyIfName.contains(intf.getName())) {
+            deletePhysicalPort(srcNode, intf.getName());
         } else {
             /* delete all other interfaces */
-            this.removeLocalRules(tunnelType, network.getProviderSegmentationID(),
-                                  srcNode, intf);
+            this.removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
+                    srcNode, intf);
+
+            if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
+                this.removeVlanRules(network, srcNode,
+                                 intf, isLastInstanceOnNode);
+            } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
+                   || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
 
-            if (tunnelType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
-                 || tunnelType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
                 for (Node dstNode : nodes) {
                     InetAddress src = adminConfigManager.getTunnelEndPoint(srcNode);
                     InetAddress dst = adminConfigManager.getTunnelEndPoint(dstNode);
@@ -935,8 +1341,9 @@ public class OF13Provider implements NetworkProvider {
      * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
      */
 
-    private void handleTunnelIn(Long dpidLong, Short writeTable, Short goToTableId,
-                                String segmentationId,  Long ofPort, boolean write) {
+    private void handleTunnelIn(Long dpidLong, Short writeTable,
+                                Short goToTableId, String segmentationId,
+                                Long ofPort, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -989,6 +1396,65 @@ public class OF13Provider implements NetworkProvider {
         }
     }
 
+    /*
+     * (Table:0) Ingress VLAN Traffic
+     * Match: OpenFlow InPort and vlan ID
+     * Action: GOTO Local Table (20)
+     * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
+     */
+
+    private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
+                      String segmentationId,  Long ethPort, boolean write) {
+
+        String nodeName = "openflow:" + dpidLong;
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create Match(es) and Set them in the FlowBuilder Object
+        flowBuilder.setMatch(createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId))).build());
+        flowBuilder.setMatch(createInPortMatch(matchBuilder, dpidLong, ethPort).build());
+
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
+
+            // Call the InstructionBuilder Methods Containing Actions
+            createGotoTableInstructions(ib, goToTableId);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+        }
+
+        String flowId = "VlanIn_"+segmentationId+"_"+ethPort;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(true);
+        flowBuilder.setBarrier(false);
+        flowBuilder.setTableId(writeTable);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
    /*
     * (Table:0) Egress VM Traffic Towards TEP
     * Match: Destination Ethernet Addr and OpenFlow InPort
@@ -998,7 +1464,8 @@ public class OF13Provider implements NetworkProvider {
     */
 
     private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
-                                   String segmentationId, Long inPort, String attachedMac, boolean write) {
+                           String segmentationId, Long inPort, String attachedMac,
+                           boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1055,7 +1522,74 @@ public class OF13Provider implements NetworkProvider {
     }
 
     /*
-     * (Table:0) Drop frames sourced from a VM that do not
+     * (Table:0) Egress VM Traffic Towards TEP
+     * Match: Source Ethernet Addr and OpenFlow InPort
+     * Instruction: Set VLANID and GOTO Table Egress (n)
+     * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
+     * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
+     */
+
+     private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
+                                  Short goToTableId, String segmentationId,
+                                  Long inPort, String attachedMac,
+                                  boolean write) {
+
+         String nodeName = "openflow:" + dpidLong;
+
+         MatchBuilder matchBuilder = new MatchBuilder();
+         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+         FlowBuilder flowBuilder = new FlowBuilder();
+
+         // Create the OF Match using MatchBuilder
+         flowBuilder.setMatch(createEthSrcMatch(matchBuilder, new MacAddress(attachedMac)).build());
+         // TODO Broken In_Port Match
+         flowBuilder.setMatch(createInPortMatch(matchBuilder, dpidLong, inPort).build());
+
+         String flowId = "LocalMac_"+segmentationId+"_"+inPort+"_"+attachedMac;
+         // Add Flow Attributes
+         flowBuilder.setId(new FlowId(flowId));
+         FlowKey key = new FlowKey(new FlowId(flowId));
+         flowBuilder.setStrict(true);
+         flowBuilder.setBarrier(false);
+         flowBuilder.setTableId(writeTable);
+         flowBuilder.setKey(key);
+         flowBuilder.setFlowName(flowId);
+         flowBuilder.setHardTimeout(0);
+         flowBuilder.setIdleTimeout(0);
+
+         if (write) {
+             // Instantiate the Builders for the OF Actions and Instructions
+             InstructionBuilder ib = new InstructionBuilder();
+             InstructionsBuilder isb = new InstructionsBuilder();
+
+             // Instructions List Stores Individual Instructions
+             List<Instruction> instructions = new ArrayList<Instruction>();
+
+             // GOTO Instructions Need to be added first to the List
+             createGotoTableInstructions(ib, goToTableId);
+             ib.setOrder(0);
+             ib.setKey(new InstructionKey(0));
+             instructions.add(ib.build());
+             // Set VLAN ID Instruction
+             createSetVlanInstructions(ib, new VlanId(Integer.valueOf(segmentationId)));
+             ib.setOrder(1);
+             ib.setKey(new InstructionKey(1));
+             instructions.add(ib.build());
+
+             // Add InstructionBuilder to the Instruction(s)Builder List
+             isb.setInstruction(instructions);
+
+             // Add InstructionsBuilder to FlowBuilder
+             flowBuilder.setInstructions(isb.build());
+
+             writeFlow(flowBuilder, nodeBuilder);
+         } else {
+             removeFlow(flowBuilder, nodeBuilder);
+         }
+     }
+
+    /*
+     * (Table:0) Drop frames source from a VM that do not
      * match the associated MAC address of the local VM.
      * Match: Low priority anything not matching the VM SMAC
      * Instruction: Drop
@@ -1120,9 +1654,10 @@ public class OF13Provider implements NetworkProvider {
     * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
     * actions=output:10,goto_table:2"
     */
-
-    private void handleTunnelOut(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId,
-                                 Long OFPortOut, String attachedMac, boolean write) {
+    private void handleTunnelOut(Long dpidLong, Short writeTable,
+                         Short goToTableId, String segmentationId,
+                         Long OFPortOut, String attachedMac,
+                         boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1177,6 +1712,66 @@ public class OF13Provider implements NetworkProvider {
         }
     }
 
+    /*
+     * (Table:1) Egress VLAN Traffic
+     * Match: Destination Ethernet Addr and VLAN id
+     * Instruction: GOTO Table Table 2
+     * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
+     * actions= goto_table:2"
+     */
+
+     private void handleVlanOut(Long dpidLong, Short writeTable,
+                        Short goToTableId, String segmentationId,
+                        Long ethPort, String attachedMac, boolean write) {
+
+         String nodeName = "openflow:" + dpidLong;
+
+         MatchBuilder matchBuilder = new MatchBuilder();
+         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+         FlowBuilder flowBuilder = new FlowBuilder();
+
+         // Create the OF Match using MatchBuilder
+         flowBuilder.setMatch(createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId))).build());
+         flowBuilder.setMatch(createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
+
+         String flowId = "VlanOut_"+segmentationId+"_"+ethPort+"_"+attachedMac;
+         // Add Flow Attributes
+         flowBuilder.setId(new FlowId(flowId));
+         FlowKey key = new FlowKey(new FlowId(flowId));
+         flowBuilder.setStrict(true);
+         flowBuilder.setBarrier(false);
+         flowBuilder.setTableId(writeTable);
+         flowBuilder.setKey(key);
+         flowBuilder.setFlowName(flowId);
+         flowBuilder.setHardTimeout(0);
+         flowBuilder.setIdleTimeout(0);
+
+         if (write) {
+             // Instantiate the Builders for the OF Actions and Instructions
+             InstructionBuilder ib = new InstructionBuilder();
+             InstructionsBuilder isb = new InstructionsBuilder();
+
+             // Instructions List Stores Individual Instructions
+             List<Instruction> instructions = new ArrayList<Instruction>();
+
+             // GOTO Instuctions
+             createGotoTableInstructions(ib, goToTableId);
+             ib.setOrder(0);
+             ib.setKey(new InstructionKey(0));
+             instructions.add(ib.build());
+
+             // Add InstructionBuilder to the Instruction(s)Builder List
+             isb.setInstruction(instructions);
+
+             // Add InstructionsBuilder to FlowBuilder
+             flowBuilder.setInstructions(isb.build());
+
+             writeFlow(flowBuilder, nodeBuilder);
+         } else {
+             removeFlow(flowBuilder, nodeBuilder);
+         }
+     }
+
        /*
     * (Table:1) Egress Tunnel Traffic
     * Match: Destination Ethernet Addr and Local InPort
@@ -1185,8 +1780,9 @@ public class OF13Provider implements NetworkProvider {
     * actions=output:10,output:11,goto_table:2
     */
 
-    private void handleTunnelFloodOut(Long dpidLong, Short writeTable, Short localTable,
-                                      String segmentationId,  Long OFPortOut, boolean write) {
+    private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
+                             Short localTable, String segmentationId,
+                             Long OFPortOut, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1227,12 +1823,13 @@ public class OF13Provider implements NetworkProvider {
         }
 
         if (write) {
-            // GOTO Instuction
+            // GOTO Instruction
             createGotoTableInstructions(ib, localTable);
             ib.setOrder(0);
             ib.setKey(new InstructionKey(0));
             instructions.add(ib.build());
             // Set the Output Port/Iface
+            //createOutputGroupInstructions(nodeBuilder, ib, dpidLong, OFPortOut, existingInstructions);
             createOutputPortInstructions(ib, dpidLong, OFPortOut, existingInstructions);
             ib.setOrder(1);
             ib.setKey(new InstructionKey(1));
@@ -1247,7 +1844,8 @@ public class OF13Provider implements NetworkProvider {
             writeFlow(flowBuilder, nodeBuilder);
         } else {
             /* remove port from action list */
-            boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong,OFPortOut, existingInstructions);
+            boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong,
+                                   OFPortOut, existingInstructions);
             if (flowRemove) {
                 /* if all port are removed, remove the flow too. */
                 removeFlow(flowBuilder, nodeBuilder);
@@ -1266,6 +1864,72 @@ public class OF13Provider implements NetworkProvider {
         }
     }
 
+    /*
+     * (Table:1) Egress VLAN Traffic
+     * Match: Destination Ethernet Addr and VLAN id
+     * Instruction: GOTO table 2 and Output port eth interface
+     * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=output:eth1,goto_table:2
+     */
+
+     private void handleVlanFloodOut(Long dpidLong, Short writeTable,
+                           Short localTable, String segmentationId,
+                           Long ethPort, boolean write) {
+
+         String nodeName = "openflow:" + dpidLong;
+
+         MatchBuilder matchBuilder = new MatchBuilder();
+         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+         FlowBuilder flowBuilder = new FlowBuilder();
+
+         // Create the OF Match using MatchBuilder
+         // Match Vlan ID
+         flowBuilder.setMatch(createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId))).build());
+         // Match DMAC
+         flowBuilder.setMatch(createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"), new MacAddress("01:00:00:00:00:00")).build());
+
+         String flowId = "VlanFloodOut_"+segmentationId;
+         // Add Flow Attributes
+         flowBuilder.setId(new FlowId(flowId));
+         FlowKey key = new FlowKey(new FlowId(flowId));
+         flowBuilder.setBarrier(true);
+         flowBuilder.setTableId(writeTable);
+         flowBuilder.setKey(key);
+         flowBuilder.setPriority(16384);
+         flowBuilder.setFlowName(flowId);
+         flowBuilder.setHardTimeout(0);
+         flowBuilder.setIdleTimeout(0);
+
+         Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+         // Instantiate the Builders for the OF Actions and Instructions
+         InstructionBuilder ib = new InstructionBuilder();
+         InstructionsBuilder isb = new InstructionsBuilder();
+         List<Instruction> instructions = new ArrayList<Instruction>();
+
+         if (write) {
+             // GOTO Instuction
+             createGotoTableInstructions(ib, localTable);
+             ib.setOrder(0);
+             ib.setKey(new InstructionKey(0));
+             instructions.add(ib.build());
+             // Set the Output Port/Iface
+             createOutputPortInstructions(ib, dpidLong, ethPort);
+             ib.setOrder(1);
+             ib.setKey(new InstructionKey(1));
+             instructions.add(ib.build());
+
+             // Add InstructionBuilder to the Instruction(s)Builder List
+             isb.setInstruction(instructions);
+
+             // Add InstructionsBuilder to FlowBuilder
+             flowBuilder.setInstructions(isb.build());
+
+             writeFlow(flowBuilder, nodeBuilder);
+         } else {
+             removeFlow(flowBuilder, nodeBuilder);
+         }
+     }
+
    /*
     * (Table:1) Table Drain w/ Catch All
     * Match: Tunnel ID
@@ -1273,7 +1937,9 @@ public class OF13Provider implements NetworkProvider {
     * table=2,priority=8192,tun_id=0x5 actions=drop
     */
 
-    private void handleTunnelMiss(Long dpidLong, Short writeTable, Short goToTableId, String segmentationId, boolean write) {
+    private void handleTunnelMiss(Long dpidLong, Short writeTable,
+                          Short goToTableId, String segmentationId,
+                          boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1324,6 +1990,72 @@ public class OF13Provider implements NetworkProvider {
         }
     }
 
+
+    /*
+     * (Table:1) Table Drain w/ Catch All
+     * Match: Vlan ID
+     * Action: Output port eth interface
+     * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
+     */
+
+     private void handleVlanMiss(Long dpidLong, Short writeTable,
+                         Short goToTableId, String segmentationId,
+                         Long ethPort, boolean write) {
+
+         String nodeName = "openflow:" + dpidLong;
+
+         MatchBuilder matchBuilder = new MatchBuilder();
+         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+         FlowBuilder flowBuilder = new FlowBuilder();
+
+         // Create Match(es) and Set them in the FlowBuilder Object
+         flowBuilder.setMatch(createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId))).build());
+
+         if (write) {
+             // Create the OF Actions and Instructions
+             InstructionBuilder ib = new InstructionBuilder();
+             InstructionsBuilder isb = new InstructionsBuilder();
+
+             // Instructions List Stores Individual Instructions
+             List<Instruction> instructions = new ArrayList<Instruction>();
+
+             // Call the InstructionBuilder Methods Containing Actions
+             //createGotoTableInstructions(ib, goToTableId);
+             //ib.setOrder(0);
+             //ib.setKey(new InstructionKey(0));
+             //instructions.add(ib.build());
+             // Set the Output Port/Iface
+             createOutputPortInstructions(ib, dpidLong, ethPort);
+             ib.setOrder(0);
+             ib.setKey(new InstructionKey(1));
+             instructions.add(ib.build());
+
+             // Add InstructionBuilder to the Instruction(s)Builder List
+             isb.setInstruction(instructions);
+
+             // Add InstructionsBuilder to FlowBuilder
+             flowBuilder.setInstructions(isb.build());
+         }
+
+         String flowId = "VlanMiss_"+segmentationId;
+         // Add Flow Attributes
+         flowBuilder.setId(new FlowId(flowId));
+         FlowKey key = new FlowKey(new FlowId(flowId));
+         flowBuilder.setStrict(true);
+         flowBuilder.setBarrier(false);
+         flowBuilder.setTableId(writeTable);
+         flowBuilder.setKey(key);
+         flowBuilder.setPriority(8192);
+         flowBuilder.setFlowName(flowId);
+         flowBuilder.setHardTimeout(0);
+         flowBuilder.setIdleTimeout(0);
+         if (write) {
+             writeFlow(flowBuilder, nodeBuilder);
+         } else {
+             removeFlow(flowBuilder, nodeBuilder);
+         }
+     }
+
     /*
      * (Table:1) Local Broadcast Flood
      * Match: Tunnel ID and dMAC
@@ -1331,8 +2063,9 @@ public class OF13Provider implements NetworkProvider {
      * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
      */
 
-    private void handleLocalUcastOut(Long dpidLong, Short writeTable, String segmentationId, Long localPort,
-                                     String attachedMac, boolean write) {
+    private void handleLocalUcastOut(Long dpidLong, Short writeTable,
+                             String segmentationId, Long localPort,
+                             String attachedMac, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1382,14 +2115,81 @@ public class OF13Provider implements NetworkProvider {
     }
 
     /*
-     * (Table:1) Local Broadcast Flood
+     * (Table:2) Local VLAN unicast
+     * Match: VLAN ID and dMAC
+     * Action: Output Port
+     * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
+     */
+
+    private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
+                                 String segmentationId, Long localPort,
+                                 String attachedMac, boolean write) {
+
+        String nodeName = "openflow:" + dpidLong;
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        flowBuilder.setMatch(createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId))).build());
+        flowBuilder.setMatch(createDestEthMatch(matchBuilder, new MacAddress(attachedMac), null).build());
+
+        String flowId = "VlanUcastOut_"+segmentationId+"_"+localPort+"_"+attachedMac;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(true);
+        flowBuilder.setBarrier(false);
+        flowBuilder.setTableId(writeTable);
+        flowBuilder.setKey(key);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+
+        if (write) {
+            // Instantiate the Builders for the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
+            List<Instruction> instructions_tmp = new ArrayList<Instruction>();
+
+            /* Strip vlan and store to tmp instruction space*/
+            createPopVlanInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions_tmp.add(ib.build());
+
+            // Set the Output Port/Iface
+            ib = new InstructionBuilder();
+            addOutputPortInstructions(ib, dpidLong, localPort, instructions_tmp);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
+        }
+    }
+
+    /*
+     * (Table:2) Local Broadcast Flood
      * Match: Tunnel ID and dMAC (::::FF:FF)
      * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
      * actions=output:2,3,4,5
      */
 
-    private void handleLocalBcastOut(Long dpidLong, Short writeTable, String segmentationId,
-                                     Long localPort, boolean write) {
+    private void handleLocalBcastOut(Long dpidLong, Short writeTable,
+                             String segmentationId, Long localPort,
+                             boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1441,37 +2241,208 @@ public class OF13Provider implements NetworkProvider {
 
             writeFlow(flowBuilder, nodeBuilder);
         } else {
-            boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong,
-                                       localPort, existingInstructions);
-            if (flowRemove) {
-                   /* if all ports are removed, remove flow */
-                 removeFlow(flowBuilder, nodeBuilder);
-               } else {
-                /* Install instruction with new output port list*/
-                   ib.setOrder(0);
-                   ib.setKey(new InstructionKey(0));
-                 instructions.add(ib.build());
-
-                // Add InstructionBuilder to the Instruction(s)Builder List
-                isb.setInstruction(instructions);
-
-                // Add InstructionsBuilder to FlowBuilder
-                   flowBuilder.setInstructions(isb.build());
-
-                   writeFlow(flowBuilder, nodeBuilder);
-            }
+            boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong, localPort,
+                                                                  existingInstructions);
+            if (flowRemove) {
+                /* if all ports are removed, remove flow */
+                removeFlow(flowBuilder, nodeBuilder);
+            } else {
+                /* Install instruction with new output port list*/
+                ib.setOrder(0);
+                ib.setKey(new InstructionKey(0));
+                instructions.add(ib.build());
+
+                // Add InstructionBuilder to the Instruction(s)Builder List
+                isb.setInstruction(instructions);
+
+                // Add InstructionsBuilder to FlowBuilder
+                flowBuilder.setInstructions(isb.build());
+
+                writeFlow(flowBuilder, nodeBuilder);
+            }
+        }
+    }
+
+    /*
+     * (Table:2) Local VLAN Broadcast Flood
+     * Match: vlan ID and dMAC (::::FF:FF)
+     * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
+     * actions=strip_vlan, output:2,3,4,5
+     */
+
+    private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable,
+                                 String segmentationId, Long localPort,
+                                 boolean write) {
+
+        String nodeName = "openflow:" + dpidLong;
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create the OF Match using MatchBuilder
+        flowBuilder.setMatch(createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId))).build());
+        flowBuilder.setMatch(createDestEthMatch(matchBuilder, new MacAddress("01:00:00:00:00:00"), new MacAddress("01:00:00:00:00:00")).build());
+
+        String flowId = "VlanBcastOut_"+segmentationId;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(true);
+        flowBuilder.setBarrier(false);
+        flowBuilder.setTableId(writeTable);
+        flowBuilder.setKey(key);
+        flowBuilder.setPriority(16384);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        Flow flow = this.getFlow(flowBuilder, nodeBuilder);
+        // Instantiate the Builders for the OF Actions and Instructions
+        InstructionBuilder ib = new InstructionBuilder();
+        InstructionsBuilder isb = new InstructionsBuilder();
+        List<Instruction> instructions = new ArrayList<Instruction>();
+        List<Instruction> existingInstructions = null;
+        boolean add_pop_vlan = true;
+        if (flow != null) {
+            Instructions ins = flow.getInstructions();
+            if (ins != null) {
+                existingInstructions = ins.getInstruction();
+            }
+        }
+
+        if (write) {
+            if (existingInstructions != null) {
+                /* Check if pop vlan is already the first action in action list */
+                List<Action> existingActions = null;
+                for (Instruction in : existingInstructions) {
+                    if (in.getInstruction() instanceof ApplyActionsCase) {
+                        existingActions = (((ApplyActionsCase)
+                                in.getInstruction()).getApplyActions().getAction());
+                        if (existingActions.get(0).getAction() instanceof PopVlanActionCase) {
+                            add_pop_vlan = false;
+                            break;
+                        }
+                    }
+                }
+            } else {
+                existingInstructions = new ArrayList<Instruction>();
+            }
+
+            if (add_pop_vlan) {
+                /* pop vlan */
+                createPopVlanInstructions(ib);
+                ib.setOrder(0);
+                ib.setKey(new InstructionKey(0));
+                existingInstructions.add(ib.build());
+                ib = new InstructionBuilder();
+            }
+
+            // Create port list
+            //createOutputGroupInstructions(nodeBuilder, ib, dpidLong, localPort, existingInstructions);
+            createOutputPortInstructions(ib, dpidLong, localPort, existingInstructions);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            //boolean flowRemove = removeOutputPortFromGroup(nodeBuilder, ib, dpidLong,
+            //                     localPort, existingInstructions);
+            boolean flowRemove = removeOutputPortFromInstructions(ib, dpidLong,
+                                                    localPort, existingInstructions);
+            if (flowRemove) {
+                /* if all ports are removed, remove flow */
+                removeFlow(flowBuilder, nodeBuilder);
+            } else {
+                /* Install instruction with new output port list*/
+                ib.setOrder(0);
+                ib.setKey(new InstructionKey(0));
+                instructions.add(ib.build());
+
+                // Add InstructionBuilder to the Instruction(s)Builder List
+                isb.setInstruction(instructions);
+
+                // Add InstructionsBuilder to FlowBuilder
+                flowBuilder.setInstructions(isb.build());
+                writeFlow(flowBuilder, nodeBuilder);
+            }
+        }
+    }
+
+    /*
+     * (Table:1) Local Table Miss
+     * Match: Any Remaining Flows w/a TunID
+     * Action: Drop w/ a low priority
+     * table=2,priority=8192,tun_id=0x5 actions=drop
+     */
+
+    private void handleLocalTableMiss(Long dpidLong, Short writeTable,
+                             String segmentationId, boolean write) {
+
+        String nodeName = "openflow:" + dpidLong;
+
+        MatchBuilder matchBuilder = new MatchBuilder();
+        NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
+        FlowBuilder flowBuilder = new FlowBuilder();
+
+        // Create Match(es) and Set them in the FlowBuilder Object
+        flowBuilder.setMatch(createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+
+        if (write) {
+            // Create the OF Actions and Instructions
+            InstructionBuilder ib = new InstructionBuilder();
+            InstructionsBuilder isb = new InstructionsBuilder();
+
+            // Instructions List Stores Individual Instructions
+            List<Instruction> instructions = new ArrayList<Instruction>();
+
+            // Call the InstructionBuilder Methods Containing Actions
+            createDropInstructions(ib);
+            ib.setOrder(0);
+            ib.setKey(new InstructionKey(0));
+            instructions.add(ib.build());
+
+            // Add InstructionBuilder to the Instruction(s)Builder List
+            isb.setInstruction(instructions);
+
+            // Add InstructionsBuilder to FlowBuilder
+            flowBuilder.setInstructions(isb.build());
+        }
+
+        String flowId = "LocalTableMiss_"+segmentationId;
+        // Add Flow Attributes
+        flowBuilder.setId(new FlowId(flowId));
+        FlowKey key = new FlowKey(new FlowId(flowId));
+        flowBuilder.setStrict(true);
+        flowBuilder.setBarrier(false);
+        flowBuilder.setTableId(writeTable);
+        flowBuilder.setKey(key);
+        flowBuilder.setPriority(8192);
+        flowBuilder.setFlowName(flowId);
+        flowBuilder.setHardTimeout(0);
+        flowBuilder.setIdleTimeout(0);
+        if (write) {
+            writeFlow(flowBuilder, nodeBuilder);
+        } else {
+            removeFlow(flowBuilder, nodeBuilder);
         }
     }
 
     /*
      * (Table:1) Local Table Miss
-     * Match: Any Remaining Flows w/a TunID
+     * Match: Any Remaining Flows w/a VLAN ID
      * Action: Drop w/ a low priority
-     * table=2,priority=8192,tun_id=0x5 actions=drop
+     * table=2,priority=8192,vlan_id=0x5 actions=drop
      */
 
-    private void handleLocalTableMiss(Long dpidLong, Short writeTable, String segmentationId,
-                                      boolean write) {
+    private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
+                                  String segmentationId, boolean write) {
 
         String nodeName = "openflow:" + dpidLong;
 
@@ -1480,7 +2451,7 @@ public class OF13Provider implements NetworkProvider {
         FlowBuilder flowBuilder = new FlowBuilder();
 
         // Create Match(es) and Set them in the FlowBuilder Object
-        flowBuilder.setMatch(createTunnelIDMatch(matchBuilder, new BigInteger(segmentationId)).build());
+        flowBuilder.setMatch(createVlanIdMatch(matchBuilder, new VlanId(Integer.valueOf(segmentationId))).build());
 
         if (write) {
             // Create the OF Actions and Instructions
@@ -1522,6 +2493,90 @@ public class OF13Provider implements NetworkProvider {
         }
     }
 
+    private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
+        IMDSALConsumer mdsalConsumer = (IMDSALConsumer) ServiceHelper.getInstance(IMDSALConsumer.class, "default", this);
+        if (mdsalConsumer == null) {
+            logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
+            return null;
+        }
+
+        dataBrokerService = mdsalConsumer.getDataBrokerService();
+
+        if (dataBrokerService == null) {
+            logger.error("ERROR finding reference for DataBrokerService. Please check out the MD-SAL support on the Controller.");
+            return null;
+        }
+
+        InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
+                new GroupKey(groupBuilder.getGroupId())).build();
+        return (Group)dataBrokerService.readConfigurationData(path1);
+    }
+
+    private Group writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
+        IMDSALConsumer mdsalConsumer = (IMDSALConsumer) ServiceHelper.getInstance(IMDSALConsumer.class, "default", this);
+        if (mdsalConsumer == null) {
+            logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
+            return null;
+        }
+
+        dataBrokerService = mdsalConsumer.getDataBrokerService();
+
+        if (dataBrokerService == null) {
+            logger.error("ERROR finding reference for DataBrokerService. Please check out the MD-SAL support on the Controller.");
+            return null;
+        }
+        DataModification<InstanceIdentifier<?>, DataObject> modification = dataBrokerService.beginTransaction();
+        InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
+                new GroupKey(groupBuilder.getGroupId())).build();
+        modification.putConfigurationData(nodeBuilderToInstanceId(nodeBuilder), nodeBuilder.build());
+        modification.putConfigurationData(path1, groupBuilder.build());
+        Future<RpcResult<TransactionStatus>> commitFuture = modification.commit();
+
+        try {
+            RpcResult<TransactionStatus> result = commitFuture.get();
+            TransactionStatus status = result.getResult();
+            logger.debug("Transaction Status "+status.toString()+" for Group "+groupBuilder.getGroupName());
+        } catch (InterruptedException e) {
+            logger.error(e.getMessage(), e);
+        } catch (ExecutionException e) {
+            logger.error(e.getMessage(), e);
+        }
+        return (Group)dataBrokerService.readConfigurationData(path1);
+    }
+
+    private Group removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
+        IMDSALConsumer mdsalConsumer = (IMDSALConsumer) ServiceHelper.getInstance(IMDSALConsumer.class, "default", this);
+        if (mdsalConsumer == null) {
+            logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
+            return null;
+        }
+
+        dataBrokerService = mdsalConsumer.getDataBrokerService();
+
+        if (dataBrokerService == null) {
+            logger.error("ERROR finding reference for DataBrokerService. Please check out the MD-SAL support on the Controller.");
+            return null;
+        }
+        DataModification<InstanceIdentifier<?>, DataObject> modification = dataBrokerService.beginTransaction();
+        InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
+                .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
+                new GroupKey(groupBuilder.getGroupId())).build();
+        modification.removeConfigurationData(path1);
+        Future<RpcResult<TransactionStatus>> commitFuture = modification.commit();
+
+        try {
+            RpcResult<TransactionStatus> result = commitFuture.get();
+            TransactionStatus status = result.getResult();
+            logger.debug("Transaction Status "+status.toString()+" for Group "+groupBuilder.getGroupName());
+        } catch (InterruptedException e) {
+            logger.error(e.getMessage(), e);
+        } catch (ExecutionException e) {
+            logger.error(e.getMessage(), e);
+        }
+        return (Group)dataBrokerService.readConfigurationData(path1);
+    }
     private Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
         IMDSALConsumer mdsalConsumer = (IMDSALConsumer) ServiceHelper.getInstance(IMDSALConsumer.class, "default", this);
         if (mdsalConsumer == null) {
@@ -1559,8 +2614,8 @@ public class OF13Provider implements NetworkProvider {
         InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
                 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
-        modification.putOperationalData(nodeBuilderToInstanceId(nodeBuilder), nodeBuilder.build());
-        modification.putOperationalData(path1, flowBuilder.build());
+        //modification.putOperationalData(nodeBuilderToInstanceId(nodeBuilder), nodeBuilder.build());
+        //modification.putOperationalData(path1, flowBuilder.build());
         modification.putConfigurationData(nodeBuilderToInstanceId(nodeBuilder), nodeBuilder.build());
         modification.putConfigurationData(path1, flowBuilder.build());
         Future<RpcResult<TransactionStatus>> commitFuture = modification.commit();
@@ -1585,7 +2640,7 @@ public class OF13Provider implements NetworkProvider {
         dataBrokerService = mdsalConsumer.getDataBrokerService();
 
         if (dataBrokerService == null) {
-            logger.error("ERROR finding reference for DataBrokerService. Please check out the MD-SALsupport on the Controller.");
+            logger.error("ERROR finding reference for DataBrokerService. Please check out the MD-SAL support on the Controller.");
             return;
         }
         DataModification<InstanceIdentifier<?>, DataObject> modification = dataBrokerService.beginTransaction();
@@ -1595,7 +2650,7 @@ public class OF13Provider implements NetworkProvider {
                 .augmentation(FlowCapableNode.class).child(Table.class,
                 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
         //modification.removeOperationalData(nodeBuilderToInstanceId(nodeBuilder));
-        modification.removeOperationalData(path1);
+        //modification.removeOperationalData(path1);
         //modification.removeConfigurationData(nodeBuilderToInstanceId(nodeBuilder));
         modification.removeConfigurationData(path1);
         Future<RpcResult<TransactionStatus>> commitFuture = modification.commit();
@@ -1673,10 +2728,10 @@ public class OF13Provider implements NetworkProvider {
      */
 
     protected static MatchBuilder createVlanIdMatch(MatchBuilder matchBuilder, VlanId vlanId) {
-
         VlanMatchBuilder vlanMatchBuilder = new VlanMatchBuilder();
         VlanIdBuilder vlanIdBuilder = new VlanIdBuilder();
         vlanIdBuilder.setVlanId(new VlanId(vlanId));
+        vlanIdBuilder.setVlanIdPresent(true);
         vlanMatchBuilder.setVlanId(vlanIdBuilder.build());
         matchBuilder.setVlanMatch(vlanMatchBuilder.build());
 
@@ -1913,15 +2968,16 @@ public class OF13Provider implements NetworkProvider {
     }
 
     /**
-     * Create Output Port Instruction
+     * Create Output Port Group Instruction
      *
      * @param ib       Map InstructionBuilder without any instructions
      * @param dpidLong Long the datapath ID of a switch/node
      * @param port     Long representing a port on a switch/node
      * @return ib InstructionBuilder Map with instructions
      */
-    protected static InstructionBuilder createOutputPortInstructions(InstructionBuilder ib, Long dpidLong, Long port , List<Instruction> instructions) {
-
+    protected InstructionBuilder createOutputPortInstructions(InstructionBuilder ib,
+                                                              Long dpidLong, Long port ,
+                                                              List<Instruction> instructions) {
         NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
         logger.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
 
@@ -1937,24 +2993,184 @@ public class OF13Provider implements NetworkProvider {
                 }
             }
         }
-
+        /* Create output action for this port*/
         OutputActionBuilder oab = new OutputActionBuilder();
         oab.setOutputNodeConnector(ncid);
         ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
-        ab.setOrder(0);
-        ab.setKey(new ActionKey(0));
-        Action newAction = ab.build();
         boolean addNew = true;
+
+        /* Find the group action and get the group */
         for (Action action : actionList) {
             if (action.getAction() instanceof OutputActionCase) {
                 OutputActionCase opAction = (OutputActionCase)action.getAction();
+                /* If output port action already in the action list of one of the buckets, skip */
                 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
                     addNew = false;
                     break;
                 }
             }
         }
-        if (addNew) actionList.add(newAction);
+        if (addNew) {
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+        }
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+        logger.debug("createOutputPortInstructions() : applyAction {}", aab.build());
+        return ib;
+    }
+
+    /**
+     * Create Output Port Group Instruction
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
+                                                               InstructionBuilder ib,
+                                                               Long dpidLong, Long port ,
+                                                               List<Instruction> instructions) {
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+        logger.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
+
+        List<Action> actionList = new ArrayList<Action>();
+        ActionBuilder ab = new ActionBuilder();
+
+        List<Action> existingActions = null;
+        if (instructions != null) {
+            for (Instruction in : instructions) {
+                if (in.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                    actionList.addAll(existingActions);
+                }
+            }
+        }
+
+        GroupBuilder groupBuilder = new GroupBuilder();
+        Group group = null;
+
+        /* Create output action for this port*/
+        OutputActionBuilder oab = new OutputActionBuilder();
+        oab.setOutputNodeConnector(ncid);
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
+        logger.debug("createOutputGroupInstructions(): output action {}", ab.build());
+        boolean addNew = true;
+        boolean groupActionAdded = false;
+
+        /* Find the group action and get the group */
+        for (Action action : actionList) {
+            if (action.getAction() instanceof GroupActionCase) {
+                groupActionAdded = true;
+                GroupActionCase groupAction = (GroupActionCase) action.getAction();
+                Long id = groupAction.getGroupAction().getGroupId();
+                String groupName = groupAction.getGroupAction().getGroup();
+                GroupKey key = new GroupKey(new GroupId(id));
+
+                groupBuilder.setGroupId(new GroupId(id));
+                groupBuilder.setGroupName(groupName);
+                groupBuilder.setGroupType(GroupTypes.GroupAll);
+                groupBuilder.setKey(key);
+                group = getGroup(groupBuilder, nodeBuilder);
+                logger.debug("createOutputGroupInstructions: group {}", group);
+                break;
+            }
+        }
+
+        logger.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
+        if (groupActionAdded) {
+            /* modify the action bucket in group */
+            groupBuilder = new GroupBuilder(group);
+            Buckets buckets = groupBuilder.getBuckets();
+            for (Bucket bucket : buckets.getBucket()) {
+                List<Action> bucketActions = bucket.getAction();
+                logger.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
+                for (Action action : bucketActions) {
+                    if (action.getAction() instanceof OutputActionCase) {
+                        OutputActionCase opAction = (OutputActionCase)action.getAction();
+                        /* If output port action already in the action list of one of the buckets, skip */
+                        if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
+                            addNew = false;
+                            break;
+                        }
+                    }
+                }
+            }
+            logger.debug("createOutputGroupInstructions: addNew {}", addNew);
+            if (addNew) {
+                /* the new output action is not in the bucket, add to bucket */
+                if (!buckets.getBucket().isEmpty()) {
+                    Bucket bucket = buckets.getBucket().get(0);
+                    List<Action> bucketActionList = new ArrayList<Action>();
+                    bucketActionList.addAll(bucket.getAction());
+                    /* set order for new action and add to action list */
+                    ab.setOrder(bucketActionList.size());
+                    ab.setKey(new ActionKey(bucketActionList.size()));
+                    bucketActionList.add(ab.build());
+
+                    /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
+                    BucketsBuilder bucketsBuilder = new BucketsBuilder();
+                    List<Bucket> bucketList = new ArrayList<Bucket>();
+                    BucketBuilder bucketBuilder = new BucketBuilder();
+                    bucketBuilder.setBucketId(new BucketId((long) 1));
+                    bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
+                    bucketBuilder.setAction(bucketActionList);
+                    bucketList.add(bucketBuilder.build());
+                    bucketsBuilder.setBucket(bucketList);
+                    groupBuilder.setBuckets(bucketsBuilder.build());
+                    logger.debug("createOutputGroupInstructions: bucketList {}", bucketList);
+                }
+            }
+        } else {
+            /* create group */
+            groupBuilder = new GroupBuilder();
+            groupBuilder.setGroupType(GroupTypes.GroupAll);
+            groupBuilder.setGroupId(new GroupId(groupId));
+            groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
+            groupBuilder.setGroupName("Output port group" + groupId);
+            groupBuilder.setBarrier(false);
+
+            BucketsBuilder bucketBuilder = new BucketsBuilder();
+            List<Bucket> bucketList = new ArrayList<Bucket>();
+            BucketBuilder bucket = new BucketBuilder();
+            bucket.setBucketId(new BucketId((long) 1));
+            bucket.setKey(new BucketKey(new BucketId((long) 1)));
+
+            /* put output action to the bucket */
+            List<Action> bucketActionList = new ArrayList<Action>();
+            /* set order for new action and add to action list */
+            ab.setOrder(bucketActionList.size());
+            ab.setKey(new ActionKey(bucketActionList.size()));
+            bucketActionList.add(ab.build());
+
+            bucket.setAction(bucketActionList);
+            bucketList.add(bucket.build());
+            bucketBuilder.setBucket(bucketList);
+            groupBuilder.setBuckets(bucketBuilder.build());
+
+            /* Add new group action */
+            GroupActionBuilder groupActionB = new GroupActionBuilder();
+            groupActionB.setGroupId(groupId);
+            groupActionB.setGroup("Output port group" + groupId);
+            ab = new ActionBuilder();
+            ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
+            ab.setOrder(actionList.size());
+            ab.setKey(new ActionKey(actionList.size()));
+            actionList.add(ab.build());
+
+            groupId++;
+        }
+        logger.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
+        logger.debug("createOutputGroupInstructions: actionList {}", actionList);
+
+        if (addNew) {
+            /* rewrite the group to group table */
+            writeGroup(groupBuilder, nodeBuilder);
+        }
 
         // Create an Apply Action
         ApplyActionsBuilder aab = new ApplyActionsBuilder();
@@ -1965,21 +3181,187 @@ public class OF13Provider implements NetworkProvider {
     }
 
     /**
-    * Remove Output Port from Instruction
-    *
-    * @param ib Map InstructionBuilder without any instructions
-    * @param dpidLong Long the datapath ID of a switch/node
-    * @param port Long representing a port on a switch/node
-    * @return ib InstructionBuilder Map with instructions
-    */
+     * add Output Port action to Instruction action list.
+     * This is use for flow with single output port actions.
+     * Flow with mutiple output port actions should use createOutputPortInstructions() method.
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    protected static InstructionBuilder addOutputPortInstructions(InstructionBuilder ib,
+                                                                     Long dpidLong, Long port ,
+                                                                     List<Instruction> instructions) {
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+        logger.debug("addOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
+
+        List<Action> actionList = new ArrayList<Action>();
+        ActionBuilder ab = new ActionBuilder();
+
+        List<Action> existingActions = null;
+        if (instructions != null) {
+            for (Instruction in : instructions) {
+                if (in.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                    actionList.addAll(existingActions);
+                }
+            }
+        }
+
+        /* Create output action for this port*/
+        OutputActionBuilder oab = new OutputActionBuilder();
+        oab.setOutputNodeConnector(ncid);
+        ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
+        ab.setOrder(actionList.size());
+        ab.setKey(new ActionKey(actionList.size()));
+        actionList.add(ab.build());
+
+        // Create an Apply Action
+        ApplyActionsBuilder aab = new ApplyActionsBuilder();
+        aab.setAction(actionList);
+        ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+
+        return ib;
+    }
+
+    /**
+     * Remove Output Port from action list in group bucket
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
+    protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
+                                Long dpidLong, Long port , List<Instruction> instructions) {
+
+        NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
+        logger.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
+
+        List<Action> actionList = new ArrayList<Action>();
+        ActionBuilder ab;
+
+        List<Action> existingActions = null;
+        if (instructions != null) {
+            for (Instruction in : instructions) {
+                if (in.getInstruction() instanceof ApplyActionsCase) {
+                    existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
+                    actionList.addAll(existingActions);
+                    break;
+                }
+            }
+        }
+
+        GroupBuilder groupBuilder = new GroupBuilder();
+        Group group = null;
+        boolean groupActionAdded = false;
+        /* Find the group action and get the group */
+        for (Action action : actionList) {
+            if (action.getAction() instanceof GroupActionCase) {
+                groupActionAdded = true;
+                GroupActionCase groupAction = (GroupActionCase) action.getAction();
+                Long id = groupAction.getGroupAction().getGroupId();
+                String groupName = groupAction.getGroupAction().getGroup();
+                GroupKey key = new GroupKey(new GroupId(id));
+
+                groupBuilder.setGroupId(new GroupId(id));
+                groupBuilder.setGroupName(groupName);
+                groupBuilder.setGroupType(GroupTypes.GroupAll);
+                groupBuilder.setKey(key);
+                group = getGroup(groupBuilder, nodeBuilder);
+                break;
+            }
+        }
+
+        if (groupActionAdded) {
+            /* modify the action bucket in group */
+            groupBuilder = new GroupBuilder(group);
+            Buckets buckets = groupBuilder.getBuckets();
+            List<Action> bucketActions = new ArrayList<Action>();
+            for (Bucket bucket : buckets.getBucket()) {
+                int index = 0;
+                boolean isPortDeleted = false;
+                bucketActions = bucket.getAction();
+                for (Action action : bucketActions) {
+                    if (action.getAction() instanceof OutputActionCase) {
+                        OutputActionCase opAction = (OutputActionCase)action.getAction();
+                        if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
+                            /* Find the output port in action list and remove */
+                            index = bucketActions.indexOf(action);
+                            bucketActions.remove(action);
+                            isPortDeleted = true;
+                            break;
+                        }
+                    }
+                }
+                if (isPortDeleted && !bucketActions.isEmpty()) {
+                    for (int i = index; i< bucketActions.size(); i++) {
+                        Action action = bucketActions.get(i);
+                        if (action.getOrder() != i) {
+                            /* Shift the action order */
+                            ab = new ActionBuilder();
+                            ab.setAction(action.getAction());
+                            ab.setOrder(i);
+                            ab.setKey(new ActionKey(i));
+                            Action actionNewOrder = ab.build();
+                            bucketActions.remove(action);
+                            bucketActions.add(i, actionNewOrder);
+                        }
+                    }
+
+                } else if (bucketActions.isEmpty()) {
+                    /* remove bucket with empty action list */
+                    buckets.getBucket().remove(bucket);
+                    break;
+                }
+            }
+            if (!buckets.getBucket().isEmpty()) {
+                /* rewrite the group to group table */
+                /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
+                BucketsBuilder bucketsBuilder = new BucketsBuilder();
+                List<Bucket> bucketList = new ArrayList<Bucket>();
+                BucketBuilder bucketBuilder = new BucketBuilder();
+                bucketBuilder.setBucketId(new BucketId((long) 1));
+                bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
+                bucketBuilder.setAction(bucketActions);
+                bucketList.add(bucketBuilder.build());
+                bucketsBuilder.setBucket(bucketList);
+                groupBuilder.setBuckets(bucketsBuilder.build());
+                logger.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
+
+                writeGroup(groupBuilder, nodeBuilder);
+                ApplyActionsBuilder aab = new ApplyActionsBuilder();
+                aab.setAction(actionList);
+                ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+                return false;
+            } else {
+                /* remove group with empty bucket. return true to delete flow */
+                removeGroup(groupBuilder, nodeBuilder);
+                return true;
+            }
+        } else {
+            /* no group for port list. flow can be removed */
+            return true;
+        }
+    }
+
+    /**
+     * Remove Output Port from Instruction
+     *
+     * @param ib       Map InstructionBuilder without any instructions
+     * @param dpidLong Long the datapath ID of a switch/node
+     * @param port     Long representing a port on a switch/node
+     * @return ib InstructionBuilder Map with instructions
+     */
     protected static boolean removeOutputPortFromInstructions(InstructionBuilder ib,
-                                   Long dpidLong, Long port , List<Instruction> instructions) {
+                                Long dpidLong, Long port , List<Instruction> instructions) {
 
         NodeConnectorId ncid = new NodeConnectorId("openflow:" + dpidLong + ":" + port);
         logger.debug("createOutputPortInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
 
         List<Action> actionList = new ArrayList<Action>();
-        ActionBuilder ab = new ActionBuilder();
+        ActionBuilder ab;
 
         List<Action> existingActions = null;
         if (instructions != null) {
@@ -1993,24 +3375,45 @@ public class OF13Provider implements NetworkProvider {
         }
 
         int numOutputPort = 0;
+        int index = 0;
+        boolean isPortDeleted = false;
         for (Action action : actionList) {
             if (action.getAction() instanceof OutputActionCase) {
                 numOutputPort++;
                 OutputActionCase opAction = (OutputActionCase)action.getAction();
                 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
                     /* Find the output port in action list and remove */
+                    index = actionList.indexOf(action);
                     actionList.remove(action);
+                    isPortDeleted = true;
                     numOutputPort--;
                     break;
                 }
             }
         }
 
+        if (isPortDeleted) {
+            for (int i = index; i< actionList.size(); i++) {
+                Action action = actionList.get(i);
+                if (action.getOrder() != i) {
+                    /* Shift the action order */
+                    ab = new ActionBuilder();
+                    ab.setAction(action.getAction());
+                    ab.setOrder(i);
+                    ab.setKey(new ActionKey(i));
+                    Action actionNewOrder = ab.build();
+                    actionList.remove(action);
+                    actionList.add(i, actionNewOrder);
+                }
+            }
+        }
+
         /* Put new action list in Apply Action instruction */
         if (numOutputPort > 0) {
             ApplyActionsBuilder aab = new ApplyActionsBuilder();
             aab.setAction(actionList);
             ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
+            logger.debug("createOutputPortInstructions() : applyAction {}", aab.build());
             return false;
         } else {
             /* if all output port are removed. Return true to indicate flow remove */
@@ -2019,7 +3422,7 @@ public class OF13Provider implements NetworkProvider {
     }
 
     /**
-     * Create Set Vlan ID Instruction
+     * Create Set Vlan ID Instruction - This includes push vlan action, and set field -> vlan vid action
      *
      * @param ib     Map InstructionBuilder without any instructions
      * @param vlanId Integer representing a VLAN ID Integer representing a VLAN ID
@@ -2030,9 +3433,19 @@ public class OF13Provider implements NetworkProvider {
         List<Action> actionList = new ArrayList<Action>();
         ActionBuilder ab = new ActionBuilder();
 
+        /* First we push vlan header */
+        PushVlanActionBuilder vlan = new PushVlanActionBuilder();
+        vlan.setEthernetType(new Integer(0x8100));
+        ab.setAction(new PushVlanActionCaseBuilder().setPushVlanAction(vlan.build()).build());
+        ab.setOrder(0);
+        actionList.add(ab.build());
+
+        /* Then we set vlan id value as vlanId */
         SetVlanIdActionBuilder vl = new SetVlanIdActionBuilder();
         vl.setVlanId(vlanId);
+        ab = new ActionBuilder();
         ab.setAction(new SetVlanIdActionCaseBuilder().setSetVlanIdAction(vl.build()).build());
+        ab.setOrder(1);
         actionList.add(ab.build());
         // Create an Apply Action
         ApplyActionsBuilder aab = new ApplyActionsBuilder();
@@ -2045,20 +3458,19 @@ public class OF13Provider implements NetworkProvider {
     }
 
     /**
-     * Create Set IPv4 Destination Instruction
+     * Create Pop Vlan Instruction - this remove vlan header
      *
      * @param ib Map InstructionBuilder without any instructions
      * @return ib Map InstructionBuilder with instructions
      */
-    protected static InstructionBuilder createStripVlanInstructions(InstructionBuilder ib) {
+    protected static InstructionBuilder createPopVlanInstructions(InstructionBuilder ib) {
 
-        StripVlanActionBuilder stripVlanActionBuilder = new StripVlanActionBuilder();
-        StripVlanAction vlanAction = stripVlanActionBuilder.build();
+        List<Action> actionList = new ArrayList<Action>();
         ActionBuilder ab = new ActionBuilder();
-        ab.setAction(new StripVlanActionCaseBuilder().setStripVlanAction(vlanAction).build());
 
-        // Add our drop action to a list
-        List<Action> actionList = new ArrayList<Action>();
+        PopVlanActionBuilder popVlanActionBuilder = new PopVlanActionBuilder();
+        ab.setAction(new PopVlanActionCaseBuilder().setPopVlanAction(popVlanActionBuilder.build()).build());
+        ab.setOrder(0);
         actionList.add(ab.build());
 
         // Create an Apply Action
@@ -2141,6 +3553,7 @@ public class OF13Provider implements NetworkProvider {
         DropAction dropAction = dab.build();
         ActionBuilder ab = new ActionBuilder();
         ab.setAction(new DropActionCaseBuilder().setDropAction(dropAction).build());
+        ab.setOrder(0);
 
         // Add our drop action to a list
         List<Action> actionList = new ArrayList<Action>();
@@ -2192,6 +3605,7 @@ public class OF13Provider implements NetworkProvider {
         tunnel.setTunnelId(tunnelId);
         setFieldBuilder.setTunnel(tunnel.build());
         ab.setAction(new SetFieldCaseBuilder().setSetField(setFieldBuilder.build()).build());
+        ab.setOrder(0);
         actionList.add(ab.build());
 
         ApplyActionsBuilder aab = new ApplyActionsBuilder();