CORD-367 L2 bridging and L3 routing support with internal VLANs in OF-DPA.
Also includes:
All forwarding in app is now via nextObjectives (not treatments) - Spring Open driver converts
non-ECMP forwarding to flow-actions, while OF-DPA driver continues to use groups.
Convert 'setMeta' methods to 'withMeta' in Flow Objectives API.
Bug fix in Flow Objective Manager - set of PendingNext is now threadsafe.
Bug fix in ArpHandler - now recognizes routerIp in addition to gatewayIps
Removed a bunch of testcode
Added group count in CLI
Change-Id: Id3b879c5dda78151ca0ec359179f1604066d39fc
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 518bce3..62722f0 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -57,6 +57,7 @@
import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
+import org.onosproject.segmentrouting.grouphandler.PortNextObjectiveStoreKey;
import org.onosproject.mastership.MastershipService;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
@@ -97,7 +98,6 @@
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
-@SuppressWarnings("ALL")
@Service
@Component(immediate = true)
public class SegmentRoutingManager implements SegmentRoutingService {
@@ -150,21 +150,27 @@
private ScheduledExecutorService executorService = Executors
.newScheduledThreadPool(1);
+ @SuppressWarnings("unused")
private static ScheduledFuture<?> eventHandlerFuture = null;
+ @SuppressWarnings("rawtypes")
private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
private Map<DeviceId, DefaultGroupHandler> groupHandlerMap =
new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
// Per device next objective ID store with (device id + neighbor set) as key
private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
nsNextObjStore = null;
+ // Per device next objective ID store with (device id + subnet) as key
private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
subnetNextObjStore = null;
- private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
- private EventuallyConsistentMap<String, Policy> policyStore = null;
+ // Per device next objective ID store with (device id + port) as key
+ private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
+ portNextObjStore = null;
// Per device, per-subnet assigned-vlans store, with (device id + subnet
// IPv4 prefix) as key
private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
subnetVidStore = null;
+ private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
+ private EventuallyConsistentMap<String, Policy> policyStore = null;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
@@ -175,6 +181,7 @@
private final InternalConfigListener cfgListener =
new InternalConfigListener(this);
+ @SuppressWarnings({ "unchecked", "rawtypes" })
private final ConfigFactory cfgFactory =
new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY,
SegmentRoutingConfig.class,
@@ -228,7 +235,6 @@
log.debug("Creating EC map nsnextobjectivestore");
EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
-
nsNextObjStore = nsNextObjMapBuilder
.withName("nsnextobjectivestore")
.withSerializer(kryoBuilder)
@@ -239,16 +245,23 @@
log.debug("Creating EC map subnetnextobjectivestore");
EventuallyConsistentMapBuilder<SubnetNextObjectiveStoreKey, Integer>
subnetNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
-
subnetNextObjStore = subnetNextObjMapBuilder
.withName("subnetnextobjectivestore")
.withSerializer(kryoBuilder)
.withTimestampProvider((k, v) -> new WallClockTimestamp())
.build();
+ log.debug("Creating EC map subnetnextobjectivestore");
+ EventuallyConsistentMapBuilder<PortNextObjectiveStoreKey, Integer>
+ portNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
+ portNextObjStore = portNextObjMapBuilder
+ .withName("portnextobjectivestore")
+ .withSerializer(kryoBuilder)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .build();
+
EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
storageService.eventuallyConsistentMapBuilder();
-
tunnelStore = tunnelMapBuilder
.withName("tunnelstore")
.withSerializer(kryoBuilder)
@@ -257,7 +270,6 @@
EventuallyConsistentMapBuilder<String, Policy> policyMapBuilder =
storageService.eventuallyConsistentMapBuilder();
-
policyStore = policyMapBuilder
.withName("policystore")
.withSerializer(kryoBuilder)
@@ -266,7 +278,6 @@
EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
-
subnetVidStore = subnetVidStoreMapBuilder
.withName("subnetvidstore")
.withSerializer(kryoBuilder)
@@ -425,8 +436,7 @@
/**
* Returns the next objective ID for the given NeighborSet.
* If the nextObjective does not exist, a new one is created and
- * it's id is returned.
- * TODO move the side-effect creation of a Next Objective into a new method
+ * its id is returned.
*
* @param deviceId Device ID
* @param ns NegighborSet
@@ -441,18 +451,19 @@
return groupHandlerMap
.get(deviceId).getNextObjectiveId(ns, meta);
} else {
- log.warn("getNextObjectiveId query in device {} not found", deviceId);
+ log.warn("getNextObjectiveId query - groupHandler for device {} "
+ + "not found", deviceId);
return -1;
}
}
/**
- * Returns the next objective ID for the Subnet given. If the nextObjectiveID does not exist,
- * a new one is created and returned.
+ * Returns the next objective ID for the given subnet prefix. It is expected
+ * that the next-objective has been pre-created from configuration.
*
* @param deviceId Device ID
* @param prefix Subnet
- * @return next objective ID
+ * @return next objective ID or -1 if it was not found
*/
public int getSubnetNextObjectiveId(DeviceId deviceId, IpPrefix prefix) {
if (groupHandlerMap.get(deviceId) != null) {
@@ -460,7 +471,33 @@
return groupHandlerMap
.get(deviceId).getSubnetNextObjectiveId(prefix);
} else {
- log.warn("getSubnetNextObjectiveId query in device {} not found", deviceId);
+ log.warn("getSubnetNextObjectiveId query - groupHandler for "
+ + "device {} not found", deviceId);
+ return -1;
+ }
+ }
+
+ /**
+ * Returns the next objective ID for the given portNumber, given the treatment.
+ * There could be multiple different treatments to the same outport, which
+ * would result in different objectives. If the next object
+ * does not exist, a new one is created and its id is returned.
+ *
+ * @param deviceId Device ID
+ * @param portNum port number on device for which NextObjective is queried
+ * @param treatment the actions to apply on the packets (should include outport)
+ * @param meta metadata passed into the creation of a Next Objective if necessary
+ * @return next objective ID or -1 if it was not found
+ */
+ public int getPortNextObjectiveId(DeviceId deviceId, PortNumber portNum,
+ TrafficTreatment treatment,
+ TrafficSelector meta) {
+ DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
+ if (ghdlr != null) {
+ return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
+ } else {
+ log.warn("getPortNextObjectiveId query - groupHandler for device {}"
+ + " not found", deviceId);
return -1;
}
}
@@ -475,7 +512,7 @@
InboundPacket pkt = context.inPacket();
Ethernet ethernet = pkt.parsed();
-
+ log.trace("Rcvd pktin: {}", ethernet);
if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
arpHandler.processPacketIn(pkt);
} else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
@@ -517,6 +554,7 @@
}
}
+ @SuppressWarnings("rawtypes")
private void scheduleEventHandlerIfNotScheduled(Event event) {
synchronized (threadSchedulerLock) {
eventQueue.add(event);
@@ -539,6 +577,7 @@
public void run() {
try {
while (true) {
+ @SuppressWarnings("rawtypes")
Event event = null;
synchronized (threadSchedulerLock) {
if (!eventQueue.isEmpty()) {
@@ -647,7 +686,8 @@
linkService,
flowObjectiveService,
nsNextObjStore,
- subnetNextObjStore);
+ subnetNextObjStore,
+ portNextObjStore);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting processDeviceAdded.");
return;
@@ -714,7 +754,8 @@
linkService,
flowObjectiveService,
nsNextObjStore,
- subnetNextObjStore);
+ subnetNextObjStore,
+ portNextObjStore);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting configureNetwork.");
return;
@@ -766,7 +807,7 @@
// Populate bridging table entry
ForwardingObjective.Builder fob =
- getForwardingObjectiveBuilder(mac, vlanId, port);
+ getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
flowObjectiveService.forward(deviceId, fob.add(
new BridgingTableObjectiveContext(mac, vlanId)
));
@@ -782,20 +823,37 @@
}
private ForwardingObjective.Builder getForwardingObjectiveBuilder(
- MacAddress mac, VlanId vlanId, PortNumber port) {
+ DeviceId deviceId, MacAddress mac, VlanId vlanId,
+ PortNumber outport) {
+ // match rule
TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
sbuilder.matchEthDst(mac);
sbuilder.matchVlanId(vlanId);
TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
- // TODO Move popVlan from flow action to group action
tbuilder.immediate().popVlan();
- tbuilder.immediate().setOutput(port);
+ tbuilder.immediate().setOutput(outport);
+
+ // for switch pipelines that need it, provide outgoing vlan as metadata
+ VlanId outvlan = null;
+ Ip4Prefix subnet = deviceConfiguration.getPortSubnet(deviceId, outport);
+ if (subnet == null) {
+ outvlan = VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET);
+ } else {
+ outvlan = getSubnetAssignedVlanId(deviceId, subnet);
+ }
+ TrafficSelector meta = DefaultTrafficSelector.builder()
+ .matchVlanId(outvlan).build();
+
+ // All forwarding is via Groups. Drivers can re-purpose to flow-actions if needed.
+ int portNextObjId = getPortNextObjectiveId(deviceId, outport,
+ tbuilder.build(),
+ meta);
return DefaultForwardingObjective.builder()
.withFlag(ForwardingObjective.Flag.SPECIFIC)
.withSelector(sbuilder.build())
- .withTreatment(tbuilder.build())
+ .nextStep(portNextObjId)
.withPriority(100)
.fromApp(appId)
.makePermanent();
@@ -807,11 +865,13 @@
DeviceId deviceId = event.subject().location().deviceId();
PortNumber port = event.subject().location().port();
Set<IpAddress> ips = event.subject().ipAddresses();
- log.debug("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
+ log.info("Host {}/{} is added at {}:{}", mac, vlanId, deviceId, port);
// Populate bridging table entry
+ log.debug("Populate L2 table entry for host {} at {}:{}",
+ mac, deviceId, port);
ForwardingObjective.Builder fob =
- getForwardingObjectiveBuilder(mac, vlanId, port);
+ getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
flowObjectiveService.forward(deviceId, fob.add(
new BridgingTableObjectiveContext(mac, vlanId)
));
@@ -835,7 +895,7 @@
// Revoke bridging table entry
ForwardingObjective.Builder fob =
- getForwardingObjectiveBuilder(mac, vlanId, port);
+ getForwardingObjectiveBuilder(deviceId, mac, vlanId, port);
flowObjectiveService.forward(deviceId, fob.remove(
new BridgingTableObjectiveContext(mac, vlanId)
));
@@ -863,7 +923,7 @@
// Revoke previous bridging table entry
ForwardingObjective.Builder prevFob =
- getForwardingObjectiveBuilder(mac, vlanId, prevPort);
+ getForwardingObjectiveBuilder(prevDeviceId, mac, vlanId, prevPort);
flowObjectiveService.forward(prevDeviceId, prevFob.remove(
new BridgingTableObjectiveContext(mac, vlanId)
));
@@ -878,7 +938,7 @@
// Populate new bridging table entry
ForwardingObjective.Builder newFob =
- getForwardingObjectiveBuilder(mac, vlanId, prevPort);
+ getForwardingObjectiveBuilder(newDeviceId, mac, vlanId, newPort);
flowObjectiveService.forward(newDeviceId, newFob.add(
new BridgingTableObjectiveContext(mac, vlanId)
));