[CORD-46] Create a broadcast group for each subnet

DONE
- Expose subnet-to-ports information from DeviceProperties and DeviceConfiguration
- Create subnetNextObjectiveStore to store <DeviceId, IpPrefix> to nextId mapping
- Implement broadcast NextObjective in SpringOpenTTP
      Use ALL group type to achieve broadcast

TODO (not in this submission)
- Push ARP table for a host when its location is learned
- Push default ARP table miss rule. Action = to the broadcast group

Change-Id: I2de28095e85289e75af3fc7a02c811b270b342ad
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
index 665ad66..895c446 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -23,7 +23,6 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.Link;
-import org.onosproject.net.MastershipRole;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -97,7 +96,7 @@
             log.debug("populateAllRoutingRules: populationStatus is STARTED");
 
             for (Device sw : srManager.deviceService.getDevices()) {
-                if (srManager.mastershipService.getLocalRole(sw.id()) != MastershipRole.MASTER) {
+                if (!srManager.mastershipService.isLocalMaster(sw.id())) {
                     log.debug("populateAllRoutingRules: skipping device {}...we are not master",
                               sw.id());
                     continue;
@@ -146,8 +145,7 @@
             // Take the snapshots of the links
             updatedEcmpSpgMap = new HashMap<>();
             for (Device sw : srManager.deviceService.getDevices()) {
-                if (srManager.mastershipService.
-                        getLocalRole(sw.id()) != MastershipRole.MASTER) {
+                if (!srManager.mastershipService.isLocalMaster(sw.id())) {
                     continue;
                 }
                 ECMPShortestPathGraph ecmpSpgUpdated =
@@ -273,8 +271,7 @@
         for (Device sw : srManager.deviceService.getDevices()) {
             log.debug("Computing the impacted routes for device {} due to link fail",
                       sw.id());
-            if (srManager.mastershipService.
-                    getLocalRole(sw.id()) != MastershipRole.MASTER) {
+            if (!srManager.mastershipService.isLocalMaster(sw.id())) {
                 continue;
             }
             ECMPShortestPathGraph ecmpSpg = currentEcmpSpgMap.get(sw.id());
@@ -320,8 +317,7 @@
         for (Device sw : srManager.deviceService.getDevices()) {
             log.debug("Computing the impacted routes for device {}",
                       sw.id());
-            if (srManager.mastershipService.
-                    getLocalRole(sw.id()) != MastershipRole.MASTER) {
+            if (!srManager.mastershipService.isLocalMaster(sw.id())) {
                 log.debug("No mastership for {} and skip route optimization",
                           sw.id());
                 continue;
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
index 97a662a..5c10eb6 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DeviceConfiguration.java
@@ -44,8 +44,6 @@
  * Segment Routing configuration component that reads the
  * segment routing related configuration from Network Configuration Manager
  * component and organizes in more accessible formats.
- *
- * TODO: Merge multiple Segment Routing configuration wrapper classes into one.
  */
 public class DeviceConfiguration implements DeviceProperties {
 
@@ -251,6 +249,26 @@
         return allSegmentIds;
     }
 
+    @Override
+    public Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId) {
+        Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>();
+
+        // Construct subnet-port mapping from port-subnet mapping
+        Map<PortNumber, Ip4Prefix> portSubnetMap =
+                this.deviceConfigMap.get(deviceId).subnets;
+        portSubnetMap.forEach((port, subnet) -> {
+            if (subnetPortMap.containsKey(subnet)) {
+                subnetPortMap.get(subnet).add(port);
+            } else {
+                ArrayList<PortNumber> ports = new ArrayList<>();
+                ports.add(port);
+                subnetPortMap.put(subnet, ports);
+            }
+        });
+
+        return subnetPortMap;
+    }
+
     /**
      * Returns the device identifier or data plane identifier (dpid)
      * of a segment router given its segment id.
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 9305541..a5ac678 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -22,13 +22,17 @@
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.apache.felix.scr.annotations.Service;
 import org.onlab.packet.Ethernet;
-import org.onlab.packet.IPv4;
-import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.VlanId;
+import org.onlab.packet.IPv4;
+import org.onlab.packet.Ip4Address;
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
 import org.onlab.util.KryoNamespace;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.event.Event;
+import org.onosproject.net.ConnectPoint;
 import org.onosproject.net.config.ConfigFactory;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigRegistry;
@@ -57,6 +61,7 @@
 import org.onosproject.net.packet.PacketProcessor;
 import org.onosproject.net.packet.PacketService;
 import org.onosproject.net.topology.TopologyService;
+import org.onosproject.segmentrouting.grouphandler.SubnetNextObjectiveStoreKey;
 import org.onosproject.store.service.EventuallyConsistentMap;
 import org.onosproject.store.service.EventuallyConsistentMapBuilder;
 import org.onosproject.store.service.StorageService;
@@ -136,6 +141,7 @@
     // Per device next objective ID store with (device id + neighbor set) as key
     private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
         Integer> nsNextObjStore = null;
+    private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
     private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
     private EventuallyConsistentMap<String, Policy> policyStore = null;
     // Per device, per-subnet assigned-vlans store, with (device id + subnet
@@ -180,6 +186,8 @@
 
         kryoBuilder = new KryoNamespace.Builder()
             .register(NeighborSetNextObjectiveStoreKey.class,
+                    SubnetNextObjectiveStoreKey.class,
+                    SubnetAssignedVidStoreKey.class,
                     NeighborSet.class,
                     DeviceId.class,
                     URI.class,
@@ -191,8 +199,11 @@
                     Policy.class,
                     TunnelPolicy.class,
                     Policy.Type.class,
-                    SubnetAssignedVidStoreKey.class,
-                    VlanId.class
+                    VlanId.class,
+                    Ip4Address.class,
+                    Ip4Prefix.class,
+                    IpAddress.Version.class,
+                    ConnectPoint.class
             );
 
         log.debug("Creating EC map nsnextobjectivestore");
@@ -206,6 +217,16 @@
                 .build();
         log.trace("Current size {}", nsNextObjStore.size());
 
+        log.debug("Creating EC map subnetnextobjectivestore");
+        EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
+                subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
+
+        subnetNextObjStore = subnetNextObjMapBuilder
+                .withName("subnetnextobjectivestore")
+                .withSerializer(kryoBuilder)
+                .withTimestampProvider((k, v) -> new WallClockTimestamp())
+                .build();
+
         EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
                 storageService.eventuallyConsistentMapBuilder();
 
@@ -399,6 +420,25 @@
         }
     }
 
+    /**
+     * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
+     * a new one is created and returned.
+     *
+     * @param deviceId Device ID
+     * @param prefix Subnet
+     * @return next objective ID
+     */
+    public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
+        if (groupHandlerMap.get(deviceId) != null) {
+            log.trace("getSubnetNextObjectiveId query in device {}", deviceId);
+            return groupHandlerMap
+                    .get(deviceId).getSubnetNextObjectiveId(prefix);
+        } else {
+            log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
+            return -1;
+        }
+    }
+
     private class InternalPacketProcessor implements PacketProcessor {
         @Override
         public void process(PacketContext context) {
@@ -559,15 +599,20 @@
         //Because in a multi-instance setup, instances can initiate
         //groups for any devices. Also the default TTP rules are needed
         //to be pushed before inserting any IP table entries for any device
-        DefaultGroupHandler dgh = DefaultGroupHandler.
+        DefaultGroupHandler groupHandler = DefaultGroupHandler.
                 createGroupHandler(device.id(),
                                    appId,
                                    deviceConfiguration,
                                    linkService,
                                    flowObjectiveService,
-                                   nsNextObjStore);
-        groupHandlerMap.put(device.id(), dgh);
+                                   nsNextObjStore,
+                                   subnetNextObjStore);
+        groupHandlerMap.put(device.id(), groupHandler);
         defaultRoutingHandler.populatePortAddressingRules(device.id());
+
+        if (mastershipService.isLocalMaster(device.id())) {
+            groupHandler.createGroupsFromSubnetConfig();
+        }
     }
 
     private void processPortRemoved(Device device, Port port) {
@@ -610,9 +655,14 @@
                         .createGroupHandler(device.id(), appId,
                                             deviceConfiguration, linkService,
                                             flowObjectiveService,
-                                            nsNextObjStore);
+                                            nsNextObjStore,
+                                            subnetNextObjStore);
                 groupHandlerMap.put(device.id(), groupHandler);
                 defaultRoutingHandler.populatePortAddressingRules(device.id());
+
+                if (mastershipService.isLocalMaster(device.id())) {
+                    groupHandler.createGroupsFromSubnetConfig();
+                }
             }
 
             defaultRoutingHandler.startPopulationProcess();
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
index c960adc..a5c1090 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultEdgeGroupHandler.java
@@ -52,9 +52,12 @@
                                   LinkService linkService,
                                   FlowObjectiveService flowObjService,
                                   EventuallyConsistentMap<
-                                  NeighborSetNextObjectiveStoreKey,
-                                  Integer> nsNextObjStore) {
-        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+                                          NeighborSetNextObjectiveStoreKey,
+                                          Integer> nsNextObjStore,
+                                  EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                          Integer> subnetNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService,
+              nsNextObjStore, subnetNextObjStore);
     }
 
     @Override
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index 9bbde2f..2606f48 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -25,10 +25,11 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Random;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.onlab.packet.Ip4Prefix;
+import org.onlab.packet.IpPrefix;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onlab.util.KryoNamespace;
@@ -74,7 +75,8 @@
     //        new HashMap<NeighborSet, Integer>();
     protected EventuallyConsistentMap<
         NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
-    protected Random rand = new Random();
+    protected EventuallyConsistentMap<
+            SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
 
     protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
             .register(URI.class).register(HashSet.class)
@@ -89,8 +91,10 @@
                                   LinkService linkService,
                                   FlowObjectiveService flowObjService,
                                   EventuallyConsistentMap<
-                                  NeighborSetNextObjectiveStoreKey,
-                                  Integer> nsNextObjStore) {
+                                          NeighborSetNextObjectiveStoreKey,
+                                          Integer> nsNextObjStore,
+                                  EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                          Integer> subnetNextObjStore) {
         this.deviceId = checkNotNull(deviceId);
         this.appId = checkNotNull(appId);
         this.deviceConfig = checkNotNull(config);
@@ -101,6 +105,7 @@
         nodeMacAddr = checkNotNull(config.getDeviceMac(deviceId));
         this.flowObjectiveService = flowObjService;
         this.nsNextObjStore = nsNextObjStore;
+        this.subnetNextObjStore = subnetNextObjStore;
 
         populateNeighborMaps();
     }
@@ -115,7 +120,8 @@
      * @param config interface to retrieve the device properties
      * @param linkService link service object
      * @param flowObjService flow objective service object
-     * @param nsNextObjStore next objective store map
+     * @param nsNextObjStore NeighborSet next objective store map
+     * @param subnetNextObjStore subnet next objective store map
      * @return default group handler type
      */
     public static DefaultGroupHandler createGroupHandler(DeviceId deviceId,
@@ -123,18 +129,23 @@
                                                          DeviceProperties config,
                                                          LinkService linkService,
                                                          FlowObjectiveService flowObjService,
-                                                         EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
-                                                                 Integer> nsNextObjStore) {
+                                                         EventuallyConsistentMap<
+                                                                 NeighborSetNextObjectiveStoreKey,
+                                                                 Integer> nsNextObjStore,
+                                                         EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                                                 Integer> subnetNextObjStore) {
         if (config.isEdgeDevice(deviceId)) {
             return new DefaultEdgeGroupHandler(deviceId, appId, config,
                                                linkService,
                                                flowObjService,
-                                               nsNextObjStore);
+                                               nsNextObjStore,
+                                               subnetNextObjStore);
         } else {
             return new DefaultTransitGroupHandler(deviceId, appId, config,
                                                   linkService,
                                                   flowObjService,
-                                                  nsNextObjStore);
+                                                  nsNextObjStore,
+                                                  subnetNextObjStore);
         }
     }
 
@@ -323,6 +334,44 @@
     }
 
     /**
+     * Returns the next objective associated with the neighborset.
+     * If there is no next objective for this neighborset, this API
+     * would create a next objective and return.
+     *
+     * @param prefix subnet information
+     * @return int if found or -1
+     */
+    public int getSubnetNextObjectiveId(IpPrefix prefix) {
+        Integer nextId = subnetNextObjStore.
+                get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
+        if (nextId == null) {
+            log.trace("getSubnetNextObjectiveId in device{}: Next objective id "
+                              + "not found for {} and creating", deviceId, prefix);
+            log.trace("getSubnetNextObjectiveId: subnetNextObjStore contents for device {}: {}",
+                      deviceId,
+                      subnetNextObjStore.entrySet()
+                              .stream()
+                              .filter((subnetStoreEntry) ->
+                                              (subnetStoreEntry.getKey().deviceId().equals(deviceId)))
+                              .collect(Collectors.toList()));
+            createGroupsFromSubnetConfig();
+            nextId = subnetNextObjStore.
+                    get(new SubnetNextObjectiveStoreKey(deviceId, prefix));
+            if (nextId == null) {
+                log.warn("subnetNextObjStore: unable to create next objective");
+                return -1;
+            } else {
+                log.debug("subnetNextObjStore in device{}: Next objective id {} "
+                                  + "created for {}", deviceId, nextId, prefix);
+            }
+        } else {
+            log.trace("subnetNextObjStore in device{}: Next objective id {} "
+                              + "found for {}", deviceId, nextId, prefix);
+        }
+        return nextId;
+    }
+
+    /**
      * Checks if the next objective ID (group) for the neighbor set exists or not.
      *
      * @param ns neighbor set to check
@@ -486,6 +535,35 @@
         }
     }
 
+    public void createGroupsFromSubnetConfig() {
+        Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
+                this.deviceConfig.getSubnetPortsMap(this.deviceId);
+
+        // Construct a broadcast group for each subnet
+        subnetPortMap.forEach((subnet, ports) -> {
+            int nextId = flowObjectiveService.allocateNextId();
+
+            NextObjective.Builder nextObjBuilder = DefaultNextObjective
+                    .builder().withId(nextId)
+                    .withType(NextObjective.Type.BROADCAST).fromApp(appId);
+
+            ports.forEach(port -> {
+                TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+                tBuilder.setOutput(port);
+                nextObjBuilder.addTreatment(tBuilder.build());
+            });
+
+            NextObjective nextObj = nextObjBuilder.add();
+            flowObjectiveService.next(deviceId, nextObj);
+            log.debug("createGroupFromSubnetConfig: Submited "
+                              + "next objective {} in device {}",
+                      nextId, deviceId);
+            SubnetNextObjectiveStoreKey key =
+                    new SubnetNextObjectiveStoreKey(deviceId, subnet);
+            subnetNextObjStore.put(key, nextId);
+        });
+    }
+
     public GroupKey getGroupKey(Object obj) {
         return new DefaultGroupKey(kryo.build().serialize(obj));
     }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
index 3cb73ab..b009e86 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultTransitGroupHandler.java
@@ -45,9 +45,12 @@
                                   LinkService linkService,
                                   FlowObjectiveService flowObjService,
                                   EventuallyConsistentMap<
-                                  NeighborSetNextObjectiveStoreKey,
-                                  Integer> nsNextObjStore) {
-        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+                                        NeighborSetNextObjectiveStoreKey,
+                                        Integer> nsNextObjStore,
+                                  EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                        Integer> subnetNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService,
+              nsNextObjStore, subnetNextObjStore);
     }
 
     @Override
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
index 497f525..d28d38d 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/DeviceProperties.java
@@ -16,9 +16,12 @@
 package org.onosproject.segmentrouting.grouphandler;
 
 import java.util.List;
+import java.util.Map;
 
+import org.onlab.packet.Ip4Prefix;
 import org.onlab.packet.MacAddress;
 import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
 
 /**
  * Mechanism through which group handler module retrieves
@@ -33,6 +36,7 @@
      * @return segment id of a device
      */
     int getSegmentId(DeviceId deviceId);
+
     /**
      * Returns the Mac address of a device to be used in group creation.
      *
@@ -40,6 +44,7 @@
      * @return mac address of a device
      */
     MacAddress getDeviceMac(DeviceId deviceId);
+
     /**
      * Indicates whether a device is edge device or transit/core device.
      *
@@ -47,6 +52,7 @@
      * @return boolean
      */
     boolean isEdgeDevice(DeviceId deviceId);
+
     /**
      * Returns all segment IDs to be considered in building auto
      *
@@ -54,4 +60,16 @@
      * @return list of segment IDs
      */
     List<Integer> getAllDeviceSegmentIds();
+
+    /**
+     * Returns subnet-to-ports mapping of given device.
+     *
+     * For each entry of the map
+     * Key: a subnet
+     * Value: a list of ports, which are bound to the subnet
+     *
+     * @param deviceId device identifier
+     * @return a map that contains all subnet-to-ports mapping of given device
+     */
+    Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId);
 }
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
index e7e8783..e47a662 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupHandler.java
@@ -54,7 +54,8 @@
      * @param config interface to retrieve the device properties
      * @param linkService link service object
      * @param flowObjService flow objective service object
-     * @param nsNextObjStore next objective store map
+     * @param nsNextObjStore NeighborSet next objective store map
+     * @param subnetNextObjStore subnet next objective store map
      */
     public PolicyGroupHandler(DeviceId deviceId,
                               ApplicationId appId,
@@ -62,8 +63,11 @@
                               LinkService linkService,
                               FlowObjectiveService flowObjService,
                               EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
-                                      Integer> nsNextObjStore) {
-        super(deviceId, appId, config, linkService, flowObjService, nsNextObjStore);
+                                      Integer> nsNextObjStore,
+                              EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
+                                      Integer> subnetNextObjStore) {
+        super(deviceId, appId, config, linkService, flowObjService,
+              nsNextObjStore, subnetNextObjStore);
     }
 
     public PolicyGroupIdentifier createPolicyGroupChain(String id,
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java
new file mode 100644
index 0000000..d6b16c7
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014-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.segmentrouting.grouphandler;
+
+import org.onlab.packet.IpPrefix;
+import org.onosproject.net.DeviceId;
+
+import java.util.Objects;
+
+/**
+ * Class definition of Key for Subnet to NextObjective store.
+ */
+public class SubnetNextObjectiveStoreKey {
+    private final DeviceId deviceId;
+    private final IpPrefix prefix;
+
+    public SubnetNextObjectiveStoreKey(DeviceId deviceId,
+                                       IpPrefix prefix) {
+        this.deviceId = deviceId;
+        this.prefix = prefix;
+    }
+
+    /**
+     * Gets device id in this SubnetNextObjectiveStoreKey.
+     *
+     * @return device id
+     */
+    public DeviceId deviceId() {
+        return this.deviceId;
+    }
+
+    /**
+     * Gets subnet information in this SubnetNextObjectiveStoreKey.
+     *
+     * @return subnet information
+     */
+    public IpPrefix prefix() {
+        return this.prefix;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof SubnetNextObjectiveStoreKey)) {
+            return false;
+        }
+        SubnetNextObjectiveStoreKey that =
+                (SubnetNextObjectiveStoreKey) o;
+        return (Objects.equals(this.deviceId, that.deviceId) &&
+                Objects.equals(this.prefix, that.prefix));
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(deviceId, prefix);
+    }
+
+    @Override
+    public String toString() {
+        return "Device: " + deviceId + " Subnet: " + prefix;
+    }
+}
diff --git a/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java b/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java
index 6efd3e7..9d942ee 100644
--- a/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java
+++ b/core/api/src/main/java/org/onosproject/net/group/DefaultGroupBucket.java
@@ -139,6 +139,20 @@
                                       watchGroup);
     }
 
+    /**
+     * Creates all group bucket.
+     *
+     * @param treatment traffic treatment associated with group bucket
+     * @return all group bucket object
+     */
+    public static GroupBucket createAllGroupBucket(TrafficTreatment treatment) {
+        return new DefaultGroupBucket(GroupDescription.Type.ALL,
+                                      treatment,
+                                      (short) -1,
+                                      null,
+                                      null);
+    }
+
     @Override
     public GroupDescription.Type type() {
         return this.type;
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
index 7ef72fa..31297ff 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
@@ -247,6 +247,7 @@
     private void addGroup(NextObjective nextObjective) {
         log.debug("addGroup with type{} for nextObjective id {}",
                   nextObjective.type(), nextObjective.id());
+        List<GroupBucket> buckets;
         switch (nextObjective.type()) {
             case SIMPLE:
                 log.debug("processing SIMPLE next objective");
@@ -274,7 +275,7 @@
                 break;
             case HASHED:
                 log.debug("processing HASHED next objective");
-                List<GroupBucket> buckets = nextObjective
+                buckets = nextObjective
                         .next()
                         .stream()
                         .map((treatment) -> DefaultGroupBucket
@@ -298,8 +299,32 @@
                 }
                 break;
             case BROADCAST:
+                log.debug("processing BROADCAST next objective");
+                buckets = nextObjective
+                        .next()
+                        .stream()
+                        .map((treatment) -> DefaultGroupBucket
+                                .createAllGroupBucket(treatment))
+                        .collect(Collectors.toList());
+                if (!buckets.isEmpty()) {
+                    final GroupKey key = new DefaultGroupKey(
+                            appKryo.serialize(nextObjective
+                                                      .id()));
+                    GroupDescription groupDescription = new DefaultGroupDescription(
+                            deviceId,
+                            GroupDescription.Type.ALL,
+                            new GroupBuckets(buckets),
+                            key,
+                            null,
+                            nextObjective.appId());
+                    log.debug("Creating BROADCAST group for next objective id {}",
+                              nextObjective.id());
+                    groupService.addGroup(groupDescription);
+                    pendingGroups.put(key, nextObjective);
+                }
+                break;
             case FAILOVER:
-                log.debug("BROADCAST and FAILOVER next objectives not supported");
+                log.debug("FAILOVER next objectives not supported");
                 fail(nextObjective, ObjectiveError.UNSUPPORTED);
                 log.warn("Unsupported next objective type {}", nextObjective.type());
                 break;
@@ -327,6 +352,8 @@
             bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
         } else if (group.type() == GroupDescription.Type.SELECT) {
             bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
+        } else if (group.type() == GroupDescription.Type.ALL) {
+            bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
         } else {
             log.warn("Unsupported Group type {}", group.type());
             return;
@@ -357,6 +384,8 @@
                 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
             } else if (group.type() == GroupDescription.Type.SELECT) {
                 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
+            } else if (group.type() == GroupDescription.Type.ALL) {
+                bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
             } else {
                 log.warn("Unsupported Group type {}", group.type());
                 return;
@@ -539,7 +568,7 @@
     protected List<FlowRule> processEthDstFilter(Criterion c,
                                        FilteringObjective filt,
                                        ApplicationId applicationId) {
-        List<FlowRule> rules = new ArrayList<FlowRule>();
+        List<FlowRule> rules = new ArrayList<>();
         EthCriterion e = (EthCriterion) c;
         TrafficSelector.Builder selectorIp = DefaultTrafficSelector
                 .builder();
@@ -577,7 +606,7 @@
     protected List<FlowRule> processVlanIdFilter(Criterion c,
                                                  FilteringObjective filt,
                                                  ApplicationId applicationId) {
-        List<FlowRule> rules = new ArrayList<FlowRule>();
+        List<FlowRule> rules = new ArrayList<>();
         VlanIdCriterion v = (VlanIdCriterion) c;
         log.debug("adding rule for VLAN: {}", v.vlanId());
         TrafficSelector.Builder selector = DefaultTrafficSelector
diff --git a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
index b9de7c0..d3a2378 100644
--- a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
+++ b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/GroupBucketEntryBuilder.java
@@ -115,6 +115,10 @@
                             DefaultGroupBucket.createFailoverGroupBucket(treatment,
                                     port, groupId);
                     break;
+                case ALL:
+                    groupBucket =
+                            DefaultGroupBucket.createAllGroupBucket(treatment);
+                    break;
                 default:
                     log.error("Unsupported Group type : {}", type);
             }
diff --git a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
index 8acf08e..5783c84 100644
--- a/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
+++ b/providers/openflow/group/src/main/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProvider.java
@@ -252,7 +252,7 @@
     private GroupDescription.Type getGroupType(OFGroupType type) {
         switch (type) {
             case ALL:
-                return  GroupDescription.Type.ALL;
+                return GroupDescription.Type.ALL;
             case INDIRECT:
                 return GroupDescription.Type.INDIRECT;
             case SELECT: