CORD-81 Support for editing buckets of ALL groups, both L2Flood and
L3Multicast in the OF-DPA driver. Additionally changed SR app to
react to edge ports going up/down by sending flood group edit calls.
Change-Id: I6d7749f579d3d1d800e6ca8ce2316bd0e3f6136b
diff --git a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 81fb220..ca41a0f 100644
--- a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -667,7 +667,8 @@
public void event(DeviceEvent event) {
switch (event.type()) {
case DEVICE_ADDED:
- case PORT_REMOVED:
+ case PORT_UPDATED:
+ case PORT_ADDED:
case DEVICE_UPDATED:
case DEVICE_AVAILABILITY_CHANGED:
log.debug("Event {} received from Device Service", event.type());
@@ -740,20 +741,21 @@
event.type(), ((Device) event.subject()).id());
processDeviceRemoved((Device) event.subject());
}
- } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
- processPortRemoved((Device) event.subject(),
- ((DeviceEvent) event).port());
- } else if (event.type() == DeviceEvent.Type.PORT_ADDED ||
- event.type() == DeviceEvent.Type.PORT_UPDATED) {
- log.info("** PORT ADDED OR UPDATED {}/{} -> {}",
+ } else if (event.type() == DeviceEvent.Type.PORT_ADDED) {
+ // XXX typically these calls come when device is added
+ // so port filtering rules are handled there, and it
+ // represents all ports on the device, enabled or not.
+ log.debug("** PORT ADDED {}/{} -> {}",
event.subject(),
((DeviceEvent) event).port(),
event.type());
- /* XXX create method for single port filtering rules
- if (defaultRoutingHandler != null) {
- defaultRoutingHandler.populatePortAddressingRules(
- ((Device) event.subject()).id());
- }*/
+ } else if (event.type() == DeviceEvent.Type.PORT_UPDATED) {
+ log.info("** PORT UPDATED {}/{} -> {}",
+ event.subject(),
+ ((DeviceEvent) event).port(),
+ event.type());
+ processPortUpdated(((Device) event.subject()),
+ ((DeviceEvent) event).port());
} else {
log.warn("Unhandled event type: {}", event.type());
}
@@ -898,12 +900,51 @@
xConnectHandler.removeDevice(device.id());
}
- private void processPortRemoved(Device device, Port port) {
- log.info("Port {} was removed", port.toString());
+ private void processPortUpdated(Device device, Port port) {
+ if (deviceConfiguration == null || !deviceConfiguration.isConfigured(device.id())) {
+ log.warn("Device configuration uploading. Not handling port event for"
+ + "dev: {} port: {}", device.id(), port.number());
+ return;
+ }
+ /* XXX create method for single port filtering rules which are needed
+ for both switch-to-switch ports and edge ports
+ if (defaultRoutingHandler != null) {
+ defaultRoutingHandler.populatePortAddressingRules(
+ ((Device) event.subject()).id());
+ }*/
+
+ // portUpdated calls are for ports that have gone down or up. For switch
+ // to switch ports, link-events should take care of any re-routing or
+ // group editing necessary for port up/down. Here we only process edge ports
+ // that are already configured.
+ Ip4Prefix configuredSubnet = deviceConfiguration.getPortSubnet(device.id(),
+ port.number());
+ if (configuredSubnet == null) {
+ log.debug("Not handling port updated event for unconfigured port "
+ + "dev/port: {}/{}", device.id(), port.number());
+ return;
+ }
+ processEdgePort(device, port, configuredSubnet);
+ }
+
+ private void processEdgePort(Device device, Port port, Ip4Prefix subnet) {
+ boolean portUp = port.isEnabled();
+ if (portUp) {
+ log.info("Device:EdgePort {}:{} is enabled in subnet: {}", device.id(),
+ port.number(), subnet);
+ } else {
+ log.info("Device:EdgePort {}:{} is disabled in subnet: {}", device.id(),
+ port.number(), subnet);
+ }
+
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
if (groupHandler != null) {
- groupHandler.portDown(port.number(),
+ groupHandler.processEdgePort(port.number(), subnet, portUp,
mastershipService.isLocalMaster(device.id()));
+ } else {
+ log.warn("Group handler not found for dev:{}. Not handling edge port"
+ + " {} event for port:{}", device.id(),
+ (portUp) ? "UP" : "DOWN", port.number());
}
}
diff --git a/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java b/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
index c378541..52606cf 100644
--- a/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
+++ b/src/main/java/org/onosproject/segmentrouting/grouphandler/DefaultGroupHandler.java
@@ -78,13 +78,16 @@
// that connect to the same neighbor
protected ConcurrentHashMap<DeviceId, Set<PortNumber>> devicePortMap =
new ConcurrentHashMap<>();
- //local store for ports on this device connected to neighbor-device-id
+ // local store for ports on this device connected to neighbor-device-id
protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
new ConcurrentHashMap<>();
+ // distributed store for (device+neighborset) mapped to next-id
protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
nsNextObjStore = null;
+ // distributed store for (device+subnet-ip-prefix) mapped to next-id
protected EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
subnetNextObjStore = null;
+ // distributed store for (device+port+treatment) mapped to next-id
protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
portNextObjStore = null;
private SegmentRoutingManager srManager;
@@ -271,7 +274,8 @@
}
/**
- * Performs group recovery procedures when a port goes down on this device.
+ * Performs hash group recovery procedures when a switch-to-switch
+ * port goes down on this device.
*
* @param port port number that has gone down
* @param isMaster true if local instance is the master
@@ -350,6 +354,70 @@
}
/**
+ * Adds or removes a port that has been configured with a subnet to a broadcast group
+ * for bridging. Note that this does not create the broadcast group itself.
+ *
+ * @param port the port on this device that needs to be added/removed to a bcast group
+ * @param subnet the subnet corresponding to the broadcast group
+ * @param portUp true if port is enabled, false if disabled
+ * @param isMaster true if local instance is the master
+ */
+ public void processEdgePort(PortNumber port, Ip4Prefix subnet,
+ boolean portUp, boolean isMaster) {
+ if (!isMaster) {
+ return;
+ }
+ //get the next id for the subnet and edit it.
+ Integer nextId = getSubnetNextObjectiveId(subnet);
+ if (nextId == -1) {
+ if (portUp) {
+ log.debug("**Creating flooding group for first port enabled in"
+ + " subnet {} on dev {} port {}", subnet, deviceId, port);
+ createBcastGroupFromSubnet(subnet, Collections.singletonList(port));
+ } else {
+ log.warn("Could not find flooding group for subnet {} on dev:{} when"
+ + " removing port:{}", subnet, deviceId, port);
+ }
+ return;
+ }
+
+ log.info("**port{} in device {}: {} Bucket with Port {} to"
+ + " next-id {}", (portUp) ? "UP" : "DOWN", deviceId,
+ (portUp) ? "Adding" : "Removing",
+ port, nextId);
+ // Create the bucket to be added or removed
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.popVlan();
+ tBuilder.setOutput(port);
+
+ VlanId assignedVlanId =
+ srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
+ TrafficSelector metadata =
+ DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
+
+ NextObjective.Builder nextObjBuilder = DefaultNextObjective
+ .builder().withId(nextId)
+ .withType(NextObjective.Type.BROADCAST).fromApp(appId)
+ .addTreatment(tBuilder.build())
+ .withMeta(metadata);
+
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective) -> log.debug("port {} successfully {} NextObj {} on {}",
+ port, (portUp) ? "addedTo" : "removedFrom",
+ nextId, deviceId),
+ (objective, error) ->
+ log.warn("port {} failed to {} NextObj {} on {}: {}",
+ port, (portUp) ? "addTo" : "removeFrom",
+ nextId, deviceId, error));
+
+ NextObjective nextObj = (portUp) ? nextObjBuilder.addToExisting(context)
+ : nextObjBuilder.removeFromExisting(context);
+ log.debug("edgePort processed: Submited next objective {} in device {}",
+ nextId, deviceId);
+ flowObjectiveService.next(deviceId, nextObj);
+ }
+
+ /**
* Returns the next objective of type hashed associated with the neighborset.
* If there is no next objective for this neighborset, this method
* would create a next objective and return. Optionally metadata can be
@@ -394,7 +462,8 @@
* Returns the next objective of type broadcast associated with the subnet,
* or -1 if no such objective exists. Note that this method does NOT create
* the next objective as a side-effect. It is expected that is objective is
- * created at startup from network configuration.
+ * created at startup from network configuration. Typically this is used
+ * for L2 flooding within the subnet configured on the switch.
*
* @param prefix subnet information
* @return int if found or -1
@@ -411,7 +480,9 @@
* device, given the treatment. Different treatments to the same port result
* in different next objectives. If no such objective exists, this method
* creates one and returns the id. Optionally metadata can be passed in for
- * the creation of the objective.
+ * the creation of the objective. Typically this is used for L2 and L3 forwarding
+ * to compute nodes and containers/VMs on the compute nodes directly attached
+ * to the switch.
*
* @param portNum the port number for the simple next objective
* @param treatment the actions to apply on the packets (should include outport)
@@ -567,7 +638,7 @@
}
/**
- * Creates Groups from a set of NeighborSet given.
+ * Creates hash groups from a set of NeighborSet given.
*
* @param nsSet a set of NeighborSet
* @param meta metadata passed into the creation of a Next Objective
@@ -633,7 +704,8 @@
}
/**
- * Creates broadcast groups for all ports in the same configured subnet.
+ * Creates broadcast groups for all ports in the same subnet for
+ * all configured subnets.
*/
public void createGroupsFromSubnetConfig() {
Map<Ip4Prefix, List<PortNumber>> subnetPortMap;
@@ -645,43 +717,50 @@
return;
}
// Construct a broadcast group for each subnet
- subnetPortMap.forEach((subnet, ports) -> {
- SubnetNextObjectiveStoreKey key =
- new SubnetNextObjectiveStoreKey(deviceId, subnet);
+ subnetPortMap.forEach((subnet, ports) -> createBcastGroupFromSubnet(subnet, ports));
+ }
- if (subnetNextObjStore.containsKey(key)) {
- log.debug("Broadcast group for device {} and subnet {} exists",
- deviceId, subnet);
- return;
- }
+ /**
+ * Creates a single broadcast group from a given subnet and list of ports.
+ *
+ * @param subnet a configured subnet
+ * @param ports list of ports in the subnet
+ */
+ public void createBcastGroupFromSubnet(Ip4Prefix subnet, List<PortNumber> ports) {
+ SubnetNextObjectiveStoreKey key =
+ new SubnetNextObjectiveStoreKey(deviceId, subnet);
- VlanId assignedVlanId =
- srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
- TrafficSelector metadata =
- DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
+ if (subnetNextObjStore.containsKey(key)) {
+ log.debug("Broadcast group for device {} and subnet {} exists",
+ deviceId, subnet);
+ return;
+ }
- int nextId = flowObjectiveService.allocateNextId();
+ VlanId assignedVlanId =
+ srManager.getSubnetAssignedVlanId(this.deviceId, subnet);
+ TrafficSelector metadata =
+ DefaultTrafficSelector.builder().matchVlanId(assignedVlanId).build();
- NextObjective.Builder nextObjBuilder = DefaultNextObjective
- .builder().withId(nextId)
- .withType(NextObjective.Type.BROADCAST).fromApp(appId)
- .withMeta(metadata);
+ int nextId = flowObjectiveService.allocateNextId();
- ports.forEach(port -> {
- TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
- tBuilder.popVlan();
- tBuilder.setOutput(port);
- nextObjBuilder.addTreatment(tBuilder.build());
- });
+ NextObjective.Builder nextObjBuilder = DefaultNextObjective
+ .builder().withId(nextId)
+ .withType(NextObjective.Type.BROADCAST).fromApp(appId)
+ .withMeta(metadata);
- NextObjective nextObj = nextObjBuilder.add();
- flowObjectiveService.next(deviceId, nextObj);
- log.debug("createGroupFromSubnetConfig: Submited "
- + "next objective {} in device {}",
- nextId, deviceId);
-
- subnetNextObjStore.put(key, nextId);
+ ports.forEach(port -> {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.popVlan();
+ tBuilder.setOutput(port);
+ nextObjBuilder.addTreatment(tBuilder.build());
});
+
+ NextObjective nextObj = nextObjBuilder.add();
+ flowObjectiveService.next(deviceId, nextObj);
+ log.debug("createBcastGroupFromSubnet: Submited next objective {} in device {}",
+ nextId, deviceId);
+
+ subnetNextObjStore.put(key, nextId);
}
/**