Pseudowire enhancements :
- Fix bug for transporting l-s-s pws tagged.
- Refactored and cleaned code.
- Refactored cli commands.
- Fixed bug in bulk rest api when the same pseudowires were tried
to be added.
Change-Id: I28ded776266a08110922b93a8b330d0b343d470d
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 0e4373b..93665ec 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -126,6 +126,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashSet;
@@ -557,8 +558,8 @@
}
@Override
- public Set<L2TunnelDescription> getL2TunnelDescriptions() {
- return l2TunnelHandler.getL2Descriptions();
+ public Set<L2TunnelDescription> getL2TunnelDescriptions(boolean pending) {
+ return l2TunnelHandler.getL2Descriptions(pending);
}
@Override
@@ -574,16 +575,22 @@
@Override
public L2TunnelHandler.Result addPseudowiresBulk(List<DefaultL2TunnelDescription> bulkPseudowires) {
- Set<L2TunnelDescription> pseudowires = l2TunnelHandler.getL2Descriptions();
-
+ // get both added and pending pseudowires
+ List<L2TunnelDescription> pseudowires = new ArrayList<>();
+ pseudowires.addAll(l2TunnelHandler.getL2Descriptions(false));
+ pseudowires.addAll(l2TunnelHandler.getL2Descriptions(true));
pseudowires.addAll(bulkPseudowires);
+
Set<L2TunnelDescription> newPseudowires = new HashSet(bulkPseudowires);
// check global validity for all the new pseudowires, if it fails
// do not add any of them
+ log.debug("Verifying set of pseudowires {}", pseudowires);
boolean res = configurationValidity(pseudowires);
if (res) {
+ log.debug("Pseudowire configuration is valid, deploying pseudowires!");
l2TunnelHandler.deploy(newPseudowires);
+
return L2TunnelHandler.Result.SUCCESS;
} else {
log.error("Bulk pseudowires {} can not be added, error in global configuration!",
@@ -595,22 +602,20 @@
@Override
public L2TunnelHandler.Result addPseudowire(L2TunnelDescription l2TunnelDescription) {
- Set<L2TunnelDescription> newPseudowires = l2TunnelHandler.getL2Descriptions();
+ // get both added and pending pseudowires
+ List<L2TunnelDescription> newPseudowires = new ArrayList<>();
+ newPseudowires.addAll(l2TunnelHandler.getL2Descriptions(false));
+ newPseudowires.addAll(l2TunnelHandler.getL2Descriptions(true));
- // corner case where we try to add the exact same pseudowire
- if (newPseudowires.contains(l2TunnelDescription)) {
- log.info("Pseudowire with {} already exists!", l2TunnelDescription);
- return L2TunnelHandler.Result.SUCCESS;
- }
- // add the new pseudowire to the Set
+ // add the new pseudowire to the List
newPseudowires.add(l2TunnelDescription);
- // validate the new set of pseudowires
+ // validate the new list of pseudowires
boolean res = configurationValidity(newPseudowires);
if (res) {
// deploy a set with ONLY the new pseudowire
- newPseudowires = new HashSet<>();
- newPseudowires.add(l2TunnelDescription);
- l2TunnelHandler.deploy(newPseudowires);
+ Set<L2TunnelDescription> pwToDeploy = new HashSet<>();
+ pwToDeploy.add(l2TunnelDescription);
+ l2TunnelHandler.deploy(pwToDeploy);
log.info("Pseudowire with {} deployment started, check log for any errors in this process!",
l2TunnelDescription.l2Tunnel().tunnelId());
@@ -624,34 +629,31 @@
@Override
public L2TunnelHandler.Result removePseudowire(Integer pwId) {
- List<L2Tunnel> tunnels = getL2Tunnels();
- List<L2TunnelPolicy> policies = getL2Policies();
+ // get both added and pending pseudowires
+ Set<L2TunnelDescription> pseudowires = l2TunnelHandler.getL2Descriptions(false)
+ .stream()
+ .filter(pw -> pw.l2Tunnel().tunnelId() == pwId)
+ .collect(Collectors.toSet());
+ Set<L2TunnelDescription> pendingPseudowires = l2TunnelHandler.getL2Descriptions(true)
+ .stream()
+ .filter(pw -> pw.l2Tunnel().tunnelId() == pwId)
+ .collect(Collectors.toSet());
- // get the pseudowire, if it exists
- List<L2TunnelDescription> pseudowires = tunnels.stream().map(l2Tunnel -> {
- L2TunnelPolicy policy = null;
- for (L2TunnelPolicy l2Policy : policies) {
- if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
- policy = l2Policy;
- break;
- }
- }
-
- return new DefaultL2TunnelDescription(l2Tunnel, policy);
- }).filter(l2desc ->
- l2desc.l2Tunnel().tunnelId() == pwId
- ).collect(Collectors.toList());
-
- if (pseudowires.size() == 0) {
+ if ((pendingPseudowires.size() == 0) && (pseudowires.size() == 0)) {
log.error("Pseudowire with id {} does not exist", pwId);
return L2TunnelHandler.Result.REMOVAL_ERROR;
- } else {
-
+ }
+ if (pendingPseudowires.size() != 0) {
+ log.info("Remove pseudowire from pending store!");
+ // will fill when we implement failure mechanism detection.
+ }
+ if (pseudowires.size() != 0) {
l2TunnelHandler.tearDown(new HashSet<>(pseudowires));
log.info("Removal of pseudowire with {} started, check log for any errors in this process!",
pwId);
- return L2TunnelHandler.Result.SUCCESS;
}
+
+ return L2TunnelHandler.Result.SUCCESS;
}
@Override
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
index dc3d7b1..c329d3d 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
@@ -92,9 +92,10 @@
/**
* Returns the l2 tunnel descriptions.
*
+ * @param pending if true fetch pending pseudowires, else fetch installed
* @return set of l2 tunnel descriptions.
*/
- Set<L2TunnelDescription> getL2TunnelDescriptions();
+ Set<L2TunnelDescription> getL2TunnelDescriptions(boolean pending);
/**
* Returns all l2 tunnels of pseudowires.
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
index b69763d..4e2c4b7 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
@@ -118,7 +118,6 @@
L2TunnelDescription pw = new DefaultL2TunnelDescription(tun, policy);
L2TunnelHandler.Result res = srService.addPseudowire(pw);
-
switch (res) {
case ADDITION_ERROR:
print("Pseudowire could not be added!");
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireListCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireListCommand.java
index a633a8a..f38fe80 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireListCommand.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireListCommand.java
@@ -19,14 +19,7 @@
import org.onlab.packet.VlanId;
import org.onosproject.cli.AbstractShellCommand;
import org.onosproject.segmentrouting.SegmentRoutingService;
-import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
-import org.onosproject.segmentrouting.pwaas.L2Tunnel;
import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
-import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
/**
* Command to show the pseudowires.
*/
@@ -39,7 +32,8 @@
" mode : %s, sdTag : %s, pwLabel : %s \n" +
" cP1 : %s , cP1OuterTag : %s, cP1InnerTag : %s \n" +
" cP2 : %s , cP2OuterTag : %s, cP2InnerTag : %s \n" +
- " transportVlan : %s";
+ " transportVlan : %s \n" +
+ " pending = %s";
@Override
protected void execute() {
@@ -47,30 +41,14 @@
SegmentRoutingService srService =
AbstractShellCommand.get(SegmentRoutingService.class);
- List<L2Tunnel> tunnels = srService.getL2Tunnels();
- List<L2TunnelPolicy> policies = srService.getL2Policies();
+ srService.getL2TunnelDescriptions(false)
+ .forEach(pw -> printPseudowire(pw, false));
- // combine polices and tunnels to pseudowires
- List<L2TunnelDescription> pseudowires = tunnels.stream()
- .map(l2Tunnel -> {
- L2TunnelPolicy policy = null;
- for (L2TunnelPolicy l2Policy : policies) {
- if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
- policy = l2Policy;
- break;
- }
- }
-
- return new DefaultL2TunnelDescription(l2Tunnel, policy);
- })
- .collect(Collectors.toList());
-
- pseudowires.forEach(pw -> printPseudowire(pw));
+ srService.getL2TunnelDescriptions(true)
+ .forEach(pw -> printPseudowire(pw, true));
}
- private void printPseudowire(L2TunnelDescription pseudowire) {
-
-
+ private void printPseudowire(L2TunnelDescription pseudowire, boolean pending) {
VlanId vlan = pseudowire.l2Tunnel().transportVlan().equals(VlanId.vlanId((short) 4094)) ?
VlanId.NONE : pseudowire.l2Tunnel().transportVlan();
@@ -79,6 +57,6 @@
pseudowire.l2TunnelPolicy().cP1(), pseudowire.l2TunnelPolicy().cP1OuterTag(),
pseudowire.l2TunnelPolicy().cP1InnerTag(), pseudowire.l2TunnelPolicy().cP2(),
pseudowire.l2TunnelPolicy().cP2OuterTag(), pseudowire.l2TunnelPolicy().cP2InnerTag(),
- vlan);
+ vlan, pending);
}
}
\ No newline at end of file
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
index acaf9f6..5e2817b 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
@@ -96,6 +96,16 @@
*/
private final ConsistentMap<String, L2Tunnel> l2TunnelStore;
+ /**
+ * To store pending tunnels that need to be installed.
+ */
+ private final ConsistentMap<String, L2Tunnel> pendingL2TunnelStore;
+
+ /**
+ * To store pending policies that need to be installed.
+ */
+ private final ConsistentMap<String, L2TunnelPolicy> pendingL2PolicyStore;
+
private final KryoNamespace.Builder l2TunnelKryo;
/**
@@ -154,6 +164,19 @@
.withSerializer(Serializer.using(l2TunnelKryo.build()))
.build();
+ pendingL2PolicyStore = srManager.storageService
+ .<String, L2TunnelPolicy>consistentMapBuilder()
+ .withName("onos-l2-pending-policy-store")
+ .withSerializer(Serializer.using(l2TunnelKryo.build()))
+ .build();
+
+ pendingL2TunnelStore = srManager.storageService
+ .<String, L2Tunnel>consistentMapBuilder()
+ .withName("onos-l2-pending-tunnel-store")
+ .withSerializer(Serializer.using(l2TunnelKryo.build()))
+ .build();
+
+
vlanStore = srManager.storageService.<VlanId>setBuilder()
.withName("onos-transport-vlan-store")
.withSerializer(Serializer.using(
@@ -176,12 +199,12 @@
}
@Override
- public Set<L2TunnelDescription> getL2Descriptions() {
- List<L2Tunnel> tunnels = getL2Tunnels();
- List<L2TunnelPolicy> policies = getL2Policies();
+ public Set<L2TunnelDescription> getL2Descriptions(boolean pending) {
+ if (!pending) {
+ List<L2Tunnel> tunnels = getL2Tunnels();
+ List<L2TunnelPolicy> policies = getL2Policies();
- // determine affected pseudowires and update them at once
- return tunnels.stream()
+ return tunnels.stream()
.map(l2Tunnel -> {
L2TunnelPolicy policy = null;
for (L2TunnelPolicy l2Policy : policies) {
@@ -194,13 +217,26 @@
return new DefaultL2TunnelDescription(l2Tunnel, policy);
})
.collect(Collectors.toSet());
+ } else {
+ List<L2Tunnel> tunnels = getL2PendingTunnels();
+ List<L2TunnelPolicy> policies = getL2PendingPolicies();
+
+ return tunnels.stream()
+ .map(l2Tunnel -> {
+ L2TunnelPolicy policy = null;
+ for (L2TunnelPolicy l2Policy : policies) {
+ if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
+ policy = l2Policy;
+ break;
+ }
+ }
+
+ return new DefaultL2TunnelDescription(l2Tunnel, policy);
+ })
+ .collect(Collectors.toSet());
+ }
}
- /**
- * Returns all L2 Policies.
- *
- * @return List of policies
- */
@Override
public List<L2TunnelPolicy> getL2Policies() {
@@ -211,11 +247,6 @@
.collect(Collectors.toList()));
}
- /**
- * Returns all L2 Tunnels.
- *
- * @return List of tunnels.
- */
@Override
public List<L2Tunnel> getL2Tunnels() {
@@ -227,33 +258,108 @@
}
@Override
- public void processLinkDown(Link link) {
+ public List<L2TunnelPolicy> getL2PendingPolicies() {
- List<L2Tunnel> tunnels = getL2Tunnels();
- List<L2TunnelPolicy> policies = getL2Policies();
+ return new ArrayList<>(pendingL2PolicyStore
+ .values()
+ .stream()
+ .map(Versioned::value)
+ .collect(Collectors.toList()));
+ }
- // determine affected pseudowires and update them at once
- Set<L2TunnelDescription> pwToUpdate = tunnels
- .stream()
- .filter(tun -> tun.pathUsed().contains(link))
- .map(l2Tunnel -> {
- L2TunnelPolicy policy = null;
- for (L2TunnelPolicy l2Policy : policies) {
- if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
- policy = l2Policy;
- break;
- }
- }
+ @Override
+ public List<L2Tunnel> getL2PendingTunnels() {
- return new DefaultL2TunnelDescription(l2Tunnel, policy);
- })
- .collect(Collectors.toSet());
+ return new ArrayList<>(pendingL2TunnelStore
+ .values()
+ .stream()
+ .map(Versioned::value)
+ .collect(Collectors.toList()));
+ }
+ /**
+ * Manages intermediate filtering rules.
+ *
+ * For leaf-spine-spine pseudowires we need to install a special filtering
+ * rule in the intermediate spine for the appropriate transport vlan.
+ *
+ * @param pw The pseudowire, it will have the path and the transport vlan.
+ */
+ private Result manageIntermediateFiltering(L2TunnelDescription pw, boolean leafSpinePw) {
- log.info("Pseudowires affected by link failure : {}, rerouting them...", pwToUpdate);
+ // only leaf-spine-spine should need intermediate rules for now
+ if (!leafSpinePw) {
+ return Result.SUCCESS;
+ }
+ if (pw.l2Tunnel().pathUsed().size() != 2) {
+ return Result.SUCCESS;
+ }
- // update all pseudowires
- pwToUpdate.forEach(tun -> updatePw(tun, tun));
+ List<Link> path = pw.l2Tunnel().pathUsed();
+ DeviceId intermediateSpineId = pw.l2Tunnel().pathUsed().get(0).dst().deviceId();
+ L2Tunnel l2Tunnel = pw.l2Tunnel();
+
+ log.info("Installing intermediate filtering rules for spine {} , for pseudowire {}",
+ intermediateSpineId, pw.l2Tunnel().tunnelId());
+
+ MacAddress dstMac;
+ try {
+ dstMac = srManager.deviceConfiguration().getDeviceMac(intermediateSpineId);
+ } catch (Exception e) {
+ log.info("Device not found in configuration, no programming of MAC address");
+ dstMac = null;
+ }
+
+ PortNumber inPort;
+
+ inPort = path.get(0).dst().port();
+
+ log.debug("Populating filtering objective for pseudowire transport" +
+ " with vlan = {}, port = {}, mac = {} for device {}",
+ l2Tunnel.transportVlan(),
+ inPort,
+ dstMac,
+ intermediateSpineId);
+
+ FilteringObjective.Builder filteringObjectiveBuilder =
+ createNormalPipelineFiltObjective(inPort, l2Tunnel.transportVlan(), dstMac);
+ DefaultObjectiveContext context = new DefaultObjectiveContext((objective) ->
+ log.debug("Special filtObj for " +
+ "for {} populated",
+ l2Tunnel.tunnelId()),
+ (objective, error) ->
+ log.warn("Failed to populate " +
+ "special filtObj " +
+ "rule for {}: {}",
+ l2Tunnel.tunnelId(), error));
+ TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
+ filteringObjectiveBuilder.withMeta(treatment.build());
+ srManager.flowObjectiveService.filter(intermediateSpineId, filteringObjectiveBuilder.add(context));
+
+ inPort = path.get(1).src().port();
+
+ log.debug("Populating filtering objective for pseudowire transport" +
+ " with vlan = {}, port = {}, mac = {} for device {}",
+ l2Tunnel.transportVlan(),
+ inPort,
+ dstMac,
+ intermediateSpineId);
+
+ filteringObjectiveBuilder =
+ createNormalPipelineFiltObjective(inPort, l2Tunnel.transportVlan(), dstMac);
+ context = new DefaultObjectiveContext((objective) ->
+ log.debug("Special filtObj for " + "for {} populated",
+ l2Tunnel.tunnelId()),
+ (objective, error) ->
+ log.warn("Failed to populate " +
+ "special filtObj " +
+ "rule for {}: {}",
+ l2Tunnel.tunnelId(), error));
+ treatment = DefaultTrafficTreatment.builder();
+ filteringObjectiveBuilder.withMeta(treatment.build());
+ srManager.flowObjectiveService.filter(intermediateSpineId, filteringObjectiveBuilder.add(context));
+
+ return Result.SUCCESS;
}
/**
@@ -270,7 +376,6 @@
*/
private VlanId determineEgressVlan(VlanId ingressOuter, VlanId ingressInner,
VlanId egressOuter, VlanId egressInner) {
-
// validity of vlan combinations was checked at verifyPseudowire
if (!(ingressOuter.equals(VlanId.NONE))) {
return egressOuter;
@@ -329,23 +434,44 @@
/**
* Adds a single pseudowire.
*
- * @param pw The pseudowire
- * @param spinePw True if pseudowire is from leaf to spine
+ * @param pw The pseudowire to deploy
+ * @param removeFromPending if to remove the pseudowire from the pending store
* @return result of pseudowire deployment
*/
- private Result deployPseudowire(L2TunnelDescription pw, boolean spinePw) {
+ private Result deployPseudowire(L2TunnelDescription pw, boolean removeFromPending) {
Result result;
long l2TunnelId;
l2TunnelId = pw.l2Tunnel().tunnelId();
-
// The tunnel id cannot be 0.
if (l2TunnelId == 0) {
log.warn("Tunnel id id must be > 0");
return Result.ADDITION_ERROR;
}
+ // leafSpinePw determines if this is a leaf-leaf
+ // or leaf-spine pseudowire
+ boolean leafSpinePw;
+ ConnectPoint cp1 = pw.l2TunnelPolicy().cP1();
+ ConnectPoint cp2 = pw.l2TunnelPolicy().cP2();
+ try {
+ // differentiate between leaf-leaf pseudowires and leaf-spine
+ if (!srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
+ !srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
+ log.error("Can not deploy pseudowire from spine to spine!");
+ return Result.INTERNAL_ERROR;
+ } else if (srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
+ srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
+ leafSpinePw = false;
+ } else {
+ leafSpinePw = true;
+ }
+ } catch (DeviceConfigNotFoundException e) {
+ log.error("A device for pseudowire connection points does not exist.");
+ return Result.INTERNAL_ERROR;
+ }
+
// get path here, need to use the same for fwd and rev direction
List<Link> path = getPath(pw.l2TunnelPolicy().cP1(),
pw.l2TunnelPolicy().cP2());
@@ -363,18 +489,18 @@
return INTERNAL_ERROR;
}
- // spinePw signifies if we have a leaf-spine pw
- // thus only one label should be pushed (that of pw)
- // if size>1 we need to push intermediate labels also.
+ // oneHope flag is used to determine if we need to
+ // install transit mpls rules
+ boolean oneHop = true;
if (path.size() > 1) {
- spinePw = false;
+ oneHop = false;
}
fwdNextHop = path.get(0);
revNextHop = reverseLink(path.get(path.size() - 1));
pw.l2Tunnel().setPath(path);
- pw.l2Tunnel().setTransportVlan(determineTransportVlan(spinePw));
+ pw.l2Tunnel().setTransportVlan(determineTransportVlan(leafSpinePw));
// next hops for next objectives
log.info("Deploying process : Establishing forward direction for pseudowire {}", l2TunnelId);
@@ -390,7 +516,8 @@
pw.l2TunnelPolicy().cP2(),
FWD,
fwdNextHop,
- spinePw,
+ leafSpinePw,
+ oneHop,
egressVlan);
if (result != SUCCESS) {
log.info("Deploying process : Error in deploying pseudowire initiation for CP1");
@@ -414,7 +541,8 @@
pw.l2TunnelPolicy().cP2(),
egressVlan,
FWD,
- spinePw);
+ leafSpinePw,
+ oneHop);
if (result != SUCCESS) {
log.info("Deploying process : Error in deploying pseudowire termination for CP1");
@@ -435,7 +563,8 @@
pw.l2TunnelPolicy().cP1(),
REV,
revNextHop,
- spinePw,
+ leafSpinePw,
+ oneHop,
egressVlan);
if (result != SUCCESS) {
log.info("Deploying process : Error in deploying pseudowire initiation for CP2");
@@ -455,21 +584,41 @@
}
result = deployPseudoWireTerm(pw.l2Tunnel(),
- pw.l2TunnelPolicy().cP1(),
- egressVlan,
- REV,
- spinePw);
+ pw.l2TunnelPolicy().cP1(),
+ egressVlan,
+ REV,
+ leafSpinePw,
+ oneHop);
if (result != SUCCESS) {
log.info("Deploying process : Error in deploying pseudowire termination for CP2");
return Result.ADDITION_ERROR;
}
+ result = manageIntermediateFiltering(pw, leafSpinePw);
+ if (result != SUCCESS) {
+ log.info("Deploying process : Error in installing intermediate rules for tagged transport!");
+ return Result.ADDITION_ERROR;
+ }
+
log.info("Deploying process : Updating relevant information for pseudowire {}", l2TunnelId);
- // Populate stores
+ // Populate stores as the final step of the process
l2TunnelStore.put(Long.toString(l2TunnelId), pw.l2Tunnel());
l2PolicyStore.put(Long.toString(l2TunnelId), pw.l2TunnelPolicy());
+ // if removeFromPending then remove the information from the pending stores.
+ if (removeFromPending) {
+ // check existence of tunnels/policy in the pending store, if one is missing abort!
+ Versioned<L2Tunnel> l2TunnelVersioned = pendingL2TunnelStore.get(Long.toString(l2TunnelId));
+ Versioned<L2TunnelPolicy> l2TunnelPolicyVersioned = pendingL2PolicyStore.get(Long.toString(l2TunnelId));
+ if ((l2TunnelVersioned == null) || (l2TunnelPolicyVersioned == null)) {
+ log.warn("Removal process : Policy and/or tunnel missing for tunnel id {} in pending store",
+ l2TunnelId);
+ } else {
+ pendingL2TunnelStore.remove(Long.toString(l2TunnelId));
+ pendingL2PolicyStore.remove(Long.toString(l2TunnelId));
+ }
+ }
return Result.SUCCESS;
}
@@ -484,31 +633,9 @@
Result result;
for (L2TunnelDescription currentL2Tunnel : pwToAdd) {
- ConnectPoint cp1 = currentL2Tunnel.l2TunnelPolicy().cP1();
- ConnectPoint cp2 = currentL2Tunnel.l2TunnelPolicy().cP2();
+ // add pseudowires one by one
long tunnelId = currentL2Tunnel.l2TunnelPolicy().tunnelId();
-
-
- try {
- // differentiate between leaf-leaf pseudowires and leaf-spine
- // and pass the appropriate flag in them.
- if (!srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
- !srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
- log.warn("Can not deploy pseudowire from spine to spine!");
- result = Result.INTERNAL_ERROR;
- } else if (srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) &&
- srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) {
- log.info("Deploying a leaf-leaf pseudowire {}", tunnelId);
- result = deployPseudowire(currentL2Tunnel, false);
- } else {
- log.info("Deploying a leaf-spine pseudowire {}", tunnelId);
- result = deployPseudowire(currentL2Tunnel, true);
- }
- } catch (DeviceConfigNotFoundException e) {
- log.error("Exception caught when deploying pseudowire", e.toString());
- result = Result.INTERNAL_ERROR;
- }
-
+ result = deployPseudowire(currentL2Tunnel, false);
switch (result) {
case INTERNAL_ERROR:
log.warn("Could not deploy pseudowire {}, internal error!", tunnelId);
@@ -541,6 +668,7 @@
* @param oldPw the pseudo wire to remove
* @param newPw the pseudo wire to add
*/
+ /*
private void updatePw(L2TunnelDescription oldPw,
L2TunnelDescription newPw) {
ConnectPoint oldCp1 = oldPw.l2TunnelPolicy().cP1();
@@ -653,9 +781,11 @@
// spinePw signifies if we have a leaf-spine pw
// thus only one label should be pushed (that of pw)
// if size>1 we need to push intermediate labels also.
+ boolean oneHope = true;
if (path.size() > 1) {
- newPwSpine = false;
+ oneHope = false;
}
+ final boolean oneHopeFinal = oneHope;
fwdNextHop = path.get(0);
revNextHop = reverseLink(path.get(path.size() - 1));
@@ -681,7 +811,7 @@
log.debug("Update process : Deploying new fwd pw for {}", tunnelId);
Result lamdaResult = deployPseudoWireInit(newPw.l2Tunnel(), newPw.l2TunnelPolicy().cP1(),
newPw.l2TunnelPolicy().cP2(), FWD,
- fwdNextHop, finalNewPwSpine, egressVlanId);
+ fwdNextHop, finalNewPwSpine, oneHopeFinal, egressVlanId);
if (lamdaResult != SUCCESS) {
return;
}
@@ -694,7 +824,7 @@
return;
}
deployPseudoWireTerm(newPw.l2Tunnel(), newPw.l2TunnelPolicy().cP2(),
- egressVlanId, FWD, finalNewPwSpine);
+ egressVlanId, FWD, finalNewPwSpine, oneHopeFinal);
}
});
@@ -712,7 +842,7 @@
newPw.l2TunnelPolicy().cP2(),
newPw.l2TunnelPolicy().cP1(),
REV,
- revNextHop, finalNewPwSpine, egressVlanId);
+ revNextHop, finalNewPwSpine, oneHopeFinal, egressVlanId);
if (lamdaResult != SUCCESS) {
return;
}
@@ -729,22 +859,22 @@
deployPseudoWireTerm(newPw.l2Tunnel(),
newPw.l2TunnelPolicy().cP1(),
egressVlanId,
- REV, finalNewPwSpine);
+ REV, finalNewPwSpine, oneHopeFinal);
}
});
}
+ */
/**
- * Helper function for removing a single pseudowire.
- * <p>
- * No mastership of CP1 is checked, because it can be called from
- * the CLI for removal of pseudowires.
+ * Tears down connection points of pseudowires. We can either tear down both connection points,
+ * or each one of them.
*
- * @param l2TunnelId the id of the pseudowire to tear down
- * @return Returns SUCCESS if no error is obeserved or an appropriate
- * error on a failure
+ * @param l2TunnelId The tunnel id for this pseudowire.
+ * @param tearDownFirst Boolean, true if we want to tear down cp1
+ * @param tearDownSecond Boolean, true if we want to tear down cp2
+ * @return
*/
- private Result tearDownPseudowire(long l2TunnelId) {
+ private Result tearDownConnectionPoints(long l2TunnelId, boolean tearDownFirst, boolean tearDownSecond) {
CompletableFuture<ObjectiveError> fwdInitNextFuture = new CompletableFuture<>();
CompletableFuture<ObjectiveError> fwdTermNextFuture = new CompletableFuture<>();
@@ -766,7 +896,7 @@
}
L2TunnelDescription pwToRemove = new DefaultL2TunnelDescription(l2TunnelVersioned.value(),
- l2TunnelPolicyVersioned.value());
+ l2TunnelPolicyVersioned.value());
// remove the tunnels and the policies from the store
l2PolicyStore.remove(Long.toString(l2TunnelId));
@@ -777,92 +907,103 @@
vlanStore.remove(pwToRemove.l2Tunnel().transportVlan());
}
- log.info("Removal process : Tearing down forward direction of pseudowire {}", l2TunnelId);
+ if (tearDownFirst) {
+ log.info("Removal process : Tearing down forward direction of pseudowire {}", l2TunnelId);
- VlanId egressVlan = determineEgressVlan(pwToRemove.l2TunnelPolicy().cP1OuterTag(),
- pwToRemove.l2TunnelPolicy().cP1InnerTag(),
- pwToRemove.l2TunnelPolicy().cP2OuterTag(),
- pwToRemove.l2TunnelPolicy().cP2InnerTag());
- deletePolicy(l2TunnelId,
- pwToRemove.l2TunnelPolicy().cP1(),
- pwToRemove.l2TunnelPolicy().cP1InnerTag(),
- pwToRemove.l2TunnelPolicy().cP1OuterTag(),
- egressVlan,
- fwdInitNextFuture,
- FWD);
+ VlanId egressVlan = determineEgressVlan(pwToRemove.l2TunnelPolicy().cP1OuterTag(),
+ pwToRemove.l2TunnelPolicy().cP1InnerTag(),
+ pwToRemove.l2TunnelPolicy().cP2OuterTag(),
+ pwToRemove.l2TunnelPolicy().cP2InnerTag());
+ deletePolicy(l2TunnelId,
+ pwToRemove.l2TunnelPolicy().cP1(),
+ pwToRemove.l2TunnelPolicy().cP1InnerTag(),
+ pwToRemove.l2TunnelPolicy().cP1OuterTag(),
+ egressVlan,
+ fwdInitNextFuture,
+ FWD);
- fwdInitNextFuture.thenAcceptAsync(status -> {
- if (status == null) {
- // Finally we will tear down the pseudo wire.
- tearDownPseudoWireInit(l2TunnelId,
- pwToRemove.l2TunnelPolicy().cP1(),
- fwdTermNextFuture,
- FWD);
- }
- });
+ fwdInitNextFuture.thenAcceptAsync(status -> {
+ if (status == null) {
+ // Finally we will tear down the pseudo wire.
+ tearDownPseudoWireInit(l2TunnelId,
+ pwToRemove.l2TunnelPolicy().cP1(),
+ fwdTermNextFuture,
+ FWD);
+ }
+ });
- fwdTermNextFuture.thenAcceptAsync(status -> {
- if (status == null) {
- tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
- pwToRemove.l2TunnelPolicy().cP2(),
- null,
- FWD);
- }
- });
+ fwdTermNextFuture.thenAcceptAsync(status -> {
+ if (status == null) {
+ tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
+ pwToRemove.l2TunnelPolicy().cP2(),
+ null,
+ FWD);
+ }
+ });
+ }
- log.info("Removal process : Tearing down reverse direction of pseudowire {}", l2TunnelId);
+ if (tearDownSecond) {
+ log.info("Removal process : Tearing down reverse direction of pseudowire {}", l2TunnelId);
- egressVlan = determineEgressVlan(pwToRemove.l2TunnelPolicy().cP2OuterTag(),
- pwToRemove.l2TunnelPolicy().cP2InnerTag(),
- pwToRemove.l2TunnelPolicy().cP1OuterTag(),
- pwToRemove.l2TunnelPolicy().cP1InnerTag());
+ VlanId egressVlan = determineEgressVlan(pwToRemove.l2TunnelPolicy().cP2OuterTag(),
+ pwToRemove.l2TunnelPolicy().cP2InnerTag(),
+ pwToRemove.l2TunnelPolicy().cP1OuterTag(),
+ pwToRemove.l2TunnelPolicy().cP1InnerTag());
- // We do the same operations on the reverse side.
- deletePolicy(l2TunnelId,
- pwToRemove.l2TunnelPolicy().cP2(),
- pwToRemove.l2TunnelPolicy().cP2InnerTag(),
- pwToRemove.l2TunnelPolicy().cP2OuterTag(),
- egressVlan,
- revInitNextFuture,
- REV);
+ // We do the same operations on the reverse side.
+ deletePolicy(l2TunnelId,
+ pwToRemove.l2TunnelPolicy().cP2(),
+ pwToRemove.l2TunnelPolicy().cP2InnerTag(),
+ pwToRemove.l2TunnelPolicy().cP2OuterTag(),
+ egressVlan,
+ revInitNextFuture,
+ REV);
- revInitNextFuture.thenAcceptAsync(status -> {
- if (status == null) {
- tearDownPseudoWireInit(l2TunnelId,
- pwToRemove.l2TunnelPolicy().cP2(),
- revTermNextFuture,
- REV);
- }
- });
+ revInitNextFuture.thenAcceptAsync(status -> {
+ if (status == null) {
+ tearDownPseudoWireInit(l2TunnelId,
+ pwToRemove.l2TunnelPolicy().cP2(),
+ revTermNextFuture,
+ REV);
+ }
+ });
- revTermNextFuture.thenAcceptAsync(status -> {
- if (status == null) {
- tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
- pwToRemove.l2TunnelPolicy().cP1(),
- null,
- REV);
- }
- });
+ revTermNextFuture.thenAcceptAsync(status -> {
+ if (status == null) {
+ tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
+ pwToRemove.l2TunnelPolicy().cP1(),
+ null,
+ REV);
+ }
+ });
+ }
return Result.SUCCESS;
}
+ /**
+ * Helper function for removing a single pseudowire.
+ * <p>
+ * No mastership of CP1 is checked, because it can be called from
+ * the CLI for removal of pseudowires.
+ *
+ * @param l2TunnelId the id of the pseudowire to tear down
+ * @return Returns SUCCESS if no error is obeserved or an appropriate
+ * error on a failure
+ */
+ private Result tearDownPseudowire(long l2TunnelId) {
+ return tearDownConnectionPoints(l2TunnelId, true, true);
+ }
+
@Override
public void tearDown(Set<L2TunnelDescription> pwToRemove) {
- Result result;
-
- // We remove all the pw in the configuration file.
for (L2TunnelDescription currentL2Tunnel : pwToRemove) {
- ConnectPoint cp1 = currentL2Tunnel.l2TunnelPolicy().cP1();
- ConnectPoint cp2 = currentL2Tunnel.l2TunnelPolicy().cP2();
- long tunnelId = currentL2Tunnel.l2TunnelPolicy().tunnelId();
- // no need to differentiate here between leaf-leaf and leaf-spine, because
- // the only change is in the groups, which we do not remove either way
+ long tunnelId = currentL2Tunnel.l2TunnelPolicy().tunnelId();
log.info("Removing pseudowire {}", tunnelId);
- result = tearDownPseudowire(tunnelId);
+ Result result = tearDownPseudowire(tunnelId);
switch (result) {
case WRONG_PARAMETERS:
log.warn("Error in supplied parameters for the pseudowire removal with tunnel id {}!",
@@ -951,7 +1092,7 @@
*/
private Result deployPseudoWireInit(L2Tunnel l2Tunnel, ConnectPoint ingress,
ConnectPoint egress, Direction direction,
- Link nextHop, boolean spinePw, VlanId termVlanId) {
+ Link nextHop, boolean spinePw, boolean oneHop, VlanId termVlanId) {
if (nextHop == null) {
log.warn("No path between ingress and egress cps for tunnel {}", l2Tunnel.tunnelId());
@@ -967,6 +1108,7 @@
l2Tunnel,
egress.deviceId(),
spinePw,
+ oneHop,
termVlanId);
if (nextObjectiveBuilder == null) {
@@ -1016,12 +1158,13 @@
* @return the result of the operation
*/
private Result deployPseudoWireTerm(L2Tunnel l2Tunnel, ConnectPoint egress,
- VlanId egressVlan, Direction direction, boolean spinePw) {
+ VlanId egressVlan, Direction direction, boolean spinePw, boolean oneHop) {
// We create the group relative to the termination.
NextObjective.Builder nextObjectiveBuilder = createNextObjective(TERMINATION, egress, null,
l2Tunnel, egress.deviceId(),
spinePw,
+ oneHop,
egressVlan);
if (nextObjectiveBuilder == null) {
return INTERNAL_ERROR;
@@ -1238,12 +1381,15 @@
* @param dstCp the destination port
* @param l2Tunnel the tunnel to support
* @param egressId the egress device id
- * @param spinePw if the pw involves a spine switch
+ * @param oneHop if the pw only has one hop, push only pw label
+ * @param leafSpinePw true if we want instantiate a leaf-spine or leaf-spine-spine pw
+ * @param termVlanId the outer vlan id of the packet exiting a termination point
* @return the next objective to support the pipeline
*/
private NextObjective.Builder createNextObjective(Pipeline pipeline, ConnectPoint srcCp,
ConnectPoint dstCp, L2Tunnel l2Tunnel,
- DeviceId egressId, boolean spinePw, VlanId termVlanId) {
+ DeviceId egressId, boolean leafSpinePw,
+ boolean oneHop, VlanId termVlanId) {
NextObjective.Builder nextObjBuilder;
TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
if (pipeline == INITIATION) {
@@ -1270,9 +1416,8 @@
treatmentBuilder.copyTtlOut();
}
- // if pw is leaf-to-leaf we need to
- // add the routing label also
- if (!spinePw) {
+ // if not oneHop install transit mpls labels also
+ if (!oneHop) {
// We retrieve the sr label from the config
// specific for pseudowire traffic
// using the egress leaf device id.
@@ -1309,13 +1454,14 @@
}
treatmentBuilder.setEthDst(neighborMac);
- // if not a leaf-spine pw we need to POP the vlan at the output
- // since we carry this traffic untagged.
- if (!spinePw) {
+ // if true we need to pop the vlan because
+ // we instantiate a leaf to leaf pseudowire
+ if (!leafSpinePw) {
+ log.info("We should carry this traffic UNTAGGED!");
treatmentBuilder.popVlan();
}
- // set the appropriate transport vlan
+ // set the appropriate transport vlan from tunnel information
treatmentBuilder.setVlanId(l2Tunnel.transportVlan());
} else {
// We create the next objective which
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
index c3d5ccf..2f845cd 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
@@ -16,8 +16,6 @@
package org.onosproject.segmentrouting.pwaas;
-import org.onosproject.net.Link;
-
import java.util.List;
import java.util.Set;
@@ -27,9 +25,11 @@
/**
* Combines policies and tunnels to create descriptions.
*
+ * @param pending if it is true return pending to be installed pseudowires
+ * from the appropriate store, else return installed pseudowires
* @return Set of l2 tunnel descriptions.
*/
- Set<L2TunnelDescription> getL2Descriptions();
+ Set<L2TunnelDescription> getL2Descriptions(boolean pending);
/**
* Returns a copy of the l2 policies that exist in the store.
@@ -46,12 +46,18 @@
List<L2Tunnel> getL2Tunnels();
/**
- * Processes a link removal. Finds affected pseudowires and rewires them.
- * TODO: Make it also take into account failures of links that are used for pw
- * traffic in the spine.
- * @param link The link that failed
+ * Returns a copy of the pending l2 policies that exist in the store.
+ *
+ * @return The l2 policies
*/
- void processLinkDown(Link link);
+ List<L2TunnelPolicy> getL2PendingPolicies();
+
+ /**
+ * Returns a copy of the pending l2 tunnels that exist in the store.
+ *
+ * @return The l2 tunnels.
+ */
+ List<L2Tunnel> getL2PendingTunnels();
/**
* Helper function to handle the pw removal.
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
index fa2807e..d17ec10 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
@@ -16,8 +16,6 @@
package org.onosproject.segmentrouting.pwaas;
-import org.apache.felix.scr.annotations.Reference;
-import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.MplsLabel;
import org.onlab.packet.VlanId;
import org.onosproject.cli.AbstractShellCommand;
@@ -25,6 +23,7 @@
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -42,11 +41,9 @@
private static final Logger log = LoggerFactory.getLogger(PwaasUtil.class);
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- public static DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);;
+ private static DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);;
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- public static InterfaceService intfService = AbstractShellCommand.get(InterfaceService.class);
+ private static InterfaceService intfService = AbstractShellCommand.get(InterfaceService.class);
private PwaasUtil() {
return;
@@ -440,7 +437,7 @@
}
- public static boolean configurationValidity(Set<L2TunnelDescription> pseudowires) {
+ public static boolean configurationValidity(List<L2TunnelDescription> pseudowires) {
// structures to keep pw information
// in order to see if instantiating them will create
@@ -458,15 +455,14 @@
// Ideally we would like to return a String which could also return to
// the user issuing the rest request for adding the pseudowire.
try {
-
// check that pseudowires can be instantiated in the network
// we try to guarantee that all the pws will work before
// instantiating any of them
for (L2TunnelDescription pw : pseudowires) {
+ log.debug("Verifying pseudowire {}", pw);
verifyPseudoWire(pw, labelsUsed, vlanIds, tunIds);
}
} catch (Exception e) {
-
log.error("Caught exception while validating pseudowire : {}", e.getMessage());
return false;
}
diff --git a/apps/segmentrouting/web/src/main/resources/definitions/PseudowireCreate.json b/apps/segmentrouting/web/src/main/resources/definitions/PseudowireCreate.json
index feddd18..315d01d 100644
--- a/apps/segmentrouting/web/src/main/resources/definitions/PseudowireCreate.json
+++ b/apps/segmentrouting/web/src/main/resources/definitions/PseudowireCreate.json
@@ -61,7 +61,7 @@
},
"pwLabel": {
"type": "256",
- "example": "",
+ "example": "1577",
"description": "Pseudowire label."
}
}
diff --git a/apps/segmentrouting/web/src/main/resources/definitions/PseudowireCreateBulk.json b/apps/segmentrouting/web/src/main/resources/definitions/PseudowireCreateBulk.json
index 44db619..752e6eb 100644
--- a/apps/segmentrouting/web/src/main/resources/definitions/PseudowireCreateBulk.json
+++ b/apps/segmentrouting/web/src/main/resources/definitions/PseudowireCreateBulk.json
@@ -56,7 +56,7 @@
},
"pwLabel": {
"type": "256",
- "example": "",
+ "example": "1577",
"description": "Pseudowire label."
}
}