Implements [CORD-587] and [CORD-588]
Changes:
- Add termination in SR app;
- Add termination in the drivers
Change-Id: Ia9bb31c2c2e20acab8d6bfe27113f7421a8b83da
diff --git a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
index 5f0ed35..8206180 100644
--- a/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
+++ b/apps/segmentrouting/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
@@ -19,6 +19,7 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.RandomUtils;
+import org.onlab.packet.Ethernet;
import org.onlab.packet.MacAddress;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
@@ -63,7 +64,10 @@
import static org.onosproject.net.flowobjective.ForwardingObjective.Flag.VERSATILE;
import static org.onosproject.segmentrouting.pwaas.L2Mode.TAGGED;
import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.INITIATION;
+import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.TERMINATION;
import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Result.*;
+import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.FWD;
+import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.REV;
/**
* Handles pwaas related events.
@@ -71,20 +75,30 @@
public class L2TunnelHandler {
private static final Logger log = LoggerFactory.getLogger(L2TunnelHandler.class);
-
- private static final String FWD = "f";
- private static final String REV = "r";
-
- private static final String NOT_MASTER = "Not master controller";
+ /**
+ * Error message for invalid paths.
+ */
private static final String WRONG_TOPOLOGY = "Path in leaf-spine topology" +
" should always be two hops: ";
private final SegmentRoutingManager srManager;
-
- private final ConsistentMap<String, NextObjective> l2InitiationNextObjStore;
-
/**
- * TODO a proper store is necessary to handle the policies and collisions.
+ * To store the next objectives related to the initiation.
+ */
+ private final ConsistentMap<String, NextObjective> l2InitiationNextObjStore;
+ /**
+ * To store the next objectives related to the termination.
+ */
+ private final ConsistentMap<String, NextObjective> l2TerminationNextObjStore;
+ /**
+ * TODO a proper store is necessary to handle the policies, collisions and recovery.
+ * We should have a proper store for the policies and the tunnels. For several reasons:
+ * 1) We should avoid the overlapping of different policies;
+ * 2) We should avoid the overlapping of different tunnels;
+ * 3) We should have a proper mechanism for the protection;
+ * The most important one is 3). At least for 3.0 EA0 was not possible
+ * to remove the bucket, so we need a mapping between policies and tunnel
+ * in order to proper update the fwd objective for the recovery of a fault.
*/
private final KryoNamespace.Builder l2TunnelKryo;
@@ -104,6 +118,12 @@
.withName("onos-l2initiation-nextobj-store")
.withSerializer(Serializer.using(l2TunnelKryo.build()))
.build();
+
+ l2TerminationNextObjStore = srManager.storageService
+ .<String, NextObjective>consistentMapBuilder()
+ .withName("onos-l2termination-nextobj-store")
+ .withSerializer(Serializer.using(l2TunnelKryo.build()))
+ .build();
}
/**
@@ -122,6 +142,11 @@
deploy(pwToAdd);
}
+ /**
+ * To deploy a number of pseudo wires.
+ *
+ * @param pwToAdd the set of pseudo wires to add
+ */
private void deploy(Set<DefaultL2TunnelDescription> pwToAdd) {
Result result;
long l2TunnelId;
@@ -129,7 +154,7 @@
l2TunnelId = currentL2Tunnel.l2Tunnel().tunnelId();
// The tunnel id cannot be 0.
if (l2TunnelId == 0) {
- log.warn("Tunnel id cannot be 0");
+ log.warn("Tunnel id id must be > 0");
continue;
}
// We do a sanity check of the pseudo wire.
@@ -138,7 +163,7 @@
continue;
}
// We establish the tunnel.
- result = deployPseudoWire(
+ result = deployPseudoWireInit(
currentL2Tunnel.l2Tunnel(),
currentL2Tunnel.l2TunnelPolicy().cP1(),
currentL2Tunnel.l2TunnelPolicy().cP2(),
@@ -158,8 +183,18 @@
if (result != SUCCESS) {
continue;
}
+ // We terminate the tunnel
+ result = deployPseudoWireTerm(
+ currentL2Tunnel.l2Tunnel(),
+ currentL2Tunnel.l2TunnelPolicy().cP2(),
+ currentL2Tunnel.l2TunnelPolicy().cP2OuterTag(),
+ FWD
+ );
+ if (result != SUCCESS) {
+ continue;
+ }
// We establish the reverse tunnel.
- result = deployPseudoWire(
+ result = deployPseudoWireInit(
currentL2Tunnel.l2Tunnel(),
currentL2Tunnel.l2TunnelPolicy().cP2(),
currentL2Tunnel.l2TunnelPolicy().cP1(),
@@ -168,18 +203,27 @@
if (result != SUCCESS) {
continue;
}
- deployPolicy(
+ result = deployPolicy(
l2TunnelId,
currentL2Tunnel.l2TunnelPolicy().cP2(),
currentL2Tunnel.l2TunnelPolicy().cP2InnerTag(),
currentL2Tunnel.l2TunnelPolicy().cP2OuterTag(),
result.nextId
);
+ if (result != SUCCESS) {
+ continue;
+ }
+ deployPseudoWireTerm(
+ currentL2Tunnel.l2Tunnel(),
+ currentL2Tunnel.l2TunnelPolicy().cP1(),
+ currentL2Tunnel.l2TunnelPolicy().cP1OuterTag(),
+ REV
+ );
}
}
/**
- * Processes Pwaas Config updated event.
+ * Processes PWaaS Config updated event.
*
* @param event network config updated event
*/
@@ -209,12 +253,10 @@
.collect(Collectors.toSet());
deploy(pwToAdd);
// The pseudo wires to update.
- updPws.forEach(tunnelId -> {
- updatePw(
- prevConfig.getPwDescription(tunnelId),
- config.getPwDescription(tunnelId)
- );
- });
+ updPws.forEach(tunnelId -> updatePw(
+ prevConfig.getPwDescription(tunnelId),
+ config.getPwDescription(tunnelId))
+ );
}
/**
@@ -225,88 +267,91 @@
*/
private void updatePw(DefaultL2TunnelDescription oldPw,
DefaultL2TunnelDescription newPw) {
-
long tunnelId = oldPw.l2Tunnel().tunnelId();
- String fwdKey = generateKey(tunnelId, FWD);
- String revKey = generateKey(tunnelId, REV);
- Result result;
- NextObjective fwdNextObjective;
- NextObjective revNextObjective;
// The async tasks to orchestrate the next and
// forwarding update.
- CompletableFuture<ObjectiveError> revPolicyFuture = new CompletableFuture<>();
CompletableFuture<ObjectiveError> fwdInitNextFuture = new CompletableFuture<>();
CompletableFuture<ObjectiveError> revInitNextFuture = new CompletableFuture<>();
- CompletableFuture<ObjectiveError> newPwFuture = new CompletableFuture<>();
+ CompletableFuture<ObjectiveError> fwdTermNextFuture = new CompletableFuture<>();
+ CompletableFuture<ObjectiveError> revTermNextFuture = new CompletableFuture<>();
+ CompletableFuture<ObjectiveError> fwdPwFuture = new CompletableFuture<>();
+ CompletableFuture<ObjectiveError> revPwFuture = new CompletableFuture<>();
- result = verifyPseudoWire(newPw);
+
+ Result result = verifyPseudoWire(newPw);
if (result != SUCCESS) {
return;
}
- if (!l2InitiationNextObjStore.containsKey(fwdKey)) {
- log.warn("NextObj for {} does not exist in the store.", fwdKey);
- return;
- }
- fwdNextObjective = l2InitiationNextObjStore.get(fwdKey).value();
- if (!l2InitiationNextObjStore.containsKey(revKey)) {
- log.warn("NextObj for {} does not exist in the store.", revKey);
- return;
- }
// First we remove both policy.
- revNextObjective = l2InitiationNextObjStore.get(revKey).value();
log.debug("Start deleting fwd policy for {}", tunnelId);
deletePolicy(
tunnelId,
oldPw.l2TunnelPolicy().cP1(),
oldPw.l2TunnelPolicy().cP1InnerTag(),
oldPw.l2TunnelPolicy().cP1OuterTag(),
- fwdNextObjective.id(),
- revPolicyFuture
+ fwdInitNextFuture,
+ FWD
);
- revPolicyFuture.thenAcceptAsync(status -> {
- if (status == null) {
- log.debug("Fwd policy removed. Now remove rev policy for {}", tunnelId);
- deletePolicy(
- tunnelId,
- oldPw.l2TunnelPolicy().cP2(),
- oldPw.l2TunnelPolicy().cP2InnerTag(),
- oldPw.l2TunnelPolicy().cP2OuterTag(),
- revNextObjective.id(),
- fwdInitNextFuture
- );
- }
- });
+ log.debug("Start deleting rev policy for {}", tunnelId);
+ deletePolicy(
+ tunnelId,
+ oldPw.l2TunnelPolicy().cP2(),
+ oldPw.l2TunnelPolicy().cP2InnerTag(),
+ oldPw.l2TunnelPolicy().cP2OuterTag(),
+ revInitNextFuture,
+ REV
+ );
// Finally we remove both the tunnels.
fwdInitNextFuture.thenAcceptAsync(status -> {
if (status == null) {
- log.debug("Rev policy removed. Now remove fwd pw for {}", tunnelId);
- tearDownPseudoWire(
- fwdKey,
- fwdNextObjective,
+ log.debug("Fwd policy removed. Now remove fwd {} for {}", INITIATION, tunnelId);
+ tearDownPseudoWireInit(
+ tunnelId,
oldPw.l2TunnelPolicy().cP1(),
- oldPw.l2TunnelPolicy().cP2(),
- revInitNextFuture
+ fwdTermNextFuture,
+ FWD
);
}
});
revInitNextFuture.thenAcceptAsync(status -> {
if (status == null) {
- log.debug("Fwd tunnel removed. Now remove rev pw for {}", tunnelId);
- tearDownPseudoWire(
- revKey,
- revNextObjective,
+ log.debug("Rev policy removed. Now remove rev {} for {}", INITIATION, tunnelId);
+ tearDownPseudoWireInit(
+ tunnelId,
oldPw.l2TunnelPolicy().cP2(),
- oldPw.l2TunnelPolicy().cP1(),
- newPwFuture
+ revTermNextFuture,
+ REV
);
}
});
+ fwdTermNextFuture.thenAcceptAsync(status -> {
+ if (status == null) {
+ log.debug("Fwd {} removed. Now remove fwd {} for {}", INITIATION, TERMINATION, tunnelId);
+ tearDownPseudoWireTerm(
+ oldPw.l2Tunnel(),
+ oldPw.l2TunnelPolicy().cP2(),
+ fwdPwFuture,
+ FWD
+ );
+ }
+ });
+ revTermNextFuture.thenAcceptAsync(status -> {
+ if (status == null) {
+ log.debug("Rev {} removed. Now remove rev {} for {}", INITIATION, TERMINATION, tunnelId);
+ tearDownPseudoWireTerm(
+ oldPw.l2Tunnel(),
+ oldPw.l2TunnelPolicy().cP1(),
+ revPwFuture,
+ REV
+ );
+ }
+ });
// At the end we install the new pw.
- newPwFuture.thenAcceptAsync(status -> {
+ fwdPwFuture.thenAcceptAsync(status -> {
if (status == null) {
log.debug("Deploying new fwd pw for {}", tunnelId);
- Result lamdaResult = deployPseudoWire(
+ Result lamdaResult = deployPseudoWireInit(
newPw.l2Tunnel(),
newPw.l2TunnelPolicy().cP1(),
newPw.l2TunnelPolicy().cP2(),
@@ -322,8 +367,22 @@
newPw.l2TunnelPolicy().cP1OuterTag(),
lamdaResult.nextId
);
+ if (lamdaResult != SUCCESS) {
+ return;
+ }
+ deployPseudoWireTerm(
+ newPw.l2Tunnel(),
+ newPw.l2TunnelPolicy().cP2(),
+ newPw.l2TunnelPolicy().cP2OuterTag(),
+ FWD
+ );
+
+ }
+ });
+ revPwFuture.thenAcceptAsync(status -> {
+ if (status == null) {
log.debug("Deploying new rev pw for {}", tunnelId);
- lamdaResult = deployPseudoWire(
+ Result lamdaResult = deployPseudoWireInit(
newPw.l2Tunnel(),
newPw.l2TunnelPolicy().cP2(),
newPw.l2TunnelPolicy().cP1(),
@@ -339,6 +398,15 @@
newPw.l2TunnelPolicy().cP2OuterTag(),
lamdaResult.nextId
);
+ if (lamdaResult != SUCCESS) {
+ return;
+ }
+ deployPseudoWireTerm(
+ newPw.l2Tunnel(),
+ newPw.l2TunnelPolicy().cP1(),
+ newPw.l2TunnelPolicy().cP1OuterTag(),
+ REV
+ );
}
});
}
@@ -366,11 +434,8 @@
*/
private void tearDown(Set<DefaultL2TunnelDescription> pwToRemove) {
Result result;
- int nextId;
- NextObjective nextObjective;
long l2TunnelId;
- // We remove all the pw in the configuration
- // file.
+ // We remove all the pw in the configuration file.
for (DefaultL2TunnelDescription currentL2Tunnel : pwToRemove) {
l2TunnelId = currentL2Tunnel.l2Tunnel().tunnelId();
if (l2TunnelId == 0) {
@@ -381,52 +446,48 @@
if (result != SUCCESS) {
continue;
}
- String key = generateKey(l2TunnelId, FWD);
- if (!l2InitiationNextObjStore.containsKey(key)) {
- log.warn("NextObj for {} does not exist in the store.", key);
- continue;
- }
- nextObjective = l2InitiationNextObjStore.get(key).value();
- nextId = nextObjective.id();
// First all we have to delete the policy.
deletePolicy(
l2TunnelId,
currentL2Tunnel.l2TunnelPolicy().cP1(),
currentL2Tunnel.l2TunnelPolicy().cP1InnerTag(),
currentL2Tunnel.l2TunnelPolicy().cP1OuterTag(),
- nextId,
- null
+ null,
+ FWD
);
// Finally we will tear down the pseudo wire.
- tearDownPseudoWire(
- key,
- nextObjective,
+ tearDownPseudoWireInit(
+ l2TunnelId,
currentL2Tunnel.l2TunnelPolicy().cP1(),
+ null,
+ FWD
+ );
+ tearDownPseudoWireTerm(
+ currentL2Tunnel.l2Tunnel(),
currentL2Tunnel.l2TunnelPolicy().cP2(),
- null
+ null,
+ FWD
);
// We do the same operations on the reverse side.
- key = generateKey(l2TunnelId, REV);
- if (!l2InitiationNextObjStore.containsKey(key)) {
- log.warn("NextObj for {} does not exist in the store.", key);
- continue;
- }
- nextObjective = l2InitiationNextObjStore.get(key).value();
- nextId = nextObjective.id();
deletePolicy(
l2TunnelId,
currentL2Tunnel.l2TunnelPolicy().cP2(),
currentL2Tunnel.l2TunnelPolicy().cP2InnerTag(),
currentL2Tunnel.l2TunnelPolicy().cP2OuterTag(),
- nextId,
- null
+ null,
+ REV
);
- tearDownPseudoWire(
- key,
- nextObjective,
+ tearDownPseudoWireInit(
+ l2TunnelId,
currentL2Tunnel.l2TunnelPolicy().cP2(),
+ null,
+ REV
+ );
+ tearDownPseudoWireTerm(
+ currentL2Tunnel.l2Tunnel(),
currentL2Tunnel.l2TunnelPolicy().cP1(),
- null
+ null,
+ REV
);
}
@@ -444,7 +505,7 @@
DefaultL2TunnelPolicy l2TunnelPolicy = l2TunnelDescription.l2TunnelPolicy();
result = verifyTunnel(l2Tunnel);
if (result != SUCCESS) {
- log.warn("Tunnel {} did not pass the validation", l2Tunnel.tunnelId());
+ log.warn("Tunnel {}: did not pass the validation", l2Tunnel.tunnelId());
return result;
}
result = verifyPolicy(
@@ -455,7 +516,7 @@
l2TunnelPolicy.cP2OuterTag()
);
if (result != SUCCESS) {
- log.warn("Policy for tunnel {} did not pass the validation", l2Tunnel.tunnelId());
+ log.warn("Policy for tunnel {}: did not pass the validation", l2Tunnel.tunnelId());
return result;
}
@@ -463,8 +524,6 @@
}
/**
- * TODO Operation on the policies store.
- *
* Handles the policy establishment which consists in
* create the filtering and forwarding objectives related
* to the initiation and termination.
@@ -474,27 +533,21 @@
* @param ingressInner the ingress inner tag
* @param ingressOuter the ingress outer tag
* @param nextId the next objective id
- * @return SUCCESS if the policy has been deployed.
- * Otherwise an error according to the failure
- * scenario.
+ * @return the result of the operation
*/
private Result deployPolicy(long tunnelId,
ConnectPoint ingress,
VlanId ingressInner,
VlanId ingressOuter,
int nextId) {
-
- ForwardingObjective.Builder fwdBuilder;
- FilteringObjective.Builder filtBuilder;
- List<Objective> objectives = Lists.newArrayList();
if (!srManager.mastershipService.isLocalMaster(ingress.deviceId())) {
- log.info("Abort creation of policy for L2 tunnel {}: {}", tunnelId, NOT_MASTER);
+ log.info("Abort creation of policy for tunnel {}: I am not the master", tunnelId);
return SUCCESS;
}
+ List<Objective> objectives = Lists.newArrayList();
// We create the forwarding objective for supporting
// the l2 tunnel.
- fwdBuilder = createFwdObjective(
- INITIATION,
+ ForwardingObjective.Builder fwdBuilder = createInitFwdObjective(
tunnelId,
ingress.port(),
nextId
@@ -508,7 +561,7 @@
objectives.add(fwdBuilder.add(context));
// We create the filtering objective to define the
// permit traffic in the switch
- filtBuilder = createFiltObjective(
+ FilteringObjective.Builder filtBuilder = createFiltObjective(
ingress.port(),
ingressInner,
ingressOuter
@@ -528,7 +581,7 @@
for (Objective objective : objectives) {
if (objective instanceof ForwardingObjective) {
srManager.flowObjectiveService.forward(ingress.deviceId(), (ForwardingObjective) objective);
- log.debug("Creating new FwdObj for NextObj with id={} for tunnel {}", nextId, tunnelId);
+ log.debug("Creating new FwdObj for initiation NextObj with id={} for tunnel {}", nextId, tunnelId);
} else {
srManager.flowObjectiveService.filter(ingress.deviceId(), (FilteringObjective) objective);
log.debug("Creating new FiltObj for tunnel {}", tunnelId);
@@ -572,46 +625,36 @@
}
/**
- * TODO Operation on the policies store.
- *
* Handles the tunnel establishment which consists in
- * create the next objectives related to the initiation
- * and termination.
+ * create the next objectives related to the initiation.
*
* @param l2Tunnel the tunnel to deploy
* @param ingress the ingress connect point
* @param egress the egress connect point
* @param direction the direction of the pw
- * @return SUCCESS if the tunnel has been created.
- * Otherwise an error according to the failure
- * scenario
+ * @return the result of the operation
*/
- private Result deployPseudoWire(DefaultL2Tunnel l2Tunnel,
- ConnectPoint ingress,
- ConnectPoint egress,
- String direction) {
- Link nextHop;
- NextObjective.Builder nextObjectiveBuilder;
- NextObjective nextObjective;
- int nextId;
- Result result;
+ private Result deployPseudoWireInit(DefaultL2Tunnel l2Tunnel,
+ ConnectPoint ingress,
+ ConnectPoint egress,
+ Direction direction) {
if (!srManager.mastershipService.isLocalMaster(ingress.deviceId())) {
- log.info("Abort initiation creation of L2 tunnel {}: {}",
- l2Tunnel.tunnelId(), NOT_MASTER);
+ log.info("Abort initiation of tunnel {}: I am not the master", l2Tunnel.tunnelId());
return SUCCESS;
}
// We need at least a path between ingress and egress.
- nextHop = getNextHop(ingress, egress);
+ Link nextHop = getNextHop(ingress, egress);
if (nextHop == null) {
log.warn("No path between ingress and egress");
return WRONG_PARAMETERS;
}
// We create the next objective without the metadata
// context and id. We check if it already exists in the
- // store. If not we store as it is in the store ?
- nextObjectiveBuilder = createNextObjective(
+ // store. If not we store as it is in the store.
+ NextObjective.Builder nextObjectiveBuilder = createNextObjective(
INITIATION,
- nextHop,
+ nextHop.src(),
+ nextHop.dst(),
l2Tunnel,
egress.deviceId()
);
@@ -625,7 +668,7 @@
.matchTunnelId(l2Tunnel.tunnelId())
.build();
nextObjectiveBuilder.withMeta(metadata);
- nextId = srManager.flowObjectiveService.allocateNextId();
+ int nextId = srManager.flowObjectiveService.allocateNextId();
if (nextId < 0) {
log.warn("Not able to allocate a next id for initiation");
return INTERNAL_ERROR;
@@ -640,18 +683,95 @@
(objective, error)
-> log.warn("Failed to populate Initiation l2 tunnel rule for {}: {}",
l2Tunnel.tunnelId(), error));
- nextObjective = nextObjectiveBuilder.add(context);
+ NextObjective nextObjective = nextObjectiveBuilder.add(context);
srManager.flowObjectiveService.next(ingress.deviceId(), nextObjective);
log.debug("Initiation next objective for {} not found. Creating new NextObj with id={}",
l2Tunnel.tunnelId(),
nextObjective.id()
);
- result = SUCCESS;
+ Result result = SUCCESS;
result.nextId = nextObjective.id();
return result;
}
/**
+ * Handles the tunnel termination, which consists in the creation
+ * of a forwarding objective and a next objective.
+ *
+ * @param l2Tunnel the tunnel to terminate
+ * @param egress the egress point
+ * @param egressVlan the expected vlan at egress
+ * @param direction the direction
+ * @return the result of the operation
+ */
+ private Result deployPseudoWireTerm(DefaultL2Tunnel l2Tunnel,
+ ConnectPoint egress,
+ VlanId egressVlan,
+ Direction direction) {
+ // We create the group relative to the termination.
+ // It's fine to abort the termination if we are
+ // not the master.
+ if (!srManager.mastershipService.isLocalMaster(egress.deviceId())) {
+ log.info("Abort termination of tunnel {}: I am not the master", l2Tunnel.tunnelId());
+ return SUCCESS;
+ }
+ NextObjective.Builder nextObjectiveBuilder = createNextObjective(
+ TERMINATION,
+ egress,
+ null,
+ null,
+ egress.deviceId()
+ );
+ if (nextObjectiveBuilder == null) {
+ return INTERNAL_ERROR;
+ }
+ TrafficSelector metadata = DefaultTrafficSelector
+ .builder()
+ .matchVlanId(egressVlan)
+ .build();
+ nextObjectiveBuilder.withMeta(metadata);
+ int nextId = srManager.flowObjectiveService.allocateNextId();
+ if (nextId < 0) {
+ log.warn("Not able to allocate a next id for initiation");
+ return INTERNAL_ERROR;
+ }
+ nextObjectiveBuilder.withId(nextId);
+ String key = generateKey(l2Tunnel.tunnelId(), direction);
+ l2TerminationNextObjStore.put(key, nextObjectiveBuilder.add());
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective)
+ -> log.debug("Termination l2 tunnel rule for {} populated",
+ l2Tunnel.tunnelId()),
+ (objective, error)
+ -> log.warn("Failed to populate termination l2 tunnel rule for {}: {}",
+ l2Tunnel.tunnelId(), error));
+ NextObjective nextObjective = nextObjectiveBuilder.add(context);
+ srManager.flowObjectiveService.next(egress.deviceId(), nextObjective);
+ log.debug("Termination next objective for {} not found. Creating new NextObj with id={}",
+ l2Tunnel.tunnelId(),
+ nextObjective.id()
+ );
+ // We create the flow relative to the termination.
+ ForwardingObjective.Builder fwdBuilder = createTermFwdObjective(
+ l2Tunnel.pwLabel(),
+ l2Tunnel.tunnelId(),
+ egress.port(),
+ nextObjective.id()
+ );
+ context = new DefaultObjectiveContext(
+ (objective)
+ -> log.debug("FwdObj for tunnel termination {} populated",
+ l2Tunnel.tunnelId()),
+ (objective, error)
+ -> log.warn("Failed to populate fwdrObj for tunnel termination {}",
+ l2Tunnel.tunnelId(), error));
+ srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.add(context));
+ log.debug("Creating new FwdObj for termination NextObj with id={} for tunnel {}", nextId, l2Tunnel.tunnelId());
+ return SUCCESS;
+
+ }
+
+ /**
* Helper method to verify if the tunnel is whether or not
* supported.
*
@@ -675,7 +795,7 @@
}
/**
- * Create the filtering objective according to a given policy.
+ * Creates the filtering objective according to a given policy.
*
* @param inPort the in port
* @param innerTag the inner vlan tag
@@ -695,34 +815,69 @@
}
/**
- * Create the forwarding objective according to a given pipeline.
+ * Creates the forwarding objective for the termination.
*
- * @param pipeline the pipeline
+ * @param pwLabel the pseudo wire label
* @param tunnelId the tunnel id
+ * @param egressPort the egress port
* @param nextId the next step
- * @return the forwarding objective to support the pipeline.
+ * @return the forwarding objective to support the termination
*/
- private ForwardingObjective.Builder createFwdObjective(Pipeline pipeline,
- long tunnelId,
- PortNumber inPort,
- int nextId) {
- ForwardingObjective.Builder fwdBuilder = null;
+ private ForwardingObjective.Builder createTermFwdObjective(MplsLabel pwLabel,
+ long tunnelId,
+ PortNumber egressPort,
+ int nextId) {
TrafficSelector.Builder trafficSelector = DefaultTrafficSelector
.builder();
- if (pipeline == INITIATION) {
- // The flow has to match on the mpls logical
- // port and the tunnel id.
- trafficSelector.matchTunnelId(tunnelId);
- trafficSelector.matchInPort(inPort);
- fwdBuilder = DefaultForwardingObjective.builder()
- .fromApp(srManager.appId)
- .makePermanent()
- .nextStep(nextId)
- .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
- .withSelector(trafficSelector.build())
- .withFlag(VERSATILE);
- }
- return fwdBuilder;
+ TrafficTreatment.Builder trafficTreatment = DefaultTrafficTreatment
+ .builder();
+ // The flow has to match on the pw label and bos
+ trafficSelector.matchEthType(Ethernet.MPLS_UNICAST);
+ trafficSelector.matchMplsLabel(pwLabel);
+ trafficSelector.matchMplsBos(true);
+ // The flow has to decrement ttl, restore ttl in
+ // pop mpls, set tunnel id and port.
+ trafficTreatment.decMplsTtl();
+ trafficTreatment.copyTtlIn();
+ trafficTreatment.popMpls();
+ trafficTreatment.setTunnelId(tunnelId);
+ trafficTreatment.setOutput(egressPort);
+
+ return DefaultForwardingObjective.builder()
+ .fromApp(srManager.appId)
+ .makePermanent()
+ .nextStep(nextId)
+ .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
+ .withSelector(trafficSelector.build())
+ .withTreatment(trafficTreatment.build())
+ .withFlag(VERSATILE);
+ }
+
+ /**
+ * Creates the forwarding objective for the initiation.
+ *
+ * @param tunnelId the tunnel id
+ * @param inPort the input port
+ * @param nextId the next step
+ * @return the forwarding objective to support the initiation.
+ */
+ private ForwardingObjective.Builder createInitFwdObjective(long tunnelId,
+ PortNumber inPort,
+ int nextId) {
+ TrafficSelector.Builder trafficSelector = DefaultTrafficSelector
+ .builder();
+ // The flow has to match on the mpls logical
+ // port and the tunnel id.
+ trafficSelector.matchTunnelId(tunnelId);
+ trafficSelector.matchInPort(inPort);
+
+ return DefaultForwardingObjective.builder()
+ .fromApp(srManager.appId)
+ .makePermanent()
+ .nextStep(nextId)
+ .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
+ .withSelector(trafficSelector.build())
+ .withFlag(VERSATILE);
}
@@ -733,13 +888,15 @@
* the same next objective for different tunnels.
*
* @param pipeline the pipeline to support
- * @param nextHop the next hop towards the destination
+ * @param srcCp the source port
+ * @param dstCp the destination port
* @param l2Tunnel the tunnel to support
* @param egressId the egress device id
* @return the next objective to support the pipeline
*/
private NextObjective.Builder createNextObjective(Pipeline pipeline,
- Link nextHop,
+ ConnectPoint srcCp,
+ ConnectPoint dstCp,
DefaultL2Tunnel l2Tunnel,
DeviceId egressId) {
NextObjective.Builder nextObjBuilder;
@@ -786,7 +943,7 @@
try {
ingressMac = srManager
.deviceConfiguration
- .getDeviceMac(nextHop.src().deviceId());
+ .getDeviceMac(srcCp.deviceId());
} catch (DeviceConfigNotFoundException e) {
log.warn("Was not able to find the ingress mac");
return null;
@@ -796,20 +953,21 @@
try {
neighborMac = srManager
.deviceConfiguration
- .getDeviceMac(nextHop.dst().deviceId());
+ .getDeviceMac(dstCp.deviceId());
} catch (DeviceConfigNotFoundException e) {
log.warn("Was not able to find the neighbor mac");
return null;
}
treatmentBuilder.setEthDst(neighborMac);
} else {
+ // We create the next objective which
+ // will be a simple l2 group.
nextObjBuilder = DefaultNextObjective
.builder()
.withType(NextObjective.Type.SIMPLE)
.fromApp(srManager.appId);
-
}
- treatmentBuilder.setOutput(nextHop.src().port());
+ treatmentBuilder.setOutput(srcCp.port());
nextObjBuilder.addTreatment(treatmentBuilder.build());
return nextObjBuilder;
}
@@ -841,32 +999,41 @@
}
/**
- * TODO Operation on the store.
* Deletes a given policy using the parameter supplied.
*
* @param tunnelId the tunnel id
* @param ingress the ingress point
* @param ingressInner the ingress inner vlan id
* @param ingressOuter the ingress outer vlan id
- * @param nextId the next objective id
+ * @param future to perform the async operation
+ * @param direction the direction: forward or reverse
*/
private void deletePolicy(long tunnelId,
ConnectPoint ingress,
VlanId ingressInner,
VlanId ingressOuter,
- int nextId,
- CompletableFuture<ObjectiveError> fwdFuture) {
-
- ForwardingObjective.Builder fwdBuilder;
- FilteringObjective.Builder filtBuilder;
- List<Objective> objectives = Lists.newArrayList();
+ CompletableFuture<ObjectiveError> future,
+ Direction direction) {
if (!srManager.mastershipService.isLocalMaster(ingress.deviceId())) {
- log.info("Abort delete of policy for L2 tunnel {}: {}", tunnelId, NOT_MASTER);
+ log.info("Abort delete of policy for tunnel {}: I am not the master", tunnelId);
+ if (future != null) {
+ future.complete(null);
+ }
return;
}
+ String key = generateKey(tunnelId, direction);
+ if (!l2InitiationNextObjStore.containsKey(key)) {
+ log.warn("Abort delete of policy for tunnel {}: next does not exist in the store", tunnelId);
+ if (future != null) {
+ future.complete(null);
+ }
+ return;
+ }
+ NextObjective nextObjective = l2InitiationNextObjStore.get(key).value();
+ int nextId = nextObjective.id();
+ List<Objective> objectives = Lists.newArrayList();
// We create the forwarding objective.
- fwdBuilder = createFwdObjective(
- INITIATION,
+ ForwardingObjective.Builder fwdBuilder = createInitFwdObjective(
tunnelId,
ingress.port(),
nextId
@@ -874,24 +1041,24 @@
ObjectiveContext context = new ObjectiveContext() {
@Override
public void onSuccess(Objective objective) {
- log.debug("Previous FwdObj for policy {} removed", tunnelId);
- if (fwdFuture != null) {
- fwdFuture.complete(null);
+ log.debug("Previous fwdObj for policy {} removed", tunnelId);
+ if (future != null) {
+ future.complete(null);
}
}
@Override
public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to remove previous FwdObj for policy {}: {}", tunnelId, error);
- if (fwdFuture != null) {
- fwdFuture.complete(error);
+ log.warn("Failed to remove previous fwdObj for policy {}: {}", tunnelId, error);
+ if (future != null) {
+ future.complete(error);
}
}
};
objectives.add(fwdBuilder.remove(context));
// We create the filtering objective to define the
// permit traffic in the switch
- filtBuilder = createFiltObjective(
+ FilteringObjective.Builder filtBuilder = createFiltObjective(
ingress.port(),
ingressInner,
ingressOuter
@@ -916,55 +1083,130 @@
}
/**
- * TODO Operation on the store.
- * Deletes a given pseudo wire using the parameter supplied.
+ * Deletes the pseudo wire initiation.
*
- * @param key the key of the store
- * @param nextObjective the next objective representing the pw
+ * @param l2TunnelId the tunnel id
* @param ingress the ingress connect point
- * @param egress the egress connect point
+ * @param future to perform an async operation
+ * @param direction the direction: reverse of forward
*/
- private void tearDownPseudoWire(String key,
- NextObjective nextObjective,
- ConnectPoint ingress,
- ConnectPoint egress,
- CompletableFuture<ObjectiveError> nextFutureForInit) {
+ private void tearDownPseudoWireInit(long l2TunnelId,
+ ConnectPoint ingress,
+ CompletableFuture<ObjectiveError> future,
+ Direction direction) {
+ String key = generateKey(l2TunnelId, direction);
if (!srManager.mastershipService.isLocalMaster(ingress.deviceId())) {
- log.info("Abort delete of {} for {}: {}", INITIATION, key, NOT_MASTER);
+ log.info("Abort delete of {} for {}: I am not the master", INITIATION, key);
+ if (future != null) {
+ future.complete(null);
+ }
return;
}
+ if (!l2InitiationNextObjStore.containsKey(key)) {
+ log.info("Abort delete of {} for {}: next does not exist in the store", INITIATION, key);
+ if (future != null) {
+ future.complete(null);
+ }
+ return;
+ }
+ NextObjective nextObjective = l2InitiationNextObjStore.get(key).value();
ObjectiveContext context = new ObjectiveContext() {
@Override
public void onSuccess(Objective objective) {
- log.debug("Previous {} NextObj for {} removed", INITIATION, key);
- if (nextFutureForInit != null) {
- nextFutureForInit.complete(null);
+ log.debug("Previous {} next for {} removed", INITIATION, key);
+ if (future != null) {
+ future.complete(null);
}
}
@Override
public void onError(Objective objective, ObjectiveError error) {
- log.warn("Failed to remove previous {} NextObj for {}: {}", INITIATION, key, error);
- if (nextFutureForInit != null) {
- nextFutureForInit.complete(error);
+ log.warn("Failed to remove previous {} next for {}: {}", INITIATION, key, error);
+ if (future != null) {
+ future.complete(error);
}
}
};
- srManager.flowObjectiveService.next(
- ingress.deviceId(),
- (NextObjective) nextObjective.copy().remove(context)
- );
+ srManager.flowObjectiveService
+ .next(ingress.deviceId(), (NextObjective) nextObjective.copy().remove(context));
l2InitiationNextObjStore.remove(key);
}
/**
+ * Deletes the pseudo wire termination.
+ *
+ * @param l2Tunnel the tunnel
+ * @param egress the egress connect point
+ * @param future the async task
+ * @param direction the direction of the tunnel
+ */
+ private void tearDownPseudoWireTerm(DefaultL2Tunnel l2Tunnel,
+ ConnectPoint egress,
+ CompletableFuture<ObjectiveError> future,
+ Direction direction) {
+ /*
+ * We verify the mastership for the termination.
+ */
+ String key = generateKey(l2Tunnel.tunnelId(), direction);
+ if (!srManager.mastershipService.isLocalMaster(egress.deviceId())) {
+ log.info("Abort delete of {} for {}: I am not the master", TERMINATION, key);
+ if (future != null) {
+ future.complete(null);
+ }
+ return;
+ }
+ if (!l2TerminationNextObjStore.containsKey(key)) {
+ log.info("Abort delete of {} for {}: next does not exist in the store", TERMINATION, key);
+ if (future != null) {
+ future.complete(null);
+ }
+ return;
+ }
+ NextObjective nextObjective = l2TerminationNextObjStore.get(key).value();
+ ForwardingObjective.Builder fwdBuilder = createTermFwdObjective(
+ l2Tunnel.pwLabel(),
+ l2Tunnel.tunnelId(),
+ egress.port(),
+ nextObjective.id()
+ );
+ ObjectiveContext context = new DefaultObjectiveContext(
+ (objective)
+ -> log.debug("FwdObj for {} {} removed", TERMINATION, l2Tunnel.tunnelId()),
+ (objective, error)
+ -> log.warn("Failed to remove fwdObj for {} {}", TERMINATION, l2Tunnel.tunnelId(),
+ error));
+ srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.remove(context));
+
+ context = new ObjectiveContext() {
+ @Override
+ public void onSuccess(Objective objective) {
+ log.debug("Previous {} next for {} removed", TERMINATION, key);
+ if (future != null) {
+ future.complete(null);
+ }
+ }
+
+ @Override
+ public void onError(Objective objective, ObjectiveError error) {
+ log.warn("Failed to remove previous {} next for {}: {}", TERMINATION, key, error);
+ if (future != null) {
+ future.complete(error);
+ }
+ }
+ };
+ srManager.flowObjectiveService
+ .next(egress.deviceId(), (NextObjective) nextObjective.copy().remove(context));
+ l2TerminationNextObjStore.remove(key);
+ }
+
+ /**
* Utilities to generate pw key.
*
* @param tunnelId the tunnel id
* @param direction the direction of the pw
* @return the key of the store
*/
- private String generateKey(long tunnelId, String direction) {
+ private String generateKey(long tunnelId, Direction direction) {
return String.format("%s-%s", tunnelId, direction);
}
@@ -979,7 +1221,7 @@
/**
* The termination pipeline.
*/
- TERMINATION;
+ TERMINATION
}
/**
@@ -1012,7 +1254,7 @@
private final String description;
private int nextId;
- private Result(int code, String description) {
+ Result(int code, String description) {
this.code = code;
this.description = description;
}
@@ -1021,14 +1263,24 @@
return description;
}
- public int getCode() {
- return code;
- }
-
@Override
public String toString() {
return code + ": " + description;
}
}
+ /**
+ * Enum helper for handling the direction of the pw.
+ */
+ public enum Direction {
+ /**
+ * The forward direction of the pseudo wire.
+ */
+ FWD,
+ /**
+ * The reverse direction of the pseudo wire.
+ */
+ REV;
+ }
+
}
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);
+ }
+ }
+ }
}