Implements [CORD-587] and [CORD-588]
Changes:
- Add termination in SR app;
- Add termination in the drivers
Change-Id: Ia9bb31c2c2e20acab8d6bfe27113f7421a8b83da
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa2Pipeline.java
index e32f5d5..9da1e27 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa2Pipeline.java
@@ -129,6 +129,11 @@
protected static final int MPLS_TUNNEL_ID_BASE = 0x10000;
protected static final int MPLS_TUNNEL_ID_MAX = 0x1FFFF;
+ protected static final int MPLS_UNI_PORT_MAX = 0x0000FFFF;
+
+ protected static final int MPLS_NNI_PORT_BASE = 0x00020000;
+ protected static final int MPLS_NNI_PORT_MAX = 0x0002FFFF;
+
private final Logger log = getLogger(getClass());
protected ServiceDirectory serviceDirectory;
protected FlowRuleService flowRuleService;
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa3Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa3Pipeline.java
index 38fe384..db01906 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa3Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/Ofdpa3Pipeline.java
@@ -21,6 +21,8 @@
import org.onosproject.core.ApplicationId;
import org.onosproject.driver.extensions.Ofdpa3MatchMplsL2Port;
import org.onosproject.driver.extensions.Ofdpa3MatchOvid;
+import org.onosproject.driver.extensions.Ofdpa3PopCw;
+import org.onosproject.driver.extensions.Ofdpa3PopL2Header;
import org.onosproject.driver.extensions.Ofdpa3SetMplsL2Port;
import org.onosproject.driver.extensions.Ofdpa3SetMplsType;
import org.onosproject.driver.extensions.Ofdpa3SetOvid;
@@ -40,8 +42,11 @@
import org.onosproject.net.flow.criteria.PortCriterion;
import org.onosproject.net.flow.criteria.TunnelIdCriterion;
import org.onosproject.net.flow.criteria.VlanIdCriterion;
+import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction.L2SubType;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction;
import org.onosproject.net.flowobjective.FilteringObjective;
import org.onosproject.net.flowobjective.ForwardingObjective;
import org.onosproject.net.flowobjective.ObjectiveError;
@@ -146,7 +151,7 @@
return;
}
// 0x0000XXXX is UNI interface.
- if (portCriterion.port().toLong() > 0x0000FFFF) {
+ if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
log.error("Filering Objective invalid logical port {}",
portCriterion.port().toLong());
fail(filteringObjective, ObjectiveError.BADPARAMS);
@@ -273,23 +278,104 @@
@Override
protected Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
// We use the tunnel id to identify pw related flows.
+ // Looking for the fwd objective of the initiation.
TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) fwd.selector()
.getCriterion(TUNNEL_ID);
if (tunnelIdCriterion != null) {
- return processPwVersatile(fwd);
+ return processInitPwVersatile(fwd);
+ }
+ // Looking for the fwd objective of the termination.
+ ModTunnelIdInstruction modTunnelIdInstruction = getModTunnelIdInstruction(fwd.treatment());
+ OutputInstruction outputInstruction = getOutputInstruction(fwd.treatment());
+ if (modTunnelIdInstruction != null && outputInstruction != null) {
+ return processTermPwVersatile(fwd, modTunnelIdInstruction, outputInstruction);
}
// If it is not a pseudo wire flow we fall back
// to the OFDPA 2.0 pipeline.
return super.processVersatile(fwd);
}
+ private Collection<FlowRule> processTermPwVersatile(ForwardingObjective forwardingObjective,
+ ModTunnelIdInstruction modTunnelIdInstruction,
+ OutputInstruction outputInstruction) {
+ TrafficTreatment.Builder flowTreatment;
+ TrafficSelector.Builder flowSelector;
+ // We divide the mpls actions from the tunnel actions. We need
+ // this to order the actions in the final treatment.
+ TrafficTreatment.Builder mplsTreatment = DefaultTrafficTreatment.builder();
+ createMplsTreatment(forwardingObjective.treatment(), mplsTreatment);
+ // The match of the forwarding objective is ready to go.
+ flowSelector = DefaultTrafficSelector.builder(forwardingObjective.selector());
+ // We verify the tunnel id and mpls port are correct.
+ long tunnelId = MPLS_TUNNEL_ID_BASE | modTunnelIdInstruction.tunnelId();
+ if (tunnelId > MPLS_TUNNEL_ID_MAX) {
+ log.error("Pw Versatile Forwarding Objective must include tunnel id < {}",
+ MPLS_TUNNEL_ID_MAX);
+ fail(forwardingObjective, ObjectiveError.BADPARAMS);
+ return Collections.emptySet();
+ }
+ // 0x0002XXXX is NNI interface.
+ int mplsLogicalPort = ((int) outputInstruction.port().toLong()) | MPLS_NNI_PORT_BASE;
+ if (mplsLogicalPort > MPLS_NNI_PORT_MAX) {
+ log.error("Pw Versatile Forwarding Objective invalid logical port {}",
+ mplsLogicalPort);
+ fail(forwardingObjective, ObjectiveError.BADPARAMS);
+ return Collections.emptySet();
+ }
+ // Next id cannot be null.
+ if (forwardingObjective.nextId() == null) {
+ log.error("Pw Versatile Forwarding Objective must contain nextId ",
+ forwardingObjective.nextId());
+ fail(forwardingObjective, ObjectiveError.BADPARAMS);
+ return Collections.emptySet();
+ }
+ // We retrieve the l2 interface group and point the mpls
+ // flow to this.
+ NextGroup next = getGroupForNextObjective(forwardingObjective.nextId());
+ if (next == null) {
+ log.warn("next-id:{} not found in dev:{}", forwardingObjective.nextId(), deviceId);
+ fail(forwardingObjective, ObjectiveError.GROUPMISSING);
+ return Collections.emptySet();
+ }
+ List<Deque<GroupKey>> gkeys = appKryo.deserialize(next.data());
+ Group group = groupService.getGroup(deviceId, gkeys.get(0).peekFirst());
+ if (group == null) {
+ log.warn("Group with key:{} for next-id:{} not found in dev:{}",
+ gkeys.get(0).peekFirst(), forwardingObjective.nextId(), deviceId);
+ fail(forwardingObjective, ObjectiveError.GROUPMISSING);
+ return Collections.emptySet();
+ }
+ // We prepare the treatment for the mpls flow table.
+ // The order of the actions has to be strictly this
+ // according to the OFDPA 2.0 specification.
+ flowTreatment = DefaultTrafficTreatment.builder(mplsTreatment.build());
+ flowTreatment.extension(new Ofdpa3PopCw(), deviceId);
+ flowTreatment.popVlan();
+ flowTreatment.extension(new Ofdpa3PopL2Header(), deviceId);
+ flowTreatment.setTunnelId(tunnelId);
+ flowTreatment.extension(new Ofdpa3SetMplsL2Port(mplsLogicalPort), deviceId);
+ flowTreatment.extension(new Ofdpa3SetMplsType(VPWS), deviceId);
+ flowTreatment.transition(MPLS_TYPE_TABLE);
+ flowTreatment.deferred().group(group.id());
+ // We prepare the flow rule for the mpls table.
+ FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
+ .fromApp(forwardingObjective.appId())
+ .withPriority(forwardingObjective.priority())
+ .forDevice(deviceId)
+ .withSelector(flowSelector.build())
+ .withTreatment(flowTreatment.build())
+ .makePermanent()
+ .forTable(MPLS_TABLE_1);
+ return Collections.singletonList(ruleBuilder.build());
+ }
+
/**
* Helper method to process the pw forwarding objectives.
*
* @param forwardingObjective the fw objective to process
* @return a singleton list of flow rule
*/
- private Collection<FlowRule> processPwVersatile(ForwardingObjective forwardingObjective) {
+ private Collection<FlowRule> processInitPwVersatile(ForwardingObjective forwardingObjective) {
// We retrieve the matching criteria for mpls l2 port.
TunnelIdCriterion tunnelIdCriterion = (TunnelIdCriterion) forwardingObjective.selector()
.getCriterion(TUNNEL_ID);
@@ -315,7 +401,7 @@
return Collections.emptySet();
}
// 0x0000XXXX is UNI interface.
- if (portCriterion.port().toLong() > 0x0000FFFF) {
+ if (portCriterion.port().toLong() > MPLS_UNI_PORT_MAX) {
log.error("Pw Versatile Forwarding Objective invalid logical port {}",
portCriterion.port().toLong());
fail(forwardingObjective, ObjectiveError.BADPARAMS);
@@ -369,4 +455,94 @@
.forTable(MPLS_L2_PORT_FLOW_TABLE);
return Collections.singletonList(ruleBuilder.build());
}
+
+ /**
+ * Utility function to get the mod tunnel id instruction
+ * if present.
+ *
+ * @param treatment the treatment to analyze
+ * @return the mod tunnel id instruction if present,
+ * otherwise null
+ */
+ private ModTunnelIdInstruction getModTunnelIdInstruction(TrafficTreatment treatment) {
+ L2ModificationInstruction l2ModificationInstruction;
+ for (Instruction instruction : treatment.allInstructions()) {
+ if (instruction.type() == L2MODIFICATION) {
+ l2ModificationInstruction = (L2ModificationInstruction) instruction;
+ if (l2ModificationInstruction.subtype() == L2SubType.TUNNEL_ID) {
+ return (ModTunnelIdInstruction) l2ModificationInstruction;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Utility function to get the output instruction
+ * if present.
+ *
+ * @param treatment the treatment to analyze
+ * @return the output instruction if present,
+ * otherwise null
+ */
+ private OutputInstruction getOutputInstruction(TrafficTreatment treatment) {
+ for (Instruction instruction : treatment.allInstructions()) {
+ if (instruction.type() == Instruction.Type.OUTPUT) {
+ return (OutputInstruction) instruction;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Helper method for dividing the tunnel instructions from the mpls
+ * instructions.
+ *
+ * @param treatment the treatment to analyze
+ * @param mplsTreatment the mpls treatment builder
+ */
+ private void createMplsTreatment(TrafficTreatment treatment,
+ TrafficTreatment.Builder mplsTreatment) {
+
+ for (Instruction ins : treatment.allInstructions()) {
+
+ if (ins.type() == Instruction.Type.L2MODIFICATION) {
+ L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
+ switch (l2ins.subtype()) {
+ // These instructions have to go in the mpls
+ // treatment.
+ case TUNNEL_ID:
+ break;
+ case DEC_MPLS_TTL:
+ case MPLS_POP:
+ mplsTreatment.add(ins);
+ break;
+ default:
+ log.warn("Driver does not handle this type of TrafficTreatment"
+ + " instruction in nextObjectives: {} - {}",
+ ins.type(), ins);
+ break;
+ }
+ } else if (ins.type() == Instruction.Type.OUTPUT) {
+ break;
+ } else if (ins.type() == Instruction.Type.L3MODIFICATION) {
+ // We support partially the l3 instructions.
+ L3ModificationInstruction l3ins = (L3ModificationInstruction) ins;
+ switch (l3ins.subtype()) {
+ case TTL_IN:
+ mplsTreatment.add(ins);
+ break;
+ default:
+ log.warn("Driver does not handle this type of TrafficTreatment"
+ + " instruction in nextObjectives: {} - {}",
+ ins.type(), ins);
+ }
+
+ } else {
+ log.warn("Driver does not handle this type of TrafficTreatment"
+ + " instruction in nextObjectives: {} - {}",
+ ins.type(), ins);
+ }
+ }
+ }
}