WIP: Started implementing static flows for corsa vanderweken pipeline.

Modified to not use Corsa driver by default.

Change-Id: If8df5769cf084346121d34bf4490f578e6b6f2d0
diff --git a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
index 317bf0d..62098b4 100644
--- a/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
+++ b/apps/bgprouter/src/main/java/org/onosproject/bgprouter/BgpRouter.java
@@ -23,6 +23,7 @@
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.DeviceId;
@@ -30,6 +31,8 @@
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
 import org.onosproject.net.flow.FlowRule;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleOperationsContext;
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
@@ -90,15 +93,19 @@
     private final Multiset<NextHop> nextHops = ConcurrentHashMultiset.create();
     private final Map<NextHop, NextHopGroupKey> groups = new HashMap<>();
 
-    private DeviceId deviceId = DeviceId.deviceId("of:00000000000000a1"); // TODO config
+    private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001"); // TODO config
 
     private TunnellingConnectivityManager connectivityManager;
 
+    private InternalTableHandler provisionStaticTables = new InternalTableHandler();
+
     @Activate
     protected void activate() {
         log.info("Bgp1Router started");
         appId = coreService.registerApplication(BGP_ROUTER_APP);
 
+        provisionStaticTables.provision(true);
+
         connectivityManager = new TunnellingConnectivityManager(appId,
                                                                 configService,
                                                                 packetService);
@@ -114,6 +121,7 @@
     protected void deactivate() {
         routingService.stop();
         connectivityManager.stop();
+        provisionStaticTables.provision(false);
 
         log.info("BgpRouter stopped");
     }
@@ -224,4 +232,303 @@
             BgpRouter.this.updateFibEntry(updates);
         }
     }
+
+    private class InternalTableHandler {
+
+        private static final int CONTROLLER_PRIORITY = 255;
+        private static final int DROP_PRIORITY = 0;
+
+
+        public void provision(boolean install) {
+
+            processTableZero(install);
+            processTableOne(install);
+            processTableTwo(install);
+            processTableThree(install);
+            processTableFive(install);
+            processTableSix(install);
+            processTableNine(install);
+
+        }
+
+        private void processTableZero(boolean install) {
+            TrafficSelector.Builder selector;
+            TrafficTreatment.Builder treatment;
+
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
+
+            selector.matchEthDst(MacAddress.BROADCAST);
+            treatment.transition(FlowRule.Type.VLAN_MPLS);
+
+            FlowRule rule = new DefaultFlowRule(deviceId, selector.build(),
+                                                treatment.build(), CONTROLLER_PRIORITY,
+                                                appId, 0, true);
+
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+
+            //Drop rule
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
+
+            treatment.drop();
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), DROP_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.VLAN_MPLS);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            flowService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    log.info("Provisioned default table for bgp router");
+                }
+
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    log.info("Failed to provision default table for bgp router");
+                }
+            }));
+
+        }
+
+        private void processTableOne(boolean install) {
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+            FlowRule rule;
+
+            selector.matchEthType(Ethernet.TYPE_IPV4);
+            treatment.transition(FlowRule.Type.VLAN);
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                  treatment.build(), CONTROLLER_PRIORITY,
+                                  appId, 0, true, FlowRule.Type.VLAN_MPLS);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
+
+            selector.matchEthType(Ethernet.TYPE_ARP);
+            treatment.transition(FlowRule.Type.VLAN);
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), CONTROLLER_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.VLAN_MPLS);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
+
+            selector.matchEthType(Ethernet.TYPE_VLAN);
+            treatment.transition(FlowRule.Type.VLAN);
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), CONTROLLER_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.VLAN_MPLS);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            //Drop rule
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
+
+            treatment.drop();
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), DROP_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.VLAN_MPLS);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            flowService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    log.info("Provisioned vlan/mpls table for bgp router");
+                }
+
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    log.info("Failed to provision vlan/mpls table for bgp router");
+                }
+            }));
+
+        }
+
+        private void processTableTwo(boolean install) {
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+            FlowRule rule;
+
+            //Drop rule
+
+            treatment.drop();
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), DROP_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.VLAN);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            flowService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    log.info("Provisioned vlan table for bgp router");
+                }
+
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    log.info("Failed to provision vlan table for bgp router");
+                }
+            }));
+        }
+
+
+
+        private void processTableThree(boolean install) {
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+            FlowRule rule;
+
+            selector.matchEthType(Ethernet.TYPE_ARP);
+            treatment.punt();
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), CONTROLLER_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.ETHER);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
+
+            selector.matchEthType(Ethernet.TYPE_IPV4);
+            treatment.transition(FlowRule.Type.COS);
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), CONTROLLER_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.ETHER);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            //Drop rule
+            selector = DefaultTrafficSelector.builder();
+            treatment = DefaultTrafficTreatment.builder();
+
+            treatment.drop();
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), DROP_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.VLAN_MPLS);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            flowService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    log.info("Provisioned ether table for bgp router");
+                }
+
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    log.info("Failed to provision ether table for bgp router");
+                }
+            }));
+
+
+        }
+
+        private void processTableFive(boolean install) {
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+            FlowRule rule;
+
+            treatment.transition(FlowRule.Type.IP);
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), DROP_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.COS);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            flowService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    log.info("Provisioned cos table for bgp router");
+                }
+
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    log.info("Failed to provision cos table for bgp router");
+                }
+            }));
+
+        }
+
+        private void processTableSix(boolean install) {
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+            FlowRule rule;
+
+            //Drop rule
+
+            treatment.drop();
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), DROP_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.IP);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            flowService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    log.info("Provisioned FIB table for bgp router");
+                }
+
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    log.info("Failed to provision FIB table for bgp router");
+                }
+            }));
+        }
+
+        private void processTableNine(boolean install) {
+            TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+            TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+            FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
+            FlowRule rule;
+
+            treatment.punt();
+
+            rule = new DefaultFlowRule(deviceId, selector.build(),
+                                       treatment.build(), CONTROLLER_PRIORITY,
+                                       appId, 0, true, FlowRule.Type.ACL);
+
+            ops = install ? ops.add(rule) : ops.remove(rule);
+
+            flowService.apply(ops.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    log.info("Provisioned Local table for bgp router");
+                }
+
+                @Override
+                public void onError(FlowRuleOperations ops) {
+                    log.info("Failed to provision Local table for bgp router");
+                }
+            }));
+        }
+
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index de5c328..a8880b0 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -134,6 +134,7 @@
                 case DROP:
                     drop = true;
                     break;
+                case TABLE:
                 case OUTPUT:
                     outputs.add(instruction);
                     break;
diff --git a/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java b/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
new file mode 100644
index 0000000..c914784
--- /dev/null
+++ b/core/store/dist/src/main/java/org/onosproject/store/group/impl/DistributedGroupStore.java
@@ -0,0 +1,555 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.store.group.impl;
+
+import static org.apache.commons.lang3.concurrent.ConcurrentUtils.createIfAbsentUnchecked;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.NewConcurrentHashMap;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.core.GroupId;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.group.DefaultGroup;
+import org.onosproject.net.group.DefaultGroupDescription;
+import org.onosproject.net.group.Group;
+import org.onosproject.net.group.Group.GroupState;
+import org.onosproject.net.group.GroupBucket;
+import org.onosproject.net.group.GroupBuckets;
+import org.onosproject.net.group.GroupDescription;
+import org.onosproject.net.group.GroupEvent;
+import org.onosproject.net.group.GroupEvent.Type;
+import org.onosproject.net.group.GroupKey;
+import org.onosproject.net.group.GroupOperation;
+import org.onosproject.net.group.GroupStore;
+import org.onosproject.net.group.GroupStoreDelegate;
+import org.onosproject.net.group.StoredGroupEntry;
+import org.onosproject.store.AbstractStore;
+import org.slf4j.Logger;
+
+import com.google.common.base.Function;
+import com.google.common.collect.FluentIterable;
+
+/**
+ * Manages inventory of group entries using trivial in-memory implementation.
+ */
+@Component(immediate = true)
+@Service
+public class DistributedGroupStore
+        extends AbstractStore<GroupEvent, GroupStoreDelegate>
+        implements GroupStore {
+
+    private final Logger log = getLogger(getClass());
+
+    private final int dummyId = 0xffffffff;
+    private final GroupId dummyGroupId = new DefaultGroupId(dummyId);
+
+    // inner Map is per device group table
+    private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>>
+            groupEntriesByKey = new ConcurrentHashMap<>();
+    private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, StoredGroupEntry>>
+            groupEntriesById = new ConcurrentHashMap<>();
+    private final ConcurrentMap<DeviceId, ConcurrentMap<GroupKey, StoredGroupEntry>>
+            pendingGroupEntriesByKey = new ConcurrentHashMap<>();
+    private final ConcurrentMap<DeviceId, ConcurrentMap<GroupId, Group>>
+            extraneousGroupEntriesById = new ConcurrentHashMap<>();
+
+    private final HashMap<DeviceId, Boolean> deviceAuditStatus =
+            new HashMap<DeviceId, Boolean>();
+
+    private final AtomicInteger groupIdGen = new AtomicInteger();
+
+    @Activate
+    public void activate() {
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        groupEntriesByKey.clear();
+        groupEntriesById.clear();
+        log.info("Stopped");
+    }
+
+    private static NewConcurrentHashMap<GroupKey, StoredGroupEntry>
+    lazyEmptyGroupKeyTable() {
+        return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded();
+    }
+
+    private static NewConcurrentHashMap<GroupId, StoredGroupEntry>
+    lazyEmptyGroupIdTable() {
+        return NewConcurrentHashMap.<GroupId, StoredGroupEntry>ifNeeded();
+    }
+
+    private static NewConcurrentHashMap<GroupKey, StoredGroupEntry>
+    lazyEmptyPendingGroupKeyTable() {
+        return NewConcurrentHashMap.<GroupKey, StoredGroupEntry>ifNeeded();
+    }
+
+    private static NewConcurrentHashMap<GroupId, Group>
+    lazyEmptyExtraneousGroupIdTable() {
+        return NewConcurrentHashMap.<GroupId, Group>ifNeeded();
+    }
+
+    /**
+     * Returns the group key table for specified device.
+     *
+     * @param deviceId identifier of the device
+     * @return Map representing group key table of given device.
+     */
+    private ConcurrentMap<GroupKey, StoredGroupEntry> getGroupKeyTable(DeviceId deviceId) {
+        return createIfAbsentUnchecked(groupEntriesByKey,
+                                       deviceId, lazyEmptyGroupKeyTable());
+    }
+
+    /**
+     * Returns the group id table for specified device.
+     *
+     * @param deviceId identifier of the device
+     * @return Map representing group key table of given device.
+     */
+    private ConcurrentMap<GroupId, StoredGroupEntry> getGroupIdTable(DeviceId deviceId) {
+        return createIfAbsentUnchecked(groupEntriesById,
+                                       deviceId, lazyEmptyGroupIdTable());
+    }
+
+    /**
+     * Returns the pending group key table for specified device.
+     *
+     * @param deviceId identifier of the device
+     * @return Map representing group key table of given device.
+     */
+    private ConcurrentMap<GroupKey, StoredGroupEntry>
+    getPendingGroupKeyTable(DeviceId deviceId) {
+        return createIfAbsentUnchecked(pendingGroupEntriesByKey,
+                                       deviceId, lazyEmptyPendingGroupKeyTable());
+    }
+
+    /**
+     * Returns the extraneous group id table for specified device.
+     *
+     * @param deviceId identifier of the device
+     * @return Map representing group key table of given device.
+     */
+    private ConcurrentMap<GroupId, Group>
+    getExtraneousGroupIdTable(DeviceId deviceId) {
+        return createIfAbsentUnchecked(extraneousGroupEntriesById,
+                                       deviceId,
+                                       lazyEmptyExtraneousGroupIdTable());
+    }
+
+    /**
+     * Returns the number of groups for the specified device in the store.
+     *
+     * @return number of groups for the specified device
+     */
+    @Override
+    public int getGroupCount(DeviceId deviceId) {
+        return (groupEntriesByKey.get(deviceId) != null) ?
+                groupEntriesByKey.get(deviceId).size() : 0;
+    }
+
+    /**
+     * Returns the groups associated with a device.
+     *
+     * @param deviceId the device ID
+     *
+     * @return the group entries
+     */
+    @Override
+    public Iterable<Group> getGroups(DeviceId deviceId) {
+        // flatten and make iterator unmodifiable
+        return FluentIterable.from(getGroupKeyTable(deviceId).values())
+                .transform(
+                        new Function<StoredGroupEntry, Group>() {
+
+                            @Override
+                            public Group apply(
+                                    StoredGroupEntry input) {
+                                return input;
+                            }
+                        });
+    }
+
+    /**
+     * Returns the stored group entry.
+     *
+     * @param deviceId the device ID
+     * @param appCookie the group key
+     *
+     * @return a group associated with the key
+     */
+    @Override
+    public Group getGroup(DeviceId deviceId, GroupKey appCookie) {
+        return (groupEntriesByKey.get(deviceId) != null) ?
+                groupEntriesByKey.get(deviceId).get(appCookie) :
+                null;
+    }
+
+    private int getFreeGroupIdValue(DeviceId deviceId) {
+        int freeId = groupIdGen.incrementAndGet();
+
+        while (true) {
+            Group existing = (
+                    groupEntriesById.get(deviceId) != null) ?
+                    groupEntriesById.get(deviceId).get(new DefaultGroupId(freeId)) :
+                    null;
+            if (existing == null) {
+                existing = (
+                        extraneousGroupEntriesById.get(deviceId) != null) ?
+                        extraneousGroupEntriesById.get(deviceId).
+                                get(new DefaultGroupId(freeId)) :
+                        null;
+            }
+            if (existing != null) {
+                freeId = groupIdGen.incrementAndGet();
+            } else {
+                break;
+            }
+        }
+        return freeId;
+    }
+
+    /**
+     * Stores a new group entry using the information from group description.
+     *
+     * @param groupDesc group description to be used to create group entry
+     */
+    @Override
+    public void storeGroupDescription(GroupDescription groupDesc) {
+        // Check if a group is existing with the same key
+        if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) {
+            return;
+        }
+
+        if (deviceAuditStatus.get(groupDesc.deviceId()) == null) {
+            // Device group audit has not completed yet
+            // Add this group description to pending group key table
+            // Create a group entry object with Dummy Group ID
+            StoredGroupEntry group = new DefaultGroup(dummyGroupId, groupDesc);
+            group.setState(GroupState.WAITING_AUDIT_COMPLETE);
+            ConcurrentMap<GroupKey, StoredGroupEntry> pendingKeyTable =
+                    getPendingGroupKeyTable(groupDesc.deviceId());
+            pendingKeyTable.put(groupDesc.appCookie(), group);
+            return;
+        }
+
+        storeGroupDescriptionInternal(groupDesc);
+    }
+
+    private void storeGroupDescriptionInternal(GroupDescription groupDesc) {
+        // Check if a group is existing with the same key
+        if (getGroup(groupDesc.deviceId(), groupDesc.appCookie()) != null) {
+            return;
+        }
+
+        // Get a new group identifier
+        GroupId id = new DefaultGroupId(getFreeGroupIdValue(groupDesc.deviceId()));
+        // Create a group entry object
+        StoredGroupEntry group = new DefaultGroup(id, groupDesc);
+        // Insert the newly created group entry into concurrent key and id maps
+        ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
+                getGroupKeyTable(groupDesc.deviceId());
+        keyTable.put(groupDesc.appCookie(), group);
+        ConcurrentMap<GroupId, StoredGroupEntry> idTable =
+                getGroupIdTable(groupDesc.deviceId());
+        idTable.put(id, group);
+        notifyDelegate(new GroupEvent(GroupEvent.Type.GROUP_ADD_REQUESTED,
+                                      group));
+    }
+
+    /**
+     * Updates the existing group entry with the information
+     * from group description.
+     *
+     * @param deviceId the device ID
+     * @param oldAppCookie the current group key
+     * @param type update type
+     * @param newBuckets group buckets for updates
+     * @param newAppCookie optional new group key
+     */
+    @Override
+    public void updateGroupDescription(DeviceId deviceId,
+                                       GroupKey oldAppCookie,
+                                       UpdateType type,
+                                       GroupBuckets newBuckets,
+                                       GroupKey newAppCookie) {
+        // Check if a group is existing with the provided key
+        Group oldGroup = getGroup(deviceId, oldAppCookie);
+        if (oldGroup == null) {
+            return;
+        }
+
+        List<GroupBucket> newBucketList = getUpdatedBucketList(oldGroup,
+                                                               type,
+                                                               newBuckets);
+        if (newBucketList != null) {
+            // Create a new group object from the old group
+            GroupBuckets updatedBuckets = new GroupBuckets(newBucketList);
+            GroupKey newCookie = (newAppCookie != null) ? newAppCookie : oldAppCookie;
+            GroupDescription updatedGroupDesc = new DefaultGroupDescription(
+                    oldGroup.deviceId(),
+                    oldGroup.type(),
+                    updatedBuckets,
+                    newCookie,
+                    oldGroup.appId());
+            StoredGroupEntry newGroup = new DefaultGroup(oldGroup.id(),
+                                                         updatedGroupDesc);
+            newGroup.setState(GroupState.PENDING_UPDATE);
+            newGroup.setLife(oldGroup.life());
+            newGroup.setPackets(oldGroup.packets());
+            newGroup.setBytes(oldGroup.bytes());
+            // Remove the old entry from maps and add new entry using new key
+            ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
+                    getGroupKeyTable(oldGroup.deviceId());
+            ConcurrentMap<GroupId, StoredGroupEntry> idTable =
+                    getGroupIdTable(oldGroup.deviceId());
+            keyTable.remove(oldGroup.appCookie());
+            idTable.remove(oldGroup.id());
+            keyTable.put(newGroup.appCookie(), newGroup);
+            idTable.put(newGroup.id(), newGroup);
+            notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_REQUESTED, newGroup));
+        }
+    }
+
+    private List<GroupBucket> getUpdatedBucketList(Group oldGroup,
+                                                   UpdateType type,
+                                                   GroupBuckets buckets) {
+        GroupBuckets oldBuckets = oldGroup.buckets();
+        List<GroupBucket> newBucketList = new ArrayList<GroupBucket>(
+                oldBuckets.buckets());
+        boolean groupDescUpdated = false;
+
+        if (type == UpdateType.ADD) {
+            // Check if the any of the new buckets are part of
+            // the old bucket list
+            for (GroupBucket addBucket:buckets.buckets()) {
+                if (!newBucketList.contains(addBucket)) {
+                    newBucketList.add(addBucket);
+                    groupDescUpdated = true;
+                }
+            }
+        } else if (type == UpdateType.REMOVE) {
+            // Check if the to be removed buckets are part of the
+            // old bucket list
+            for (GroupBucket removeBucket:buckets.buckets()) {
+                if (newBucketList.contains(removeBucket)) {
+                    newBucketList.remove(removeBucket);
+                    groupDescUpdated = true;
+                }
+            }
+        }
+
+        if (groupDescUpdated) {
+            return newBucketList;
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Triggers deleting the existing group entry.
+     *
+     * @param deviceId the device ID
+     * @param appCookie the group key
+     */
+    @Override
+    public void deleteGroupDescription(DeviceId deviceId,
+                                       GroupKey appCookie) {
+        // Check if a group is existing with the provided key
+        StoredGroupEntry existing = (groupEntriesByKey.get(deviceId) != null) ?
+                groupEntriesByKey.get(deviceId).get(appCookie) :
+                null;
+        if (existing == null) {
+            return;
+        }
+
+        synchronized (existing) {
+            existing.setState(GroupState.PENDING_DELETE);
+        }
+        notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, existing));
+    }
+
+    /**
+     * Stores a new group entry, or updates an existing entry.
+     *
+     * @param group group entry
+     */
+    @Override
+    public void addOrUpdateGroupEntry(Group group) {
+        // check if this new entry is an update to an existing entry
+        StoredGroupEntry existing = (groupEntriesById.get(
+                group.deviceId()) != null) ?
+                groupEntriesById.get(group.deviceId()).get(group.id()) :
+                null;
+        GroupEvent event = null;
+
+        if (existing != null) {
+            synchronized (existing) {
+                existing.setLife(group.life());
+                existing.setPackets(group.packets());
+                existing.setBytes(group.bytes());
+                if (existing.state() == GroupState.PENDING_ADD) {
+                    existing.setState(GroupState.ADDED);
+                    event = new GroupEvent(Type.GROUP_ADDED, existing);
+                } else {
+                    if (existing.state() == GroupState.PENDING_UPDATE) {
+                        existing.setState(GroupState.PENDING_UPDATE);
+                    }
+                    event = new GroupEvent(Type.GROUP_UPDATED, existing);
+                }
+            }
+        }
+
+        if (event != null) {
+            notifyDelegate(event);
+        }
+    }
+
+    /**
+     * Removes the group entry from store.
+     *
+     * @param group group entry
+     */
+    @Override
+    public void removeGroupEntry(Group group) {
+        StoredGroupEntry existing = (groupEntriesById.get(
+                group.deviceId()) != null) ?
+                groupEntriesById.get(group.deviceId()).get(group.id()) :
+                null;
+
+        if (existing != null) {
+            ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
+                    getGroupKeyTable(existing.deviceId());
+            ConcurrentMap<GroupId, StoredGroupEntry> idTable =
+                    getGroupIdTable(existing.deviceId());
+            idTable.remove(existing.id());
+            keyTable.remove(existing.appCookie());
+            notifyDelegate(new GroupEvent(Type.GROUP_REMOVED, existing));
+        }
+    }
+
+    @Override
+    public void deviceInitialAuditCompleted(DeviceId deviceId,
+                                            boolean completed) {
+        synchronized (deviceAuditStatus) {
+            if (completed) {
+                log.debug("deviceInitialAuditCompleted: AUDIT "
+                                  + "completed for device {}", deviceId);
+                deviceAuditStatus.put(deviceId, true);
+                // Execute all pending group requests
+                ConcurrentMap<GroupKey, StoredGroupEntry> pendingGroupRequests =
+                        getPendingGroupKeyTable(deviceId);
+                for (Group group:pendingGroupRequests.values()) {
+                    GroupDescription tmp = new DefaultGroupDescription(
+                            group.deviceId(),
+                            group.type(),
+                            group.buckets(),
+                            group.appCookie(),
+                            group.appId());
+                    storeGroupDescriptionInternal(tmp);
+                }
+                getPendingGroupKeyTable(deviceId).clear();
+            } else {
+                if (deviceAuditStatus.get(deviceId)) {
+                    log.debug("deviceInitialAuditCompleted: Clearing AUDIT "
+                                      + "status for device {}", deviceId);
+                    deviceAuditStatus.put(deviceId, false);
+                }
+            }
+        }
+    }
+
+    @Override
+    public boolean deviceInitialAuditStatus(DeviceId deviceId) {
+        synchronized (deviceAuditStatus) {
+            return (deviceAuditStatus.get(deviceId) != null)
+                    ? deviceAuditStatus.get(deviceId) : false;
+        }
+    }
+
+    @Override
+    public void groupOperationFailed(DeviceId deviceId, GroupOperation operation) {
+
+        StoredGroupEntry existing = (groupEntriesById.get(
+                deviceId) != null) ?
+                groupEntriesById.get(deviceId).get(operation.groupId()) :
+                null;
+
+        if (existing == null) {
+            log.warn("No group entry with ID {} found ", operation.groupId());
+            return;
+        }
+
+        switch (operation.opType()) {
+            case ADD:
+                notifyDelegate(new GroupEvent(Type.GROUP_ADD_FAILED, existing));
+                break;
+            case MODIFY:
+                notifyDelegate(new GroupEvent(Type.GROUP_UPDATE_FAILED, existing));
+                break;
+            case DELETE:
+                notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_FAILED, existing));
+                break;
+            default:
+                log.warn("Unknown group operation type {}", operation.opType());
+        }
+
+        ConcurrentMap<GroupKey, StoredGroupEntry> keyTable =
+                getGroupKeyTable(existing.deviceId());
+        ConcurrentMap<GroupId, StoredGroupEntry> idTable =
+                getGroupIdTable(existing.deviceId());
+        idTable.remove(existing.id());
+        keyTable.remove(existing.appCookie());
+    }
+
+    @Override
+    public void addOrUpdateExtraneousGroupEntry(Group group) {
+        ConcurrentMap<GroupId, Group> extraneousIdTable =
+                getExtraneousGroupIdTable(group.deviceId());
+        extraneousIdTable.put(group.id(), group);
+        // Check the reference counter
+        if (group.referenceCount() == 0) {
+            notifyDelegate(new GroupEvent(Type.GROUP_REMOVE_REQUESTED, group));
+        }
+    }
+
+    @Override
+    public void removeExtraneousGroupEntry(Group group) {
+        ConcurrentMap<GroupId, Group> extraneousIdTable =
+                getExtraneousGroupIdTable(group.deviceId());
+        extraneousIdTable.remove(group.id());
+    }
+
+    @Override
+    public Iterable<Group> getExtraneousGroups(DeviceId deviceId) {
+        // flatten and make iterator unmodifiable
+        return FluentIterable.from(
+                getExtraneousGroupIdTable(deviceId).values());
+    }
+
+
+}
diff --git a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFCorsaSwitchDriver.java b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFCorsaSwitchDriver.java
index f07725f..62eceda 100644
--- a/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFCorsaSwitchDriver.java
+++ b/openflow/drivers/src/main/java/org/onosproject/openflow/drivers/OFCorsaSwitchDriver.java
@@ -17,7 +17,6 @@
 
 import com.google.common.collect.Lists;
 import org.onosproject.openflow.controller.Dpid;
-import org.onosproject.openflow.controller.RoleState;
 import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFFlowMod;
@@ -43,8 +42,6 @@
     private static final int FIB_TABLE = 6;
     private static final int LOCAL_TABLE = 9;
 
-
-
     OFCorsaSwitchDriver(Dpid dpid, OFDescStatsReply desc) {
         super(dpid);
 
@@ -58,10 +55,7 @@
 
     @Override
     public void write(List<OFMessage> msgs) {
-        if (role == RoleState.MASTER) {
             channel.write(msgs);
-        }
-
     }
 
     @Override
@@ -152,7 +146,9 @@
                 default:
                     log.warn("Unknown table type: {}", type);
             }
+            builder.setInstructions(newInstructions);
             this.write(builder.build());
+            log.info("Installed {}", builder.build());
         } else {
             this.write(msg);
         }
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
index 3e9bdfc..584f448 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer10.java
@@ -55,7 +55,7 @@
  */
 public class FlowModBuilderVer10 extends FlowModBuilder {
 
-    private static final Logger log = LoggerFactory.getLogger(FlowModBuilderVer10.class);
+    private final Logger log = LoggerFactory.getLogger(getClass());
     private static final int OFPCML_NO_BUFFER = 0xffff;
 
     private final TrafficTreatment treatment;
diff --git a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
index d87103d..b1848f2 100644
--- a/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
+++ b/providers/openflow/flow/src/main/java/org/onosproject/provider/of/flow/impl/FlowModBuilderVer13.java
@@ -74,7 +74,7 @@
  */
 public class FlowModBuilderVer13 extends FlowModBuilder {
 
-    private static final Logger log = LoggerFactory.getLogger(FlowModBuilderVer10.class);
+    private final Logger log = LoggerFactory.getLogger(getClass());
     private static final int OFPCML_NO_BUFFER = 0xffff;
 
     private final TrafficTreatment treatment;
@@ -118,6 +118,7 @@
                 .setMatch(match)
                 .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
                 .setPriority(flowRule().priority())
+                .setTableId(TableId.of(flowRule().type().ordinal()))
                 .build();
 
         return fm;
@@ -144,6 +145,7 @@
                 .setMatch(match)
                 .setFlags(Collections.singleton(OFFlowModFlags.SEND_FLOW_REM))
                 .setPriority(flowRule().priority())
+                .setTableId(TableId.of(flowRule().type().ordinal()))
                 .build();
 
         return fm;
@@ -219,6 +221,9 @@
                             .setGroup(OFGroup.of(group.groupId().id()));
                     actions.add(groupBuilder.build());
                     break;
+                case TABLE:
+                    //FIXME: should not occur here.
+                    break;
                 default:
                     log.warn("Instruction type {} not yet implemented.", i.type());
             }
diff --git a/utils/misc/src/main/java/org/onlab/packet/Ethernet.java b/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
index 2a69ffa..b2a01b9 100644
--- a/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
+++ b/utils/misc/src/main/java/org/onlab/packet/Ethernet.java
@@ -36,6 +36,7 @@
     public static final short TYPE_IPV4 = (short) 0x0800;
     public static final short TYPE_IPV6 = (short) 0x86dd;
     public static final short TYPE_LLDP = (short) 0x88cc;
+    public static final short TYPE_VLAN = (short) 0x8100;
     public static final short TYPE_BSN = (short) 0x8942;
     public static final short VLAN_UNTAGGED = (short) 0xffff;
     public static final short MPLS_UNICAST = (short) 0x8847;
@@ -284,7 +285,7 @@
         bb.put(this.destinationMACAddress.toBytes());
         bb.put(this.sourceMACAddress.toBytes());
         if (this.vlanID != Ethernet.VLAN_UNTAGGED) {
-            bb.putShort((short) 0x8100);
+            bb.putShort(TYPE_VLAN);
             bb.putShort((short) (this.priorityCode << 13 | this.vlanID & 0x0fff));
         }
         bb.putShort(this.etherType);
@@ -319,7 +320,7 @@
         this.sourceMACAddress = MacAddress.valueOf(srcAddr);
 
         short ethType = bb.getShort();
-        if (ethType == (short) 0x8100) {
+        if (ethType == TYPE_VLAN) {
             final short tci = bb.getShort();
             this.priorityCode = (byte) (tci >> 13 & 0x07);
             this.vlanID = (short) (tci & 0x0fff);