[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/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));
}