CORD-349 Support VLAN cross-connect traffic
Change related to this topic:
- Support VLAN cross-connect traffic
Utilize ports subjectClass to achieve. For non-xConnect port, set interface VLAN to -1
- Remove VLAN checking since we have multiple VLANs per port
- Hash the L2 interface group key generation to include VLAN as well
- Update the network-cfg.json sample
Other refactoring changes:
- Read next objective stores from srManager directly
- Use constant for flow priority
- CORD-267 Javadoc fix
Change-Id: I4ca8c2d9c8b3633a4a0101c5070d19343f7e5b90
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
index 6d9171b..51324893 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/ArpHandler.java
@@ -41,6 +41,10 @@
import static com.google.common.base.Preconditions.checkNotNull;
+/**
+ * Handler of ARP packets that responses or forwards ARP packets that
+ * are sent to the controller.
+ */
public class ArpHandler {
private static Logger log = LoggerFactory.getLogger(ArpHandler.class);
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 1a37efd..9e24da4 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultRoutingHandler.java
@@ -37,6 +37,10 @@
import static com.google.common.base.Preconditions.checkNotNull;
+/**
+ * Default routing handler that is responsible for route computing and
+ * routing rule population.
+ */
public class DefaultRoutingHandler {
private static Logger log = LoggerFactory
@@ -512,6 +516,7 @@
*/
public void populatePortAddressingRules(DeviceId deviceId) {
rulePopulator.populateRouterMacVlanFilters(deviceId);
+ rulePopulator.populateXConnectVlanFilters(deviceId);
rulePopulator.populateRouterIpPunts(deviceId);
}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java
index 7016143..7d757c4 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/DefaultTunnel.java
@@ -20,7 +20,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
/**
- * Tunnel class.
+ * Default Tunnel class.
*/
public class DefaultTunnel implements Tunnel {
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
index d1dc8dd..a8d16e8 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IcmpHandler.java
@@ -38,6 +38,10 @@
import static com.google.common.base.Preconditions.checkNotNull;
+/**
+ * Handler of ICMP packets that responses or forwards ICMP packets that
+ * are sent to the controller.
+ */
public class IcmpHandler {
private static Logger log = LoggerFactory.getLogger(IcmpHandler.class);
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java
index d6a9dcf..4a5a3e3 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/IpHandler.java
@@ -37,6 +37,10 @@
import static com.google.common.base.Preconditions.checkNotNull;
+/**
+ * Handler of IP packets that forwards IP packets that are sent to the controller,
+ * except the ICMP packets which are processed by @link{IcmpHandler}.
+ */
public class IpHandler {
private static Logger log = LoggerFactory.getLogger(IpHandler.class);
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Policy.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Policy.java
index 2e41795..6133254 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Policy.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/Policy.java
@@ -24,16 +24,24 @@
* Enums for policy type.
*/
enum Type {
- // Tunnel flow policy type
+ /**
+ * Tunnel flow policy type.
+ */
TUNNEL_FLOW,
- // Load balancing policy type
+ /**
+ * Load balancing policy type.
+ */
LOADBALANCE,
- // policy to avoid specific routers or links
+ /**
+ * policy to avoid specific routers or links.
+ */
AVOID,
- // Access Control policy type
+ /**
+ * Access Control policy type.
+ */
DENY
}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java
index 0a4c26d..308d026 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/PolicyHandler.java
@@ -48,18 +48,43 @@
private FlowObjectiveService flowObjectiveService;
private TunnelHandler tunnelHandler;
private final EventuallyConsistentMap<String, Policy> policyStore;
-
+ /**
+ * Result of policy creation.
+ */
public enum Result {
+ /**
+ * Success.
+ */
SUCCESS,
+
+ /**
+ * The same policy exists already.
+ */
POLICY_EXISTS,
+
+ /**
+ * The policy ID exists already.
+ */
ID_EXISTS,
+
+ /**
+ * Cannot find associated tunnel.
+ */
TUNNEL_NOT_FOUND,
+
+ /**
+ * Policy was not found.
+ */
POLICY_NOT_FOUND,
+
+ /**
+ * Policy type {} is not supported yet.
+ */
UNSUPPORTED_TYPE
}
/**
- * Creates a reference.
+ * Constructs policy handler.
*
* @param appId segment routing application ID
* @param deviceConfiguration DeviceConfiguration reference
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
index 03b29a5..6017e8b 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/RoutingRulePopulator.java
@@ -23,6 +23,7 @@
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
import org.onosproject.segmentrouting.config.DeviceConfiguration;
import org.onosproject.segmentrouting.grouphandler.NeighborSet;
@@ -49,11 +50,15 @@
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import static com.google.common.base.Preconditions.checkNotNull;
+/**
+ * Populator of segment routing flow rules.
+ */
public class RoutingRulePopulator {
private static final Logger log = LoggerFactory
.getLogger(RoutingRulePopulator.class);
@@ -63,6 +68,10 @@
private DeviceConfiguration config;
private static final int HIGHEST_PRIORITY = 0xffff;
+ //
+ private static final int XCONNECT_PRIORITY = 1000;
+ private static final int DEFAULT_PRIORITY = 100;
+ private static final int FLOOD_PRIORITY = 5;
private static final long OFPP_MAX = 0xffffff00L;
@@ -120,6 +129,14 @@
rulePopulationCounter.incrementAndGet();
}
+ /**
+ * Removes IP rules for host when the host is gone.
+ *
+ * @param deviceId device ID of the device that host attaches to
+ * @param hostIp IP address of the host
+ * @param hostMac MAC address of the host
+ * @param outPort port that host attaches to
+ */
public void revokeIpRuleForHost(DeviceId deviceId, Ip4Address hostIp,
MacAddress hostMac, PortNumber outPort) {
log.debug("Revoke IP table entry for host {} at {}:{}",
@@ -175,7 +192,7 @@
.withSelector(selector)
.nextStep(portNextObjId)
.fromApp(srManager.appId).makePermanent()
- .withPriority(100).withFlag(ForwardingObjective.Flag.SPECIFIC);
+ .withPriority(DEFAULT_PRIORITY).withFlag(ForwardingObjective.Flag.SPECIFIC);
}
/**
@@ -369,7 +386,7 @@
for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
.makePermanent()).withSelector(selector)
- .withPriority(100))
+ .withPriority(DEFAULT_PRIORITY))
.withFlag(ForwardingObjective.Flag.SPECIFIC);
srManager.flowObjectiveService.
forward(deviceId,
@@ -464,7 +481,8 @@
FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
fob.withKey(Criteria.matchInPort(port.number()))
.addCondition(Criteria.matchEthDst(deviceMac))
- .addCondition(Criteria.matchVlanId(VlanId.NONE));
+ .addCondition(Criteria.matchVlanId(VlanId.NONE))
+ .withPriority(DEFAULT_PRIORITY);
// vlan assignment is valid only if this instance is master
if (srManager.mastershipService.isLocalMaster(deviceId)) {
TrafficTreatment tt = DefaultTrafficTreatment.builder()
@@ -558,7 +576,7 @@
fob.withFlag(Flag.SPECIFIC)
.withSelector(sbuilder.build())
.nextStep(nextId)
- .withPriority(5)
+ .withPriority(FLOOD_PRIORITY)
.fromApp(srManager.appId)
.makePermanent();
@@ -572,6 +590,86 @@
});
}
+ /**
+ * Creates a filtering objective to permit VLAN cross-connect traffic.
+ *
+ * @param deviceId the DPID of the switch
+ */
+ public void populateXConnectVlanFilters(DeviceId deviceId) {
+ Map<VlanId, List<ConnectPoint>> xConnectsForDevice =
+ config.getXConnects();
+ xConnectsForDevice.forEach((vlanId, connectPoints) -> {
+ // Only proceed the xConnect for given device
+ for (ConnectPoint connectPoint : connectPoints) {
+ if (!connectPoint.deviceId().equals(deviceId)) {
+ return;
+ }
+ }
+
+ connectPoints.forEach(connectPoint -> {
+ FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
+ fob.withKey(Criteria.matchInPort(connectPoint.port()))
+ .addCondition(Criteria.matchVlanId(vlanId))
+ .addCondition(Criteria.matchEthDst(MacAddress.NONE))
+ .withPriority(XCONNECT_PRIORITY);
+
+ fob.permit().fromApp(srManager.appId);
+ srManager.flowObjectiveService
+ .filter(deviceId, fob.add(new SRObjectiveContext(deviceId,
+ SRObjectiveContext.ObjectiveType.FILTER)));
+ });
+ });
+ }
+
+ /**
+ * Populates a forwarding objective that points the VLAN cross-connect
+ * packets to a broadcast group.
+ *
+ * @param deviceId switch ID to set the rules
+ */
+ public void populateXConnectBroadcastRule(DeviceId deviceId) {
+ Map<VlanId, List<ConnectPoint>> xConnects =
+ config.getXConnects();
+ xConnects.forEach((vlanId, connectPoints) -> {
+ // Only proceed the xConnect for given device
+ for (ConnectPoint connectPoint : connectPoints) {
+ if (!connectPoint.deviceId().equals(deviceId)) {
+ return;
+ }
+ }
+
+ int nextId = srManager.getXConnectNextObjectiveId(deviceId, vlanId);
+ if (nextId < 0) {
+ log.error("Cannot install cross-connect broadcast rule in dev:{} " +
+ "due to missing nextId:{}", deviceId, nextId);
+ return;
+ }
+
+ /*
+ * Driver should treat objectives with MacAddress.NONE and !VlanId.NONE
+ * as the VLAN cross-connect broadcast rules
+ */
+ TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
+ sbuilder.matchVlanId(vlanId);
+ sbuilder.matchEthDst(MacAddress.NONE);
+
+ ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
+ fob.withFlag(Flag.SPECIFIC)
+ .withSelector(sbuilder.build())
+ .nextStep(nextId)
+ .withPriority(DEFAULT_PRIORITY)
+ .fromApp(srManager.appId)
+ .makePermanent();
+
+ srManager.flowObjectiveService.forward(
+ deviceId,
+ fob.add(new SRObjectiveContext(
+ deviceId,
+ SRObjectiveContext.ObjectiveType.FORWARDING)
+ )
+ );
+ });
+ }
private static class SRObjectiveContext implements ObjectiveContext {
enum ObjectiveType {
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 0f20451..592c0b1 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -69,7 +69,6 @@
import org.onosproject.net.device.DeviceService;
import org.onosproject.net.flowobjective.FlowObjectiveService;
import org.onosproject.net.host.HostService;
-import org.onosproject.net.intent.IntentService;
import org.onosproject.net.link.LinkEvent;
import org.onosproject.net.link.LinkListener;
import org.onosproject.net.link.LinkService;
@@ -77,8 +76,8 @@
import org.onosproject.net.packet.PacketContext;
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.segmentrouting.grouphandler.XConnectNextObjectiveStoreKey;
import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.store.service.EventuallyConsistentMapBuilder;
import org.onosproject.store.service.StorageService;
@@ -102,6 +101,9 @@
@Service
@Component(immediate = true)
+/**
+ * Segment routing manager.
+ */
public class SegmentRoutingManager implements SegmentRoutingService {
private static Logger log = LoggerFactory
@@ -111,15 +113,9 @@
protected CoreService coreService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected TopologyService topologyService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected PacketService packetService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- protected IntentService intentService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
protected HostService hostService;
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
@@ -157,20 +153,31 @@
@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>
+ new ConcurrentHashMap<>();
+ /**
+ * Per device next objective ID store with (device id + neighbor set) as key.
+ */
+ public EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
nsNextObjStore = null;
- // Per device next objective ID store with (device id + subnet) as key
- private EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
+ /**
+ * Per device next objective ID store with (device id + subnet) as key.
+ */
+ public EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
subnetNextObjStore = null;
- // Per device next objective ID store with (device id + port) as key
- private EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
+ /**
+ * Per device next objective ID store with (device id + port) as key.
+ */
+ public EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
portNextObjStore = null;
+ /**
+ * Per cross-connect objective ID store with VLAN ID as key.
+ */
+ public EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer>
+ xConnectNextObjStore = null;
// Per device, per-subnet assigned-vlans store, with (device id + subnet
// IPv4 prefix) as key
private EventuallyConsistentMap<SubnetAssignedVidStoreKey, VlanId>
- subnetVidStore = null;
+ subnetVidStore = null;
private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
private EventuallyConsistentMap<String, Policy> policyStore = null;
@@ -204,7 +211,13 @@
private KryoNamespace.Builder kryoBuilder = null;
+ /**
+ * The starting value of per-subnet VLAN ID assignment.
+ */
private static final short ASSIGNED_VLAN_START = 4093;
+ /**
+ * The default VLAN ID assigned to the interfaces without subnet config.
+ */
public static final short ASSIGNED_VLAN_NO_SUBNET = 4094;
@Activate
@@ -262,6 +275,15 @@
.withTimestampProvider((k, v) -> new WallClockTimestamp())
.build();
+ log.debug("Creating EC map xconnectnextobjectivestore");
+ EventuallyConsistentMapBuilder<XConnectNextObjectiveStoreKey, Integer>
+ xConnectNextObjStoreBuilder = storageService.eventuallyConsistentMapBuilder();
+ xConnectNextObjStore = xConnectNextObjStoreBuilder
+ .withName("xconnectnextobjectivestore")
+ .withSerializer(kryoBuilder)
+ .withTimestampProvider((k, v) -> new WallClockTimestamp())
+ .build();
+
EventuallyConsistentMapBuilder<String, Tunnel> tunnelMapBuilder =
storageService.eventuallyConsistentMapBuilder();
tunnelStore = tunnelMapBuilder
@@ -394,9 +416,6 @@
* 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 deviceId switch dpid
* @param subnet IPv4 prefix for which assigned vlan is desired
@@ -404,6 +423,7 @@
* null if no vlan assignment was found and this instance is not
* the master for the device.
*/
+ // TODO: We should avoid assigning VLAN IDs that are used by VLAN cross-connection.
public VlanId getSubnetAssignedVlanId(DeviceId deviceId, Ip4Prefix subnet) {
VlanId assignedVid = subnetVidStore.get(new SubnetAssignedVidStoreKey(
deviceId, subnet));
@@ -508,7 +528,26 @@
if (ghdlr != null) {
return ghdlr.getPortNextObjectiveId(portNum, treatment, meta);
} else {
- log.warn("getPortNextObjectiveId query - groupHandler for device {}"
+ log.warn("getPortNextObjectiveId query - groupHandler for device {}"
+ + " not found", deviceId);
+ return -1;
+ }
+ }
+
+ /**
+ * Returns the next objective ID of type broadcast associated with the VLAN
+ * cross-connection.
+ *
+ * @param deviceId Device ID for the cross-connection
+ * @param vlanId VLAN ID for the cross-connection
+ * @return next objective ID or -1 if it was not found
+ */
+ public int getXConnectNextObjectiveId(DeviceId deviceId, VlanId vlanId) {
+ DefaultGroupHandler ghdlr = groupHandlerMap.get(deviceId);
+ if (ghdlr != null) {
+ return ghdlr.getXConnectNextObjectiveId(vlanId);
+ } else {
+ log.warn("getPortNextObjectiveId query - groupHandler for device {}"
+ " not found", deviceId);
return -1;
}
@@ -707,9 +746,6 @@
deviceConfiguration,
linkService,
flowObjectiveService,
- nsNextObjStore,
- subnetNextObjStore,
- portNextObjStore,
this);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting processDeviceAdded.");
@@ -727,6 +763,8 @@
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
groupHandler.createGroupsFromSubnetConfig();
routingRulePopulator.populateSubnetBroadcastRule(device.id());
+ groupHandler.createGroupsForXConnect(device.id());
+ routingRulePopulator.populateXConnectBroadcastRule(device.id());
}
}
@@ -742,10 +780,18 @@
private class InternalConfigListener implements NetworkConfigListener {
SegmentRoutingManager segmentRoutingManager;
+ /**
+ * Constructs the internal network config listener.
+ *
+ * @param srMgr segment routing manager
+ */
public InternalConfigListener(SegmentRoutingManager srMgr) {
this.segmentRoutingManager = srMgr;
}
+ /**
+ * Reads network config and initializes related data structure accordingly.
+ */
public void configureNetwork() {
deviceConfiguration = new DeviceConfiguration(segmentRoutingManager.cfgService);
@@ -777,9 +823,6 @@
deviceConfiguration,
linkService,
flowObjectiveService,
- nsNextObjStore,
- subnetNextObjStore,
- portNextObjStore,
segmentRoutingManager);
} catch (DeviceConfigNotFoundException e) {
log.warn(e.getMessage() + " Aborting configureNetwork.");
@@ -798,6 +841,8 @@
DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
groupHandler.createGroupsFromSubnetConfig();
routingRulePopulator.populateSubnetBroadcastRule(device.id());
+ groupHandler.createGroupsForXConnect(device.id());
+ routingRulePopulator.populateXConnectBroadcastRule(device.id());
}
}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java
index 84b44c9..b721d0e 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/SubnetAssignedVidStoreKey.java
@@ -6,13 +6,18 @@
import org.onosproject.net.DeviceId;
/**
- * Class definition for key used to map per device subnets to assigned Vlan ids.
- *
+ * Key of assigned VLAN ID store.
*/
public class SubnetAssignedVidStoreKey {
private final DeviceId deviceId;
private final Ip4Prefix subnet;
+ /**
+ * Constructs the key of per subnet VLAN ID store.
+ *
+ * @param deviceId device ID of the VLAN cross-connection
+ * @param subnet subnet information
+ */
public SubnetAssignedVidStoreKey(DeviceId deviceId, Ip4Prefix subnet) {
this.deviceId = deviceId;
this.subnet = subnet;
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
index 5a82e71..8695874 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/TunnelHandler.java
@@ -43,16 +43,54 @@
private Map<DeviceId, DefaultGroupHandler> groupHandlerMap;
private LinkService linkService;
+ /**
+ * Result of tunnel creation or removal.
+ */
public enum Result {
+ /**
+ * Success.
+ */
SUCCESS,
+
+ /**
+ * More than one router needs to specified to created a tunnel.
+ */
WRONG_PATH,
+
+ /**
+ * The same tunnel exists already.
+ */
TUNNEL_EXISTS,
+
+ /**
+ * The same tunnel ID exists already.
+ */
ID_EXISTS,
+
+ /**
+ * Tunnel not found.
+ */
TUNNEL_NOT_FOUND,
+
+ /**
+ * Cannot remove the tunnel used by a policy.
+ */
TUNNEL_IN_USE,
+
+ /**
+ * Failed to create/remove groups for the tunnel.
+ */
INTERNAL_ERROR
}
+ /**
+ * Constructs tunnel handler.
+ *
+ * @param linkService link service
+ * @param deviceConfiguration device configuration
+ * @param groupHandlerMap group handler map
+ * @param tunnelStore tunnel store
+ */
public TunnelHandler(LinkService linkService,
DeviceConfiguration deviceConfiguration,
Map<DeviceId, DefaultGroupHandler> groupHandlerMap,
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
index dbac596..3d2d337 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceConfiguration.java
@@ -19,6 +19,7 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
import org.onosproject.incubator.net.config.basics.ConfigException;
import org.onosproject.incubator.net.config.basics.InterfaceConfig;
import org.onosproject.incubator.net.intf.Interface;
@@ -33,6 +34,7 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -48,8 +50,8 @@
private static final Logger log = LoggerFactory
.getLogger(DeviceConfiguration.class);
private final List<Integer> allSegmentIds = new ArrayList<>();
- private final ConcurrentHashMap<DeviceId, SegmentRouterInfo> deviceConfigMap
- = new ConcurrentHashMap<>();
+ private final Map<DeviceId, SegmentRouterInfo> deviceConfigMap = new ConcurrentHashMap<>();
+ private final Map<VlanId, List<ConnectPoint>> xConnects = new ConcurrentHashMap<>();
private class SegmentRouterInfo {
int nodeSid;
@@ -62,14 +64,14 @@
Map<Integer, Set<Integer>> adjacencySids;
public SegmentRouterInfo() {
- this.gatewayIps = new HashMap<>();
- this.subnets = new HashMap<>();
+ gatewayIps = new HashMap<>();
+ subnets = new HashMap<>();
}
}
/**
- * Constructor. Reads all the configuration for all devices of type
- * Segment Router and organizes into various maps for easier access.
+ * Constructs device configuration for all Segment Router devices,
+ * organizing the data into various maps for easier access.
*
* @param cfgService config service
*/
@@ -88,8 +90,8 @@
info.isEdge = config.isEdgeRouter();
info.adjacencySids = config.adjacencySids();
- this.deviceConfigMap.put(info.deviceId, info);
- this.allSegmentIds.add(info.nodeSid);
+ deviceConfigMap.put(info.deviceId, info);
+ allSegmentIds.add(info.nodeSid);
});
// Read gatewayIps and subnets from port subject.
@@ -106,17 +108,42 @@
return;
}
networkInterfaces.forEach(networkInterface -> {
- DeviceId dpid = networkInterface.connectPoint().deviceId();
- PortNumber port = networkInterface.connectPoint().port();
- SegmentRouterInfo info = this.deviceConfigMap.get(dpid);
+ VlanId vlanId = networkInterface.vlan();
+ ConnectPoint connectPoint = networkInterface.connectPoint();
+ DeviceId dpid = connectPoint.deviceId();
+ PortNumber port = connectPoint.port();
+ SegmentRouterInfo info = deviceConfigMap.get(dpid);
// skip if there is no corresponding device for this ConenctPoint
if (info != null) {
+ // Extract subnet information
Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses();
interfaceAddresses.forEach(interfaceAddress -> {
info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
});
+
+ // Extract VLAN cross-connect information
+ // Do not setup cross-connect if VLAN is NONE
+ if (vlanId.equals(VlanId.NONE)) {
+ return;
+ }
+ List<ConnectPoint> connectPoints = xConnects.get(vlanId);
+ if (connectPoints != null) {
+ if (connectPoints.size() != 1) {
+ log.warn("Cross-connect should only have two endpoints. Aborting.");
+ return;
+ }
+ if (!connectPoints.get(0).deviceId().equals(connectPoint.deviceId())) {
+ log.warn("Cross-connect endpoints must be on the same switch. Aborting.");
+ return;
+ }
+ connectPoints.add(connectPoint);
+ } else {
+ connectPoints = new LinkedList<>();
+ connectPoints.add(connectPoint);
+ xConnects.put(vlanId, connectPoints);
+ }
}
});
@@ -235,6 +262,11 @@
return subnetPortMap;
}
+ @Override
+ public Map<VlanId, List<ConnectPoint>> getXConnects() {
+ return xConnects;
+ }
+
/**
* 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/config/DeviceProperties.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
index a39c956..9d4d884 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/DeviceProperties.java
@@ -21,6 +21,8 @@
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
@@ -93,4 +95,11 @@
* @return a map that contains all subnet-to-ports mapping of given device
*/
Map<Ip4Prefix, List<PortNumber>> getSubnetPortsMap(DeviceId deviceId);
+
+ /**
+ * Returns the VLAN cross-connect configuration.
+ *
+ * @return A map of that maps VLAN ID to a list of cross-connect endpoints
+ */
+ Map<VlanId, List<ConnectPoint>> getXConnects();
}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
index f788925..64486c6 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/config/SegmentRoutingConfig.java
@@ -35,24 +35,24 @@
* Configuration object for Segment Routing Application.
*/
public class SegmentRoutingConfig extends Config<DeviceId> {
- public static final String NAME = "name";
- public static final String IP = "routerIp";
- public static final String MAC = "routerMac";
- public static final String SID = "nodeSid";
- public static final String EDGE = "isEdgeRouter";
- public static final String ADJSIDS = "adjacencySids";
- public static final String ADJSID = "adjSid";
- public static final String PORTS = "ports";
+ private static final String NAME = "name";
+ private static final String IP = "routerIp";
+ private static final String MAC = "routerMac";
+ private static final String SID = "nodeSid";
+ private static final String EDGE = "isEdgeRouter";
+ private static final String ADJSIDS = "adjacencySids";
+ private static final String ADJSID = "adjSid";
+ private static final String PORTS = "ports";
@Override
public boolean isValid() {
return hasOnlyFields(NAME, IP, MAC, SID, EDGE, ADJSIDS, ADJSID, PORTS) &&
- this.name() != null &&
- this.routerIp() != null &&
- this.routerMac() != null &&
- this.nodeSid() != -1 &&
- this.isEdgeRouter() != null &&
- this.adjacencySids() != null;
+ name() != null &&
+ routerIp() != null &&
+ routerMac() != null &&
+ nodeSid() != -1 &&
+ isEdgeRouter() != null &&
+ adjacencySids() != null;
}
/**
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 4866b82..124ffa7 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
@@ -26,7 +26,6 @@
import org.onosproject.net.link.LinkService;
import org.onosproject.segmentrouting.SegmentRoutingManager;
import org.onosproject.segmentrouting.config.DeviceProperties;
-import org.onosproject.store.service.EventuallyConsistentMap;
/**
* Default ECMP group handler creation module for an edge device.
@@ -47,22 +46,13 @@
* 8) what about ecmp no label case
*/
public class DefaultEdgeGroupHandler extends DefaultGroupHandler {
- // TODO Access stores through srManager
protected DefaultEdgeGroupHandler(DeviceId deviceId,
ApplicationId appId,
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService,
- EventuallyConsistentMap<
- NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore,
- EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore,
- EventuallyConsistentMap<PortNextObjectiveStoreKey,
- Integer> portNextObjStore,
SegmentRoutingManager srManager) {
- super(deviceId, appId, config, linkService, flowObjService,
- nsNextObjStore, subnetNextObjStore, portNextObjStore, srManager);
+ super(deviceId, appId, config, linkService, flowObjService, srManager);
}
@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 a4b89c1..4e64c4b 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
@@ -35,6 +35,7 @@
import org.onlab.packet.VlanId;
import org.onlab.util.KryoNamespace;
import org.onosproject.core.ApplicationId;
+import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Link;
import org.onosproject.net.PortNumber;
@@ -48,8 +49,6 @@
import org.onosproject.net.flowobjective.Objective;
import org.onosproject.net.flowobjective.ObjectiveContext;
import org.onosproject.net.flowobjective.ObjectiveError;
-import org.onosproject.net.group.DefaultGroupKey;
-import org.onosproject.net.group.GroupKey;
import org.onosproject.net.link.LinkService;
import org.onosproject.segmentrouting.SegmentRoutingManager;
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
@@ -81,12 +80,14 @@
//local store for ports on this device connected to neighbor-device-id
protected ConcurrentHashMap<PortNumber, DeviceId> portDeviceMap =
new ConcurrentHashMap<>();
- protected EventuallyConsistentMap<
- NeighborSetNextObjectiveStoreKey, Integer> nsNextObjStore = null;
- protected EventuallyConsistentMap<
- SubnetNextObjectiveStoreKey, Integer> subnetNextObjStore = null;
- protected EventuallyConsistentMap<
- PortNextObjectiveStoreKey, Integer> portNextObjStore = null;
+ protected EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey, Integer>
+ nsNextObjStore = null;
+ protected EventuallyConsistentMap<SubnetNextObjectiveStoreKey, Integer>
+ subnetNextObjStore = null;
+ protected EventuallyConsistentMap<PortNextObjectiveStoreKey, Integer>
+ portNextObjStore = null;
+ protected EventuallyConsistentMap<XConnectNextObjectiveStoreKey, Integer>
+ xConnectNextObjStore = null;
private SegmentRoutingManager srManager;
protected KryoNamespace.Builder kryo = new KryoNamespace.Builder()
@@ -97,17 +98,10 @@
.register(GroupBucketIdentifier.class)
.register(GroupBucketIdentifier.BucketOutputType.class);
- // TODO Access stores through srManager
protected DefaultGroupHandler(DeviceId deviceId, ApplicationId appId,
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService,
- EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore,
- EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore,
- EventuallyConsistentMap<PortNextObjectiveStoreKey,
- Integer> portNextObjStore,
SegmentRoutingManager srManager) {
this.deviceId = checkNotNull(deviceId);
this.appId = checkNotNull(appId);
@@ -123,9 +117,10 @@
+ " Skipping value assignment in DefaultGroupHandler");
}
this.flowObjectiveService = flowObjService;
- this.nsNextObjStore = nsNextObjStore;
- this.subnetNextObjStore = subnetNextObjStore;
- this.portNextObjStore = portNextObjStore;
+ this.nsNextObjStore = srManager.nsNextObjStore;
+ this.subnetNextObjStore = srManager.subnetNextObjStore;
+ this.portNextObjStore = srManager.portNextObjStore;
+ this.xConnectNextObjStore = srManager.xConnectNextObjStore;
this.srManager = srManager;
populateNeighborMaps();
@@ -141,8 +136,7 @@
* @param config interface to retrieve the device properties
* @param linkService link service object
* @param flowObjService flow objective service object
- * @param nsNextObjStore NeighborSet next objective store map
- * @param subnetNextObjStore subnet next objective store map
+ * @param srManager segment routing manager
* @throws DeviceConfigNotFoundException if the device configuration is not found
* @return default group handler type
*/
@@ -152,12 +146,6 @@
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService,
- EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore,
- EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore,
- EventuallyConsistentMap<PortNextObjectiveStoreKey,
- Integer> portNextObjStore,
SegmentRoutingManager srManager)
throws DeviceConfigNotFoundException {
// handle possible exception in the caller
@@ -165,18 +153,12 @@
return new DefaultEdgeGroupHandler(deviceId, appId, config,
linkService,
flowObjService,
- nsNextObjStore,
- subnetNextObjStore,
- portNextObjStore,
srManager
);
} else {
return new DefaultTransitGroupHandler(deviceId, appId, config,
linkService,
flowObjService,
- nsNextObjStore,
- subnetNextObjStore,
- portNextObjStore,
srManager);
}
}
@@ -194,6 +176,8 @@
* discovered on this device.
*
* @param newLink new neighbor link
+ * @param isMaster true if local instance is the master
+ *
*/
public void linkUp(Link newLink, boolean isMaster) {
@@ -296,6 +280,7 @@
* Performs group recovery procedures when a port goes down on this device.
*
* @param port port number that has gone down
+ * @param isMaster true if local instance is the master
*/
public void portDown(PortNumber port, boolean isMaster) {
if (portDeviceMap.get(port) == null) {
@@ -448,8 +433,8 @@
*/
public int getPortNextObjectiveId(PortNumber portNum, TrafficTreatment treatment,
TrafficSelector meta) {
- Integer nextId = portNextObjStore.
- get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
+ Integer nextId = portNextObjStore
+ .get(new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
if (nextId == null) {
log.trace("getPortNextObjectiveId in device{}: Next objective id "
+ "not found for {} and {} creating", deviceId, portNum);
@@ -458,7 +443,33 @@
new PortNextObjectiveStoreKey(deviceId, portNum, treatment));
if (nextId == null) {
log.warn("getPortNextObjectiveId: unable to create next obj"
- + "for dev:{} port{}", deviceId, portNum);
+ + "for dev:{} port:{}", deviceId, portNum);
+ return -1;
+ }
+ }
+ return nextId;
+ }
+
+ /**
+ * Returns the next objective ID of type broadcast associated with the VLAN
+ * cross-connection.
+ *
+ * @param vlanId VLAN ID for the cross-connection
+ * @return int if found or created, -1 if there are errors during the
+ * creation of the next objective
+ */
+ public int getXConnectNextObjectiveId(VlanId vlanId) {
+ Integer nextId = xConnectNextObjStore
+ .get(new XConnectNextObjectiveStoreKey(deviceId, vlanId));
+ if (nextId == null) {
+ log.trace("getXConnectNextObjectiveId: Next objective id "
+ + "not found for device {} and vlan {}. Creating", deviceId, vlanId);
+ createGroupsForXConnect(deviceId);
+ nextId = xConnectNextObjStore.get(
+ new XConnectNextObjectiveStoreKey(deviceId, vlanId));
+ if (nextId == null) {
+ log.warn("getXConnectNextObjectiveId: Next objective id "
+ + "not found for device {} and vlan {}.", deviceId, vlanId);
return -1;
}
}
@@ -655,7 +666,6 @@
/**
* Creates broadcast groups for all ports in the same configured subnet.
- *
*/
public void createGroupsFromSubnetConfig() {
Map<Ip4Prefix, List<PortNumber>> subnetPortMap =
@@ -700,6 +710,54 @@
});
}
+ /**
+ * Creates broadcast groups for VLAN cross-connect ports.
+ *
+ * @param deviceId the DPID of the switch
+ */
+ public void createGroupsForXConnect(DeviceId deviceId) {
+ Map<VlanId, List<ConnectPoint>> xConnectsForDevice = deviceConfig.getXConnects();
+
+ xConnectsForDevice.forEach((vlanId, connectPoints) -> {
+ // Only proceed the xConnect for given device
+ for (ConnectPoint connectPoint : connectPoints) {
+ if (!connectPoint.deviceId().equals(deviceId)) {
+ return;
+ }
+ }
+
+ // Check if the next obj is already in the store
+ XConnectNextObjectiveStoreKey key =
+ new XConnectNextObjectiveStoreKey(deviceId, vlanId);
+ if (xConnectNextObjStore.containsKey(key)) {
+ log.debug("Cross-connect Broadcast group for device {} and vlanId {} exists",
+ deviceId, vlanId);
+ return;
+ }
+
+ TrafficSelector metadata =
+ DefaultTrafficSelector.builder().matchVlanId(vlanId).build();
+ int nextId = flowObjectiveService.allocateNextId();
+
+ NextObjective.Builder nextObjBuilder = DefaultNextObjective
+ .builder().withId(nextId)
+ .withType(NextObjective.Type.BROADCAST).fromApp(appId)
+ .withMeta(metadata);
+
+ connectPoints.forEach(connectPoint -> {
+ TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
+ tBuilder.setOutput(connectPoint.port());
+ nextObjBuilder.addTreatment(tBuilder.build());
+ });
+
+ NextObjective nextObj = nextObjBuilder.add();
+ flowObjectiveService.next(deviceId, nextObj);
+ log.debug("createGroupsForXConnect: Submited next objective {} in device {}",
+ nextId, deviceId);
+ xConnectNextObjStore.put(key, nextId);
+ });
+ }
+
/**
* Create simple next objective for a single port. The treatments can include
@@ -730,11 +788,6 @@
portNextObjStore.put(key, nextId);
}
-
- public GroupKey getGroupKey(Object obj) {
- return new DefaultGroupKey(kryo.build().serialize(obj));
- }
-
/**
* Removes groups for the next objective ID given.
*
@@ -766,6 +819,9 @@
return false;
}
+ /**
+ * Removes all groups from all next objective stores.
+ */
public void removeAllGroups() {
for (Map.Entry<NeighborSetNextObjectiveStoreKey, Integer> entry:
nsNextObjStore.entrySet()) {
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 5bc7ede..9a93409 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
@@ -26,7 +26,6 @@
import org.onosproject.segmentrouting.SegmentRoutingManager;
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
import org.onosproject.segmentrouting.config.DeviceProperties;
-import org.onosproject.store.service.EventuallyConsistentMap;
/**
* Default ECMP group handler creation module for a transit device.
@@ -41,22 +40,13 @@
* 2) all ports to D3 + with no label push,
*/
public class DefaultTransitGroupHandler extends DefaultGroupHandler {
- // TODO Access stores through srManager
protected DefaultTransitGroupHandler(DeviceId deviceId,
ApplicationId appId,
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService,
- EventuallyConsistentMap<
- NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore,
- EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore,
- EventuallyConsistentMap<PortNextObjectiveStoreKey,
- Integer> portNextObjStore,
SegmentRoutingManager srManager) {
- super(deviceId, appId, config, linkService, flowObjService,
- nsNextObjStore, subnetNextObjStore, portNextObjStore, srManager);
+ super(deviceId, appId, config, linkService, flowObjService, srManager);
}
@Override
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSetNextObjectiveStoreKey.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSetNextObjectiveStoreKey.java
index 9ace531..ac33036 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSetNextObjectiveStoreKey.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/NeighborSetNextObjectiveStoreKey.java
@@ -21,22 +21,38 @@
import org.onosproject.net.DeviceId;
/**
- * Class definition of Key for Neighborset to NextObjective store.
+ * Key of Neighborset next objective store.
*/
public class NeighborSetNextObjectiveStoreKey {
private final DeviceId deviceId;
private final NeighborSet ns;
+ /**
+ * Constructs the key of neighbor set next objective store.
+ *
+ * @param deviceId device ID
+ * @param ns neighbor set
+ */
public NeighborSetNextObjectiveStoreKey(DeviceId deviceId,
NeighborSet ns) {
this.deviceId = deviceId;
this.ns = ns;
}
+ /**
+ * Returns the device ID in the key.
+ *
+ * @return device ID
+ */
public DeviceId deviceId() {
return this.deviceId;
}
+ /**
+ * Returns the neighbor set in the key.
+ *
+ * @return neighbor set
+ */
public NeighborSet neighborSet() {
return this.ns;
}
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 4b0d518..4f32226 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
@@ -31,7 +31,6 @@
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
import org.onosproject.segmentrouting.config.DeviceProperties;
import org.onosproject.segmentrouting.grouphandler.GroupBucketIdentifier.BucketOutputType;
-import org.onosproject.store.service.EventuallyConsistentMap;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.flow.DefaultTrafficTreatment;
@@ -51,33 +50,31 @@
private HashMap<PolicyGroupIdentifier, PolicyGroupIdentifier> dependentGroups = new HashMap<>();
/**
- * Policy group handler constructor.
+ * Constructs policy group handler.
*
* @param deviceId device identifier
* @param appId application identifier
* @param config interface to retrieve the device properties
* @param linkService link service object
* @param flowObjService flow objective service object
- * @param nsNextObjStore NeighborSet next objective store map
- * @param subnetNextObjStore subnet next objective store map
+ * @param srManager segment routing manager
*/
- // TODO Access stores through srManager
public PolicyGroupHandler(DeviceId deviceId,
ApplicationId appId,
DeviceProperties config,
LinkService linkService,
FlowObjectiveService flowObjService,
- EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
- Integer> nsNextObjStore,
- EventuallyConsistentMap<SubnetNextObjectiveStoreKey,
- Integer> subnetNextObjStore,
- EventuallyConsistentMap<PortNextObjectiveStoreKey,
- Integer> portNextObjStore,
SegmentRoutingManager srManager) {
- super(deviceId, appId, config, linkService, flowObjService,
- nsNextObjStore, subnetNextObjStore, portNextObjStore, srManager);
+ super(deviceId, appId, config, linkService, flowObjService, srManager);
}
+ /**
+ * Creates policy group chain.
+ *
+ * @param id unique identifier associated with the policy group
+ * @param params a list of policy group params
+ * @return policy group identifier
+ */
public PolicyGroupIdentifier createPolicyGroupChain(String id,
List<PolicyGroupParams> params) {
List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
@@ -222,69 +219,18 @@
}
//TODO: Use nextObjective APIs to handle the group chains
- /*@Override
- protected void handleGroupEvent(GroupEvent event) {
- if (event.type() == GroupEvent.Type.GROUP_ADDED) {
- if (dependentGroups.get(event.subject().appCookie()) != null) {
- PolicyGroupIdentifier dependentGroupKey = dependentGroups.get(event.subject().appCookie());
- dependentGroups.remove(event.subject().appCookie());
- boolean fullyResolved = true;
- for (GroupBucketIdentifier bucketId:
- dependentGroupKey.bucketIds()) {
- if (bucketId.type() != BucketOutputType.GROUP) {
- continue;
- }
- if (dependentGroups.containsKey(bucketId.outGroup())) {
- fullyResolved = false;
- break;
- }
- }
+ /*
+ @Override
+ protected void handleGroupEvent(GroupEvent event) {}
+ */
- if (fullyResolved) {
- List<GroupBucket> outBuckets = new ArrayList<GroupBucket>();
- for (GroupBucketIdentifier bucketId:
- dependentGroupKey.bucketIds()) {
- TrafficTreatment.Builder tBuilder =
- DefaultTrafficTreatment.builder();
- if (bucketId.label() != NeighborSet.NO_EDGE_LABEL) {
- tBuilder.pushMpls()
- .setMpls(MplsLabel.
- mplsLabel(bucketId.label()));
- }
- //TODO: BoS
- if (bucketId.type() == BucketOutputType.PORT) {
- DeviceId neighbor = portDeviceMap.
- get(bucketId.outPort());
- tBuilder.setOutput(bucketId.outPort())
- .setEthDst(deviceConfig.
- getDeviceMac(neighbor))
- .setEthSrc(nodeMacAddr);
- } else {
- if (groupService.
- getGroup(deviceId,
- getGroupKey(bucketId.
- outGroup())) == null) {
- throw new IllegalStateException();
- }
- GroupId indirectGroupId = groupService.
- getGroup(deviceId,
- getGroupKey(bucketId.
- outGroup())).id();
- tBuilder.group(indirectGroupId);
- }
- outBuckets.add(DefaultGroupBucket.
- createSelectGroupBucket(tBuilder.build()));
- }
- GroupDescription desc = new
- DefaultGroupDescription(deviceId,
- GroupDescription.Type.SELECT,
- new GroupBuckets(outBuckets));
- groupService.addGroup(desc);
- }
- }
- }
- }*/
-
+ /**
+ * Generates policy group key.
+ *
+ * @param id unique identifier associated with the policy group
+ * @param params a list of policy group params
+ * @return policy group identifier
+ */
public PolicyGroupIdentifier generatePolicyGroupKey(String id,
List<PolicyGroupParams> params) {
List<GroupBucketIdentifier> bucketIds = new ArrayList<>();
@@ -354,6 +300,11 @@
return innermostGroupkey;
}
+ /**
+ * Removes policy group chain.
+ *
+ * @param key policy group identifier
+ */
public void removeGroupChain(PolicyGroupIdentifier key) {
checkArgument(key != null);
List<PolicyGroupIdentifier> groupsToBeDeleted = new ArrayList<>();
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupIdentifier.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupIdentifier.java
index 44a0a2c..ca283f0 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupIdentifier.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PolicyGroupIdentifier.java
@@ -28,7 +28,7 @@
private List<GroupBucketIdentifier> bucketIds;
/**
- * Constructor.
+ * Constructs policy group identifier.
*
* @param id unique identifier associated with the policy group
* @param input policy group params associated with this group
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PortNextObjectiveStoreKey.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PortNextObjectiveStoreKey.java
index 5555565..ec25ec3 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PortNextObjectiveStoreKey.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/PortNextObjectiveStoreKey.java
@@ -7,15 +7,23 @@
import java.util.Objects;
/**
- * Class definition of Key for Device/Port to NextObjective store. Since there
- * can be multiple next objectives to the same physical port, we differentiate
- * between them by including the treatment in the key.
+ * Key of Device/Port to NextObjective store.
+ *
+ * Since there can be multiple next objectives to the same physical port,
+ * we differentiate between them by including the treatment in the key.
*/
public class PortNextObjectiveStoreKey {
private final DeviceId deviceId;
private final PortNumber portNum;
private final TrafficTreatment treatment;
+ /**
+ * Constructs the key of port next objective store.
+ *
+ * @param deviceId device ID
+ * @param portNum port number
+ * @param treatment treatment that will be applied to the interface
+ */
public PortNextObjectiveStoreKey(DeviceId deviceId, PortNumber portNum,
TrafficTreatment treatment) {
this.deviceId = deviceId;
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
index d6b16c7..8e5c3ce 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/SubnetNextObjectiveStoreKey.java
@@ -22,12 +22,18 @@
import java.util.Objects;
/**
- * Class definition of Key for Subnet to NextObjective store.
+ * Key of Subnet to NextObjective store.
*/
public class SubnetNextObjectiveStoreKey {
private final DeviceId deviceId;
private final IpPrefix prefix;
+ /**
+ * Constructs the key of subnet next objective store.
+ *
+ * @param deviceId device ID
+ * @param prefix subnet information
+ */
public SubnetNextObjectiveStoreKey(DeviceId deviceId,
IpPrefix prefix) {
this.deviceId = deviceId;
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/XConnectNextObjectiveStoreKey.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/XConnectNextObjectiveStoreKey.java
new file mode 100644
index 0000000..f3da880
--- /dev/null
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/grouphandler/XConnectNextObjectiveStoreKey.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 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.VlanId;
+import org.onosproject.net.DeviceId;
+
+import java.util.Objects;
+
+/**
+ * Key of VLAN cross-connect next objective store.
+ */
+public class XConnectNextObjectiveStoreKey {
+ private final DeviceId deviceId;
+ private final VlanId vlanId;
+
+ /**
+ * Constructs the key of cross-connect next objective store.
+ *
+ * @param deviceId device ID of the VLAN cross-connection
+ * @param vlanId VLAN ID of the VLAN cross-connection
+ */
+ public XConnectNextObjectiveStoreKey(DeviceId deviceId, VlanId vlanId) {
+ this.deviceId = deviceId;
+ this.vlanId = vlanId;
+ }
+
+ /**
+ * Returns the device ID of this key.
+ *
+ * @return device ID
+ */
+ public DeviceId deviceId() {
+ return this.deviceId;
+ }
+
+ /**
+ * Returns the VLAN ID of this key.
+ *
+ * @return VLAN ID
+ */
+ public VlanId vlanId() {
+ return this.vlanId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof XConnectNextObjectiveStoreKey)) {
+ return false;
+ }
+ XConnectNextObjectiveStoreKey that =
+ (XConnectNextObjectiveStoreKey) o;
+ return (Objects.equals(this.deviceId, that.deviceId) &&
+ Objects.equals(this.vlanId, that.vlanId));
+ }
+
+ // The list of neighbor ids and label are used for comparison.
+ @Override
+ public int hashCode() {
+ return Objects.hash(deviceId, vlanId);
+ }
+
+ @Override
+ public String toString() {
+ return "Device: " + deviceId + " VlanId: " + vlanId;
+ }
+}
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java
index 8e50887..17fd6e6 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/PolicyCodec.java
@@ -21,6 +21,9 @@
import org.onosproject.segmentrouting.Policy;
import org.onosproject.segmentrouting.TunnelPolicy;
+/**
+ * Codec of Policy class.
+ */
public final class PolicyCodec extends JsonCodec<Policy> {
// JSON field names
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelCodec.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelCodec.java
index 2f85afd..c9e4a32 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelCodec.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/web/TunnelCodec.java
@@ -26,6 +26,9 @@
import java.util.ArrayList;
import java.util.List;
+/**
+ * Codec of Tunnel class.
+ */
public final class TunnelCodec extends JsonCodec<Tunnel> {
// JSON field names
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2GroupHandler.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2GroupHandler.java
index 2f95ce8..828b778 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2GroupHandler.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2GroupHandler.java
@@ -1,5 +1,6 @@
package org.onosproject.driver.pipeline;
+import com.google.common.base.Objects;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.RemovalCause;
@@ -69,12 +70,18 @@
* L2 Flood Groups have <4bits-4><12bits-vlanid><16bits-index>
* L3 VPN Groups have <4bits-9><4bits-2><24bits-index>
*/
- private static final int L2INTERFACEMASK = 0x0;
- private static final int L3UNICASTMASK = 0x20000000;
- private static final int MPLSINTERFACEMASK = 0x90000000;
- private static final int L3ECMPMASK = 0x70000000;
- private static final int L2FLOODMASK = 0x40000000;
- private static final int L3VPNMASK = 0x92000000;
+ private static final int L2_INTERFACE_TYPE = 0x00000000;
+ private static final int L3_UNICAST_TYPE = 0x20000000;
+ private static final int MPLS_INTERFACE_TYPE = 0x90000000;
+ private static final int MPLS_L3VPN_SUBTYPE = 0x92000000;
+ private static final int L3_ECMP_TYPE = 0x70000000;
+ private static final int L2_FLOOD_TYPE = 0x40000000;
+
+ private static final int TYPE_MASK = 0x0fffffff;
+ private static final int SUBTYPE_MASK = 0x00ffffff;
+
+ private static final int PORT_LOWER_BITS_MASK = 0x3f;
+ private static final long PORT_HIGHER_BITS_MASK = ~PORT_LOWER_BITS_MASK;
private final Logger log = getLogger(getClass());
private ServiceDirectory serviceDirectory;
@@ -252,18 +259,9 @@
+ " instruction in simple nextObjectives: {}", ins.type());
}
}
- //use the vlanid associated with the port
- VlanId vlanid = port2Vlan.get(portNum);
- if (vlanid == null && nextObj.meta() != null) {
- // use metadata vlan info if available
- Criterion vidCriterion = nextObj.meta().getCriterion(Criterion.Type.VLAN_VID);
- if (vidCriterion != null) {
- vlanid = ((VlanIdCriterion) vidCriterion).vlanId();
- }
- }
-
- if (vlanid == null) {
+ VlanId vlanId = readVlanFromMeta(nextObj);
+ if (vlanId == null) {
log.error("Driver cannot process an L2/L3 group chain without "
+ "egress vlan information for dev: {} port:{}",
deviceId, portNum);
@@ -271,11 +269,11 @@
}
// assemble information for ofdpa l2interface group
- Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum.toLong();
+ int l2groupId = L2_INTERFACE_TYPE | (vlanId.toShort() << 16) | (int) portNum.toLong();
// a globally unique groupkey that is different for ports in the same devices
// but different for the same portnumber on different devices. Also different
// for the various group-types created out of the same next objective.
- int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum.toLong());
+ int l2gk = l2InterfaceGroupKey(deviceId, vlanId, portNum.toLong());
final GroupKey l2groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l2gk));
// create group description for the l2interfacegroup
@@ -399,20 +397,20 @@
}
// assemble information for ofdpa l2interface group
- Integer l2groupId = L2INTERFACEMASK | (vlanid.toShort() << 16) | (int) portNum;
+ int l2groupId = L2_INTERFACE_TYPE | (vlanid.toShort() << 16) | (int) portNum;
// a globally unique groupkey that is different for ports in the same devices
// but different for the same portnumber on different devices. Also different
// for the various group-types created out of the same next objective.
- int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum);
+ int l2gk = l2InterfaceGroupKey(deviceId, vlanid, portNum);
final GroupKey l2groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l2gk));
// assemble information for outer group
GroupDescription outerGrpDesc = null;
if (mpls) {
// outer group is MPLSInteface
- Integer mplsgroupId = MPLSINTERFACEMASK | (int) portNum;
+ int mplsgroupId = MPLS_INTERFACE_TYPE | (int) portNum;
// using mplsinterfacemask in groupkey to differentiate from l2interface
- int mplsgk = MPLSINTERFACEMASK | (0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum));
+ int mplsgk = MPLS_INTERFACE_TYPE | (SUBTYPE_MASK & (deviceId.hashCode() << 8 | (int) portNum));
final GroupKey mplsgroupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(mplsgk));
outerTtb.group(new DefaultGroupId(l2groupId));
// create the mpls-interface group description to wait for the
@@ -432,8 +430,8 @@
mplsgroupkey, nextId);
} else {
// outer group is L3Unicast
- Integer l3groupId = L3UNICASTMASK | (int) portNum;
- int l3gk = L3UNICASTMASK | (0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum));
+ int l3groupId = L3_UNICAST_TYPE | (int) portNum;
+ int l3gk = L3_UNICAST_TYPE | (TYPE_MASK & (deviceId.hashCode() << 8 | (int) portNum));
final GroupKey l3groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3gk));
outerTtb.group(new DefaultGroupId(l2groupId));
// create the l3unicast group description to wait for the
@@ -488,14 +486,11 @@
// break up broadcast next objective to multiple groups
Collection<TrafficTreatment> buckets = nextObj.next();
- // Read VLAN information from the metadata
- TrafficSelector metadata = nextObj.meta();
- Criterion criterion = metadata.getCriterion(Criterion.Type.VLAN_VID);
- if (criterion == null) {
+ VlanId vlanId = readVlanFromMeta(nextObj);
+ if (vlanId == null) {
log.warn("Required VLAN ID info in nextObj metadata but not found. Aborting");
return;
}
- VlanId vlanId = ((VlanIdCriterion) criterion).vlanId();
// each treatment is converted to an L2 interface group
List<GroupDescription> l2interfaceGroupDescs = new ArrayList<>();
@@ -520,26 +515,15 @@
portNum = ((Instructions.OutputInstruction) ins).port();
newTreatment.add(ins);
} else {
- log.debug("TrafficTreatment of type {} not permitted in "
- + " broadcast nextObjective", ins.type());
+ log.debug("TrafficTreatment of type {} not permitted in " +
+ " broadcast nextObjective", ins.type());
}
}
- // Ensure that all ports of this broadcast nextObj are in the same vlan
- // XXX maybe HA issue here?
- VlanId expectedVlanId = port2Vlan.putIfAbsent(portNum, vlanId);
- if (expectedVlanId != null && !vlanId.equals(expectedVlanId)) {
- log.error("Driver requires all ports in a broadcast nextObj "
- + "to be in the same vlan. Different vlans found "
- + "{} and {}. Aborting group creation", vlanId, expectedVlanId);
- return;
- }
-
-
// assemble info for l2 interface group
- int l2gk = 0x0ffffff & (deviceId.hashCode() << 8 | (int) portNum.toLong());
+ int l2gk = l2InterfaceGroupKey(deviceId, vlanId, portNum.toLong());
final GroupKey l2groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l2gk));
- Integer l2groupId = L2INTERFACEMASK | (vlanId.toShort() << 16) |
+ int l2groupId = L2_INTERFACE_TYPE | (vlanId.toShort() << 16) |
(int) portNum.toLong();
GroupBucket l2interfaceGroupBucket =
DefaultGroupBucket.createIndirectGroupBucket(newTreatment.build());
@@ -565,8 +549,8 @@
}
// assemble info for l2 flood group
- Integer l2floodgroupId = L2FLOODMASK | (vlanId.toShort() << 16) | nextObj.id();
- int l2floodgk = L2FLOODMASK | nextObj.id() << 12;
+ Integer l2floodgroupId = L2_FLOOD_TYPE | (vlanId.toShort() << 16) | nextObj.id();
+ int l2floodgk = L2_FLOOD_TYPE | nextObj.id() << 12;
final GroupKey l2floodgroupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l2floodgk));
// collection of group buckets pointing to all the l2 interface groups
List<GroupBucket> l2floodBuckets = new ArrayList<>();
@@ -610,8 +594,6 @@
}
}
-
-
/**
* As per the OFDPA 2.0 TTP, packets are sent out of ports by using
* a chain of groups. The hashed Next Objective passed in by the application
@@ -643,7 +625,7 @@
.createSelectGroupBucket(ttb.build());
l3ecmpGroupBuckets.add(sbucket);
}
- int l3ecmpGroupId = L3ECMPMASK | nextObj.id() << 12;
+ int l3ecmpGroupId = L3_ECMP_TYPE | nextObj.id() << 12;
GroupKey l3ecmpGroupKey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3ecmpGroupId));
GroupDescription l3ecmpGroupDesc =
new DefaultGroupDescription(
@@ -752,8 +734,8 @@
onelabelGroupInfo.outerGrpDesc.givenGroupId()));
GroupBucket l3vpnGrpBkt =
DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build());
- int l3vpngroupId = L3VPNMASK | l3vpnindex.incrementAndGet();
- int l3vpngk = L3VPNMASK | nextObj.id() << 12 | l3vpnindex.get();
+ int l3vpngroupId = MPLS_L3VPN_SUBTYPE | l3vpnindex.incrementAndGet();
+ int l3vpngk = MPLS_L3VPN_SUBTYPE | nextObj.id() << 12 | l3vpnindex.get();
GroupKey l3vpngroupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3vpngk));
GroupDescription l3vpnGroupDesc =
new DefaultGroupDescription(
@@ -821,7 +803,7 @@
GroupBucket sbucket = DefaultGroupBucket.createSelectGroupBucket(ttb.build());
// recreate the original L3 ECMP group id and description
- int l3ecmpGroupId = L3ECMPMASK | nextObjective.id() << 12;
+ int l3ecmpGroupId = L3_ECMP_TYPE | nextObjective.id() << 12;
GroupKey l3ecmpGroupKey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3ecmpGroupId));
// Although GroupDescriptions are not necessary for adding buckets to
@@ -1049,6 +1031,32 @@
}
}
+ private VlanId readVlanFromMeta(NextObjective nextObj) {
+ TrafficSelector metadata = nextObj.meta();
+ Criterion criterion = metadata.getCriterion(Criterion.Type.VLAN_VID);
+ return (criterion == null)
+ ? null : ((VlanIdCriterion) criterion).vlanId();
+ }
+
+ /**
+ * Returns a hash as the L2 Interface Group Key.
+ *
+ * Keep the lower 6-bit for port since port number usually smaller than 64.
+ * Hash other information into remaining 28 bits.
+ *
+ * @param deviceId Device ID
+ * @param vlanId VLAN ID
+ * @param portNumber Port number
+ * @return L2 interface group key
+ */
+ private int l2InterfaceGroupKey(
+ DeviceId deviceId, VlanId vlanId, long portNumber) {
+ int portLowerBits = (int) portNumber & PORT_LOWER_BITS_MASK;
+ long portHigherBits = portNumber & PORT_HIGHER_BITS_MASK;
+ int hash = Objects.hashCode(deviceId, vlanId, portHigherBits);
+ return L2_INTERFACE_TYPE | (TYPE_MASK & hash << 6) | portLowerBits;
+ }
+
private class InnerGroupListener implements GroupListener {
@Override
public void event(GroupEvent event) {
diff --git a/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java b/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
index cce9741..e4b7ef5 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/OFDPA2Pipeline.java
@@ -305,29 +305,35 @@
}
VlanId assignedVlan = null;
- if (vidCriterion != null && vidCriterion.vlanId() == VlanId.NONE) {
- // untagged packets are assigned vlans in OF-DPA
- if (filt.meta() == null) {
- log.error("Missing metadata in filtering objective required "
- + "for vlan assignment in dev {}", deviceId);
- fail(filt, ObjectiveError.BADPARAMS);
- return;
- }
- for (Instruction i : filt.meta().allInstructions()) {
- if (i instanceof ModVlanIdInstruction) {
- assignedVlan = ((ModVlanIdInstruction) i).vlanId();
+ // For VLAN cross-connect packets, use the configured VLAN
+ if (vidCriterion != null) {
+ if (vidCriterion.vlanId() != VlanId.NONE) {
+ assignedVlan = vidCriterion.vlanId();
+
+ // For untagged packets, assign a VLAN ID
+ } else {
+ if (filt.meta() == null) {
+ log.error("Missing metadata in filtering objective required " +
+ "for vlan assignment in dev {}", deviceId);
+ fail(filt, ObjectiveError.BADPARAMS);
+ return;
}
- }
- if (assignedVlan == null) {
- log.error("Driver requires an assigned vlan-id to tag incoming "
- + "untagged packets. Not processing vlan filters on "
- + "device {}", deviceId);
- fail(filt, ObjectiveError.BADPARAMS);
- return;
+ for (Instruction i : filt.meta().allInstructions()) {
+ if (i instanceof ModVlanIdInstruction) {
+ assignedVlan = ((ModVlanIdInstruction) i).vlanId();
+ }
+ }
+ if (assignedVlan == null) {
+ log.error("Driver requires an assigned vlan-id to tag incoming "
+ + "untagged packets. Not processing vlan filters on "
+ + "device {}", deviceId);
+ fail(filt, ObjectiveError.BADPARAMS);
+ return;
+ }
}
}
- if (ethCriterion == null) {
+ if (ethCriterion == null || ethCriterion.mac().equals(MacAddress.NONE)) {
log.debug("filtering objective missing dstMac, cannot program TMAC table");
} else {
for (FlowRule tmacRule : processEthDstFilter(portCriterion, ethCriterion,
@@ -340,8 +346,8 @@
}
if (ethCriterion == null || vidCriterion == null) {
- log.debug("filtering objective missing dstMac or vlan, cannot program"
- + "Vlan Table");
+ log.debug("filtering objective missing dstMac or VLAN, "
+ + "cannot program VLAN Table");
} else {
for (FlowRule vlanRule : processVlanIdFilter(portCriterion, vidCriterion,
assignedVlan,
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 31fa0ef..1277c75 100644
--- a/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ b/drivers/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
@@ -837,7 +837,6 @@
if (vlanIdCriterion.vlanId() != VlanId.NONE) {
selector.matchVlanId(vlanIdCriterion.vlanId());
selector.matchInPort(p.port());
- treatment.deferred().popVlan();
} else {
selector.matchInPort(p.port());
treatment.immediate().pushVlan().setVlanId(assignedVlan);
@@ -887,25 +886,31 @@
}
VlanId assignedVlan = null;
- if (vlanIdCriterion != null && vlanIdCriterion.vlanId() == VlanId.NONE) {
- // Assign a VLAN ID to untagged packets
- if (filt.meta() == null) {
- log.error("Missing metadata in filtering objective required "
- + "for vlan assignment in dev {}", deviceId);
- fail(filt, ObjectiveError.BADPARAMS);
- return;
- }
- for (Instruction i : filt.meta().allInstructions()) {
- if (i instanceof ModVlanIdInstruction) {
- assignedVlan = ((ModVlanIdInstruction) i).vlanId();
+ if (vlanIdCriterion != null) {
+ // For VLAN cross-connect packets, use the configured VLAN
+ if (vlanIdCriterion.vlanId() != VlanId.NONE) {
+ assignedVlan = vlanIdCriterion.vlanId();
+
+ // For untagged packets, assign a VLAN ID
+ } else {
+ if (filt.meta() == null) {
+ log.error("Missing metadata in filtering objective required " +
+ "for vlan assignment in dev {}", deviceId);
+ fail(filt, ObjectiveError.BADPARAMS);
+ return;
}
- }
- if (assignedVlan == null) {
- log.error("Driver requires an assigned vlan-id to tag incoming "
- + "untagged packets. Not processing vlan filters on "
- + "device {}", deviceId);
- fail(filt, ObjectiveError.BADPARAMS);
- return;
+ for (Instruction i : filt.meta().allInstructions()) {
+ if (i instanceof ModVlanIdInstruction) {
+ assignedVlan = ((ModVlanIdInstruction) i).vlanId();
+ }
+ }
+ if (assignedVlan == null) {
+ log.error("Driver requires an assigned vlan-id to tag incoming "
+ + "untagged packets. Not processing vlan filters on "
+ + "device {}", deviceId);
+ fail(filt, ObjectiveError.BADPARAMS);
+ return;
+ }
}
}
@@ -923,9 +928,9 @@
}
}
- if (ethCriterion == null || vlanIdCriterion == null) {
- log.debug("filtering objective missing dstMac or vlan, cannot program"
- + "Vlan Table");
+ if (vlanIdCriterion == null) {
+ log.debug("filtering objective missing VLAN ID criterion, "
+ + "cannot program VLAN Table");
} else {
for (FlowRule vlanRule : processVlanIdFilter(vlanIdCriterion,
filt,
diff --git a/tools/test/configs/network-cfg-2x2-leaf-spine.json b/tools/package/config/samples/network-cfg-fabric2x2-xconnect.json
similarity index 90%
rename from tools/test/configs/network-cfg-2x2-leaf-spine.json
rename to tools/package/config/samples/network-cfg-fabric2x2-xconnect.json
index 828d273..ef73261 100644
--- a/tools/test/configs/network-cfg-2x2-leaf-spine.json
+++ b/tools/package/config/samples/network-cfg-fabric2x2-xconnect.json
@@ -4,7 +4,9 @@
"interfaces" : [
{
"ips" : [ "10.0.1.254/24" ],
- "mac" : "08:9e:01:82:38:68",
+ "vlan" : "-1"
+ },
+ {
"vlan" : "100"
}
]
@@ -13,17 +15,22 @@
"interfaces" : [
{
"ips" : [ "10.0.1.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
+ "of:0000000000000001/5" : {
+ "interfaces" : [
+ {
+ "vlan" : "100"
+ }
+ ]
+ },
"of:0000000000000002/3" : {
"interfaces" : [
{
"ips" : [ "10.0.2.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -31,8 +38,7 @@
"interfaces" : [
{
"ips" : [ "10.0.2.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
}
diff --git a/tools/test/configs/network-cfg-2x2-leaf-spine.json b/tools/package/config/samples/network-cfg-fabric2x2.json
similarity index 89%
copy from tools/test/configs/network-cfg-2x2-leaf-spine.json
copy to tools/package/config/samples/network-cfg-fabric2x2.json
index 828d273..d4ab3d1 100644
--- a/tools/test/configs/network-cfg-2x2-leaf-spine.json
+++ b/tools/package/config/samples/network-cfg-fabric2x2.json
@@ -4,8 +4,7 @@
"interfaces" : [
{
"ips" : [ "10.0.1.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -13,8 +12,7 @@
"interfaces" : [
{
"ips" : [ "10.0.1.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -22,8 +20,7 @@
"interfaces" : [
{
"ips" : [ "10.0.2.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -31,8 +28,7 @@
"interfaces" : [
{
"ips" : [ "10.0.2.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
}
diff --git a/tools/test/configs/network-cfg-4x4-leaf-spine.json b/tools/package/config/samples/network-cfg-fabric4x4.json
similarity index 89%
rename from tools/test/configs/network-cfg-4x4-leaf-spine.json
rename to tools/package/config/samples/network-cfg-fabric4x4.json
index 4efcf97..958e124 100644
--- a/tools/test/configs/network-cfg-4x4-leaf-spine.json
+++ b/tools/package/config/samples/network-cfg-fabric4x4.json
@@ -4,8 +4,7 @@
"interfaces" : [
{
"ips" : [ "10.0.1.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -13,8 +12,7 @@
"interfaces" : [
{
"ips" : [ "10.0.1.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -22,8 +20,7 @@
"interfaces" : [
{
"ips" : [ "10.0.2.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -31,8 +28,7 @@
"interfaces" : [
{
"ips" : [ "10.0.2.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -40,8 +36,7 @@
"interfaces" : [
{
"ips" : [ "10.0.3.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -49,8 +44,7 @@
"interfaces" : [
{
"ips" : [ "10.0.3.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -58,8 +52,7 @@
"interfaces" : [
{
"ips" : [ "10.0.4.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
},
@@ -67,8 +60,7 @@
"interfaces" : [
{
"ips" : [ "10.0.4.254/24" ],
- "mac" : "08:9e:01:82:38:68",
- "vlan" : "100"
+ "vlan" : "-1"
}
]
}