Handling multiple layers of spines.
Also in this commit:
- Triggering swap group creation and accounting for it in DestinationSet
- Fixes in ofdpa2 and ofdpa3 pipeline to allow SR Continue operation
- Renaming mplsSet in DestinationSet to notBos
- Removing unused RandomDestinationSet
- Bug fix in ofdpa driver for swap group chain creation
- Bug fix in ofdpa driver for verify group operation
- Better internal bookeeping of device ports and associated neighbors
Change-Id: I2b8f1c4c0b305ef847d57ca7a5320943e06d190d
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2GroupHandler.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2GroupHandler.java
index 401e924..078e120 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2GroupHandler.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/CpqdOfdpa2GroupHandler.java
@@ -99,8 +99,9 @@
portNum = ((Instructions.OutputInstruction) ins).port().toLong();
innerTtb.add(ins);
} else {
- log.warn("Driver does not handle this type of TrafficTreatment"
- + " instruction in nextObjectives: {}", ins.type());
+ log.debug("Driver does not handle this type of TrafficTreatment"
+ + " instruction in l2l3chain: {} - {}", ins.type(),
+ ins);
}
}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2GroupHandler.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2GroupHandler.java
index fdee8d6..2c2f3ba 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2GroupHandler.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2GroupHandler.java
@@ -245,14 +245,14 @@
/**
* As per the OFDPA 2.0 TTP, packets are sent out of ports by using
- * a chain of groups. The simple Next Objective passed
- * in by the application has to be broken up into a group chain
- * comprising of an L3 Unicast Group that points to an L2 Interface
- * Group which in-turn points to an output port or an MPLS Interface Group
- * that points to an L2 Interface Group. In some cases, the simple
- * next Objective can just be an L2 interface without the need for chaining.
- * Further, if the label is set to the Next objective then the Group chain
- * MPLS Swap - MPLS Interface - L2 Interface is created
+ * a chain of groups. The simple Next Objective passed in by the application
+ * is broken up into a group chain. The following chains can be created
+ * depending on the parameters in the Next Objective.
+ * 1. L2 Interface group (no chaining)
+ * 2. L3 Unicast group -> L2 Interface group
+ * 3. MPLS Interface group -> L2 Interface group
+ * 4. MPLS Swap group -> MPLS Interface group -> L2 Interface group
+ * 5. PW initiation group chain
*
* @param nextObj the nextObjective of type SIMPLE
*/
@@ -275,7 +275,6 @@
mplsSwap = true;
mplsLabel = ((L2ModificationInstruction.ModMplsLabelInstruction) l2ins).label();
}
-
}
}
@@ -284,24 +283,20 @@
return;
}
- boolean isMpls = false;
- // In order to understand if it is a pseudo wire related
+ // In order to understand if it is a pseudowire related
// next objective we look for the tunnel id in the meta.
boolean isPw = false;
if (nextObj.meta() != null) {
- isMpls = isNotMplsBos(nextObj.meta());
-
TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) nextObj
.meta()
.getCriterion(TUNNEL_ID);
if (tunnelIdCriterion != null) {
isPw = true;
}
-
}
if (mplsSwap && !isPw) {
- log.debug("Creating a MPLS Swap - MPLS Interface - L2 Interface group chain.");
+ log.debug("Creating a MPLS Swap -> MPLS Interface -> L2 Interface group chain.");
// break up simple next objective to GroupChain objects
GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(),
@@ -314,38 +309,44 @@
}
Deque<GroupKey> gkeyChain = new ArrayDeque<>();
- gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie());
- gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie());
+ gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie()); // l2 interface
+ gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie()); // mpls interface
// creating the mpls swap group and adding it to the chain
- GroupChainElem groupChainElem;
- GroupKey groupKey;
- GroupDescription groupDescription;
int nextGid = groupInfo.nextGroupDesc().givenGroupId();
int index = getNextAvailableIndex();
- groupDescription = createMplsSwap(
+ GroupDescription swapGroupDescription = createMplsSwap(
nextGid,
OfdpaMplsGroupSubType.MPLS_SWAP_LABEL,
index,
mplsLabel,
nextObj.appId()
);
+ // ensure swap group is added after L2L3 chain
+ GroupKey swapGroupKey = swapGroupDescription.appCookie();
+ GroupChainElem swapChainElem = new GroupChainElem(swapGroupDescription,
+ 1, false, deviceId);
+ updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), swapChainElem);
+ gkeyChain.addFirst(swapGroupKey);
- groupKey = new DefaultGroupKey(Ofdpa2Pipeline.appKryo.serialize(index));
- groupChainElem = new GroupChainElem(groupDescription, 1, false, deviceId);
- updatePendingGroups(groupInfo.nextGroupDesc().appCookie(), groupChainElem);
- gkeyChain.addFirst(groupKey);
-
- // create a new List from singletonList that is mutable
- OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(Collections.singletonList(gkeyChain), nextObj);
- updatePendingNextObjective(groupInfo.nextGroupDesc().appCookie(), ofdpaGrp);
+ // ensure nextObjective waits on the outermost groupKey
+ List<Deque<GroupKey>> allGroupKeys = Lists.newArrayList();
+ allGroupKeys.add(gkeyChain);
+ OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj);
+ updatePendingNextObjective(swapGroupKey, ofdpaGrp);
// now we are ready to send the l2 groupDescription (inner), as all the stores
// that will get async replies have been updated. By waiting to update
// the stores, we prevent nasty race conditions.
groupService.addGroup(groupInfo.innerMostGroupDesc());
} else if (!isPw) {
+ boolean isMpls = false;
+ if (nextObj.meta() != null) {
+ isMpls = isNotMplsBos(nextObj.meta());
+ }
+ log.debug("Creating a {} -> L2 Interface group chain.",
+ (isMpls) ? "MPLS Interface" : "L3 Unicast");
// break up simple next objective to GroupChain objects
GroupInfo groupInfo = createL2L3Chain(treatment, nextObj.id(),
nextObj.appId(), isMpls,
@@ -359,8 +360,9 @@
Deque<GroupKey> gkeyChain = new ArrayDeque<>();
gkeyChain.addFirst(groupInfo.innerMostGroupDesc().appCookie());
gkeyChain.addFirst(groupInfo.nextGroupDesc().appCookie());
- OfdpaNextGroup ofdpaGrp =
- new OfdpaNextGroup(Collections.singletonList(gkeyChain), nextObj);
+ List<Deque<GroupKey>> allGroupKeys = Lists.newArrayList();
+ allGroupKeys.add(gkeyChain);
+ OfdpaNextGroup ofdpaGrp = new OfdpaNextGroup(allGroupKeys, nextObj);
// store l3groupkey with the ofdpaNextGroup for the nextObjective that depends on it
updatePendingNextObjective(groupInfo.nextGroupDesc().appCookie(), ofdpaGrp);
@@ -424,9 +426,7 @@
int index,
MplsLabel mplsLabel,
ApplicationId applicationId) {
-
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
-
treatment.setMpls(mplsLabel);
// We point the group to the next group.
@@ -436,16 +436,14 @@
// Finally we build the group description.
int groupId = makeMplsLabelGroupId(subtype, index);
GroupKey groupKey = new DefaultGroupKey(
- Ofdpa2Pipeline.appKryo.serialize(index)
- );
+ Ofdpa2Pipeline.appKryo.serialize(index));
return new DefaultGroupDescription(
deviceId,
INDIRECT,
new GroupBuckets(Collections.singletonList(groupBucket)),
groupKey,
groupId,
- applicationId
- );
+ applicationId);
}
/**
@@ -542,7 +540,8 @@
innerTtb.add(ins);
} else {
log.debug("Driver does not handle this type of TrafficTreatment"
- + " instruction in nextObjectives: {}", ins.type());
+ + " instruction in l2l3chain: {} - {}", ins.type(),
+ ins);
}
}
@@ -963,7 +962,7 @@
}
Deque<GroupKey> gKeyChain = new ArrayDeque<>();
- // XXX we only deal with 0 and 1 label push right now
+ // here we only deal with 0 and 1 label push
if (labelsPushed == 0) {
GroupInfo noLabelGroupInfo;
TrafficSelector metaSelector = nextObj.meta();
@@ -1661,12 +1660,17 @@
// Detect situation where the next data has more buckets
// (not duplicates) respect to the next objective
- if (allActiveKeys.size() > nextObjective.next().size()) {
+ if (allActiveKeys.size() > nextObjective.next().size() &&
+ // ignore specific case of empty group
+ !(nextObjective.next().size() == 0 && allActiveKeys.size() == 1
+ && allActiveKeys.get(0).size() == 1)) {
log.warn("Mismatch detected between next and flowobjstore for device {}: " +
- "nextId:{}, nextObjective-size:{} next-size:{} .. correcting",
- deviceId, nextObjective.id(), nextObjective.next().size(), allActiveKeys.size());
- List<Integer> otherIndices = indicesToRemoveFromNextGroup(allActiveKeys, nextObjective,
- groupService, deviceId);
+ "nextId:{}, nextObjective-size:{} next-size:{} .. correcting",
+ deviceId, nextObjective.id(), nextObjective.next().size(),
+ allActiveKeys.size());
+ List<Integer> otherIndices =
+ indicesToRemoveFromNextGroup(allActiveKeys, nextObjective,
+ groupService, deviceId);
// Filter out the indices not present
otherIndices = otherIndices.stream()
.filter(index -> !indicesToRemove.contains(index))
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
index 2e65d6d..567c355 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
@@ -1164,7 +1164,6 @@
TrafficSelector selector = fwd.selector();
EthTypeCriterion ethType =
(EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
- boolean popMpls = false;
boolean emptyGroup = false;
int forTableId;
TrafficSelector.Builder filteredSelector = DefaultTrafficSelector.builder();
@@ -1233,7 +1232,6 @@
for (Instruction instr : fwd.treatment().allInstructions()) {
if (instr instanceof L2ModificationInstruction &&
((L2ModificationInstruction) instr).subtype() == L2SubType.MPLS_POP) {
- popMpls = true;
// OF-DPA does not pop in MPLS table in some cases. For the L3 VPN, it requires
// setting the MPLS_TYPE so pop can happen down the pipeline
if (requireMplsPop()) {
@@ -1266,35 +1264,24 @@
}
if (fwd.nextId() != null) {
- if (forTableId == MPLS_TABLE_1 && !popMpls) {
- log.warn("SR CONTINUE case cannot be handled as MPLS ECMP "
- + "is not implemented in OF-DPA yet. Aborting this flow {} -> next:{}"
- + "in this device {}", fwd.id(), fwd.nextId(), deviceId);
- // XXX We could convert to forwarding to a single-port, via a MPLS interface,
- // or a MPLS SWAP (with-same) but that would have to be handled in the next-objective.
- // Also the pop-mpls logic used here won't work in non-BoS case.
- fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
- return Collections.emptySet();
- }
-
NextGroup next = getGroupForNextObjective(fwd.nextId());
if (next != null) {
List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
// we only need the top level group's key to point the flow to it
Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
- if (isNotMplsBos(selector) && group.type().equals(SELECT)) {
- log.warn("SR CONTINUE case cannot be handled as MPLS ECMP "
- + "is not implemented in OF-DPA yet. Aborting this flow {} -> next:{}"
- + "in this device {}", fwd.id(), fwd.nextId(), deviceId);
- fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
- return Collections.emptySet();
- }
if (group == null) {
log.warn("Group with key:{} for next-id:{} not found in dev:{}",
gkeys.get(0).peekFirst(), fwd.nextId(), deviceId);
fail(fwd, ObjectiveError.GROUPMISSING);
return Collections.emptySet();
}
+ if (isNotMplsBos(selector) && group.type().equals(SELECT)) {
+ log.warn("SR CONTINUE case cannot be handled as MPLS ECMP "
+ + "is not implemented in OF-DPA yet. Aborting flow {} -> next:{} "
+ + "in this device {}", fwd.id(), fwd.nextId(), deviceId);
+ fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
+ return Collections.emptySet();
+ }
tb.deferred().group(group.id());
// retrying flows may be necessary due to bug CORD-554
if (gkeys.size() == 1 && gkeys.get(0).size() == 1) {
@@ -1639,16 +1626,53 @@
return mappings;
}
+ /**
+ * Returns true iff the given selector matches on BOS==true, indicating that
+ * the selector is trying to match on a label that is bottom-of-stack.
+ *
+ * @param selector the given match
+ * @return true iff BoS==true; false if BOS==false, or BOS matching is not
+ * expressed in the given selector
+ */
static boolean isMplsBos(TrafficSelector selector) {
MplsBosCriterion bosCriterion = (MplsBosCriterion) selector.getCriterion(MPLS_BOS);
return bosCriterion != null && bosCriterion.mplsBos();
}
+ /**
+ * Returns true iff the given selector matches on BOS==false, indicating
+ * that the selector is trying to match on a label that is not the
+ * bottom-of-stack label.
+ *
+ * @param selector the given match
+ * @return true iff BoS==false;
+ * false if BOS==true, or BOS matching is not expressed in the given selector
+ */
static boolean isNotMplsBos(TrafficSelector selector) {
MplsBosCriterion bosCriterion = (MplsBosCriterion) selector.getCriterion(MPLS_BOS);
return bosCriterion != null && !bosCriterion.mplsBos();
}
+ /**
+ * Returns true iff the forwarding objective includes a treatment to pop the
+ * MPLS label.
+ *
+ * @param fwd the given forwarding objective
+ * @return true iff mpls pop treatment exists
+ */
+ static boolean isMplsPop(ForwardingObjective fwd) {
+ if (fwd.treatment() != null) {
+ for (Instruction instr : fwd.treatment().allInstructions()) {
+ if (instr instanceof L2ModificationInstruction
+ && ((L2ModificationInstruction) instr)
+ .subtype() == L2SubType.MPLS_POP) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
private static boolean isIpv6(TrafficSelector selector) {
EthTypeCriterion ethTypeCriterion = (EthTypeCriterion) selector.getCriterion(ETH_TYPE);
return ethTypeCriterion != null && ethTypeCriterion.ethType().toShort() == Ethernet.TYPE_IPV6;
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3GroupHandler.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3GroupHandler.java
index 99c6c61..e0e5099 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3GroupHandler.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3GroupHandler.java
@@ -342,9 +342,8 @@
mplsTreatment.add(ins);
break;
default:
- log.warn("Driver does not handle this type of TrafficTreatment"
- + " instruction in nextObjectives: {} - {}",
- ins.type(), ins);
+ log.warn("Driver does not handle TrafficTreatment"
+ + " L2Mod {} for pw next-obj", l2ins.subtype());
break;
}
} else if (ins.type() == Instruction.Type.OUTPUT) {
@@ -358,14 +357,13 @@
mplsTreatment.add(ins);
break;
default:
- log.warn("Driver does not handle this type of TrafficTreatment"
- + " instruction in nextObjectives: {} - {}",
- ins.type(), ins);
+ log.warn("Driver does not handle TrafficTreatment"
+ + " L3Mod for pw next-obj", l3ins.subtype());
}
} else {
log.warn("Driver does not handle this type of TrafficTreatment"
- + " instruction in nextObjectives: {} - {}",
+ + " instruction for pw next-obj: {} - {}",
ins.type(), ins);
}
}
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
index 0059b64..7ea79bd 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa3Pipeline.java
@@ -386,9 +386,13 @@
@Override
protected Collection<FlowRule> processEthTypeSpecific(ForwardingObjective fwd) {
- if (isNotMplsBos(fwd.selector())) {
+ // if its not-bos, we go to MPLS_TYPE_TABLE regardless of whether we pop or swap
+ // if it is bos, we go to MPLS_TYPE_TABLE only if we swap
+ if (isNotMplsBos(fwd.selector())
+ || (isMplsBos(fwd.selector()) && !isMplsPop(fwd))) {
return processEthTypeSpecificInternal(fwd, true, MPLS_TYPE_TABLE);
}
+ // if it is bos, and we pop, we go to MPLS_L3_TYPE_TABLE
return processEthTypeSpecificInternal(fwd, true, MPLS_L3_TYPE_TABLE);
}