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/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) {