SR app now assigns internal vlans per subnet and passes this
information in a filtering objective to drivers. OF-DPA driver
uses this information to assign vlans to untagged packets.
Change-Id: Ibf33bdcedf5f83992f362dfb91c12575c65da3b4
diff --git a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 1faebca..9305541 100644
--- a/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -23,6 +23,8 @@
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.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreService;
@@ -45,7 +47,6 @@
import org.onosproject.net.device.DeviceListener;
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flowobjective.FlowObjectiveService;
-import org.onosproject.net.group.GroupKey;
import org.onosproject.net.host.HostService;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.link.LinkEvent;
@@ -64,9 +65,11 @@
import org.slf4j.LoggerFactory;
import java.net.URI;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executors;
@@ -135,6 +138,10 @@
Integer> nsNextObjStore = null;
private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
private EventuallyConsistentMap<String, Policy> policyStore = null;
+ // Per device, per-subnet assigned-vlans store, with (device id + subnet
+ // IPv4 prefix) as key
+ private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
+ subnetVidStore = null;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected StorageService storageService;
@@ -163,6 +170,9 @@
private KryoNamespace.Builder kryoBuilder = null;
+ private static final short ASSIGNED_VLAN_START = 4093;
+ public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
+
@Activate
protected void activate() {
appId = coreService
@@ -180,7 +190,9 @@
DefaultTunnel.class,
Policy.class,
TunnelPolicy.class,
- Policy.Type.class
+ Policy.Type.class,
+ SubnetAssignedVidStoreKey.class,
+ VlanId.class
);
log.debug("Creating EC map nsnextobjectivestore");
@@ -212,6 +224,15 @@
.withTimestampProvider((k, v) -> new WallClockTimestamp())
.build();
+ EventuallyConsistentMapBuilder<SubnetAssignedVidStoreKey, VlanId>
+ subnetVidStoreMapBuilder = storageService.eventuallyConsistentMapBuilder();
+
+ subnetVidStore = subnetVidStoreMapBuilder
+ .withName("subnetvidstore")
+ .withSerializer(kryoBuilder)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .build();
+
cfgService.addListener(cfgListener);
cfgService.registerConfigFactory(cfgFactory);
@@ -296,23 +317,72 @@
}
/**
- * Returns the GroupKey object for the device and the NeighborSet given.
- * XXX is this called
+ * Returns the vlan-id assigned to the subnet configured for a device.
+ * If no vlan-id has been assigned, a new one is assigned out of a pool of ids,
+ * if and only if this controller instance is the master for the device.
+ * <p>
+ * USAGE: The assigned vlans are meant to be applied to untagged packets on those
+ * switches/pipelines that need this functionality. These vids are meant
+ * to be used internally within a switch, and thus need to be unique only
+ * on a switch level. Note that packets never go out on the wire with these
+ * vlans. Currently, vlan ids are assigned from value 4093 down.
+ * Vlan id 4094 expected to be used for all ports that are not assigned subnets.
+ * Vlan id 4095 is reserved and unused. Only a single vlan id is assigned
+ * per subnet.
+ * XXX This method should avoid any vlans configured on the ports, but
+ * currently the app works only on untagged packets and as a result
+ * ignores any vlan configuration.
*
- * @param ns NeightborSet object for the GroupKey
- * @return GroupKey object for the NeighborSet
+ * @param deviceId switch dpid
+ * @param subnet IPv4 prefix for which assigned vlan is desired
+ * @return VlanId assigned for the subnet on the device, or
+ * null if no vlan assignment was found and this instance is not
+ * the master for the device.
*/
- public GroupKey getGroupKey(NeighborSet ns) {
- for (DefaultGroupHandler groupHandler : groupHandlerMap.values()) {
- return groupHandler.getGroupKey(ns);
+ public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
+ VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
+ deviceId, subnet));
+ if (assignedVid != null) {
+ log.debug("Query for subnet:{} on device:{} returned assigned-vlan "
+ + "{}", subnet, deviceId, assignedVid);
+ return assignedVid;
+ }
+ //check mastership for the right to assign a vlan
+ if (!mastershipService.isLocalMaster(deviceId)) {
+ log.warn("This controller instance is not the master for device {}. "
+ + "Cannot assign vlan-id for subnet {}", deviceId, subnet);
+ return null;
+ }
+ // vlan assignment is expensive but done only once
+ List<Ip4Prefix> configuredSubnets = deviceConfiguration.getSubnets(deviceId);
+ Set<Short> assignedVlans = new HashSet<>();
+ Set<Ip4Prefix> unassignedSubnets = new HashSet<>();
+ for (Ip4Prefix sub : configuredSubnets) {
+ VlanId v = subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId,
+ sub));
+ if (v != null) {
+ assignedVlans.add(v.toShort());
+ } else {
+ unassignedSubnets.add(sub);
+ }
+ }
+ short nextAssignedVlan = ASSIGNED_VLAN_START;
+ if (!assignedVlans.isEmpty()) {
+ nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
+ }
+ for (Ip4Prefix unsub : unassignedSubnets) {
+ subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
+ VlanId.vlanId(nextAssignedVlan--));
+ log.info("Assigned vlan: {} to subnet: {} on device: {}",
+ nextAssignedVlan + 1, unsub, deviceId);
}
- return null;
+ return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
}
/**
- * Returns the next objective ID for the NeighborSet given. If the nextObjectiveID does not exist,
- * a new one is created and returned.
+ * Returns the next objective ID for the given NeighborSet.
+ * If the nextObjectiveID does not exist, a new one is created and returned.
*
* @param deviceId Device ID
* @param ns NegighborSet