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 277a1c3fda..d7d22b4da2 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 @@ -100,8 +100,9 @@ public class PseudowireAddCommand extends AbstractShellCommand { try { tun = new DefaultL2Tunnel(parseMode(mode), parseVlan(sDTag), parsePwId(pwId), parsePWLabel(pwLabel)); - } catch (Exception e) { - print("Exception while parsing L2Tunnel : {}", e); + } catch (IllegalArgumentException e) { + log.error("Exception while parsing L2Tunnel : \n\t %s", e.getMessage()); + print("Exception while parsing L2Tunnel : \n\t %s", e.getMessage()); return; } @@ -111,13 +112,15 @@ public class PseudowireAddCommand extends AbstractShellCommand { parseVlan(cP1OuterVlan), ConnectPoint.deviceConnectPoint(cP2), parseVlan(cP2InnerVlan), parseVlan(cP2OuterVlan)); - } catch (Exception e) { - print("Exception while parsing L2TunnelPolicy : {}", e); + } catch (IllegalArgumentException e) { + log.error("Exception while parsing L2TunnelPolicy : \n\t %s", e.getMessage()); + print("Exception while parsing L2TunnelPolicy : \n\t %s", e.getMessage()); return; } L2TunnelDescription pw = new DefaultL2TunnelDescription(tun, policy); L2TunnelHandler.Result res = srService.addPseudowire(pw); + log.info("Deploying pseudowire {} via the command line.", pw); switch (res) { case WRONG_PARAMETERS: print("Pseudowire could not be added , error in the parameters : \n\t%s", diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java index 362ebbbada..d0f217dfd9 100644 --- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java +++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java @@ -49,11 +49,13 @@ public class PseudowireRemoveCommand extends AbstractShellCommand { int pwIntId; try { pwIntId = parsePwId(pwId); - } catch (Exception e) { - print("Exception while parsing pseudowire id : {}", e); + } catch (IllegalArgumentException e) { + log.error("Exception while parsing pseudowire id : \n\t %s", e.getMessage()); + print("Exception while parsing pseudowire id : \n\t %s", e.getMessage()); return; } + log.info("Removing pseudowire {} from the command line.", pwIntId); L2TunnelHandler.Result res = mngr.removePseudowire(pwIntId); switch (res) { case WRONG_PARAMETERS: 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 c736614c9b..e40dcb8b6a 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 @@ -52,8 +52,10 @@ import org.onosproject.segmentrouting.SegmentRoutingService; import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException; import org.onosproject.store.serializers.KryoNamespaces; import org.onosproject.store.service.ConsistentMap; +import org.onosproject.store.service.DistributedLock; import org.onosproject.store.service.DistributedSet; import org.onosproject.store.service.Serializer; +import org.onosproject.store.service.StorageException; import org.onosproject.store.service.Versioned; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,10 +76,11 @@ import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.REV import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*; /** - * Handles pwaas related events. + * Handler for pseudowire management. */ public class DefaultL2TunnelHandler implements L2TunnelHandler { + private static final String LOCK_NAME = "l2-tunnel-handler-lock"; private static final Logger log = LoggerFactory.getLogger(DefaultL2TunnelHandler.class); private final SegmentRoutingManager srManager; @@ -117,6 +120,13 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { */ private final DistributedSet vlanStore; + /** + * Lock used when creating or removing pseudowires. + */ + private final DistributedLock pwLock; + + private static final long LOCK_TIMEOUT = 2000; + /** * Used for determining transport vlans for leaf-spine. */ @@ -188,6 +198,11 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { .build())) .build() .asDistributedSet(); + + pwLock = srManager.storageService.lockBuilder() + .withName(LOCK_NAME) + .build() + .asLock(LOCK_TIMEOUT); } /** @@ -281,10 +296,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { private Result manageIntermediateFiltering(L2TunnelDescription pw, boolean leafSpinePw) { // only leaf-spine-spine should need intermediate rules for now - if (!leafSpinePw) { - return Result.SUCCESS; - } - if (pw.l2Tunnel().pathUsed().size() != 2) { + if (!leafSpinePw || (pw.l2Tunnel().pathUsed().size() != 2)) { return Result.SUCCESS; } @@ -292,7 +304,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { DeviceId intermediateSpineId = pw.l2Tunnel().pathUsed().get(0).dst().deviceId(); L2Tunnel l2Tunnel = pw.l2Tunnel(); - log.info("Installing intermediate filtering rules for spine {} , for pseudowire {}", + log.debug("Installing intermediate filtering rules for spine {} , for pseudowire {}", intermediateSpineId, pw.l2Tunnel().tunnelId()); MacAddress dstMac; @@ -394,7 +406,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { if (!spinePw) { - log.info("Untagged transport with internal vlan {} for pseudowire!", UNTAGGED_TRANSPORT_VLAN); + log.debug("Untagged transport with internal vlan {} for pseudowire!", UNTAGGED_TRANSPORT_VLAN); return UNTAGGED_TRANSPORT_VLAN; } else { for (short i = transportVlanUpper; i > transportVlanLower; i--) { @@ -403,12 +415,12 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { if (!vlanStore.contains(vlanToUse)) { vlanStore.add(vlanToUse); - log.info("Transport vlan {} for pseudowire!", vlanToUse); + log.debug("Transport vlan {} for pseudowire!", vlanToUse); return vlanToUse; } } - log.info("No available transport vlan found, pseudowire traffic will be carried untagged " + + log.warn("No available transport vlan found, pseudowire traffic will be carried untagged " + "with internal vlan {}!", UNTAGGED_TRANSPORT_VLAN); return UNTAGGED_TRANSPORT_VLAN; } @@ -455,6 +467,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { */ private boolean isValidPath(List path, boolean leafSpinePw) { + log.debug("Checking path validity for pseudowire."); List devices = getDevicesOnPath(path); if (devices.size() < 2) { log.error("Path size for pseudowire should be greater than 1!"); @@ -528,196 +541,202 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { */ public Result deployPseudowire(L2TunnelDescription pw) { - Result result; - long l2TunnelId; - - log.debug("Pseudowire with {} deployment started, check log for any errors in this process!", - pw.l2Tunnel().tunnelId()); - - l2TunnelId = pw.l2Tunnel().tunnelId(); - // The tunnel id cannot be 0. - if (l2TunnelId == 0) { - log.warn("Tunnel id id must be > 0"); - return Result.WRONG_PARAMETERS - .appendError("Tunnel id id must be > 0"); - } - - result = verifyGlobalValidity(pw); - if (result != SUCCESS) { - log.error("Global validity for pseudowire {} is wrong!", l2TunnelId); - return result; - } - - // 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!"); + // take the lock + pwLock.lock(); + Result result; + long l2TunnelId; + log.debug("Pseudowire with {} deployment started, check log for any errors in this process!", + pw.l2Tunnel().tunnelId()); + l2TunnelId = pw.l2Tunnel().tunnelId(); + // The tunnel id cannot be 0. + if (l2TunnelId == 0) { + log.warn("Tunnel id id must be > 0 in {}", l2TunnelId); return Result.WRONG_PARAMETERS - .appendError("Can not deploy pseudowire from spine to spine!"); - } else if (srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) && - srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) { - leafSpinePw = false; - } else { - leafSpinePw = true; + .appendError("Tunnel id id must be > 0"); } - } catch (DeviceConfigNotFoundException e) { - log.error("Device for pseudowire connection points does not exist in the configuration"); - return Result.INTERNAL_ERROR - .appendError("Device for pseudowire connection points does not exist in the configuration"); + + result = verifyGlobalValidity(pw); + if (result != SUCCESS) { + log.error("Global validity for pseudowire {} is wrong!", l2TunnelId); + return result; + } + + // 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!", l2TunnelId); + return Result.WRONG_PARAMETERS + .appendError("Can not deploy pseudowire from spine to spine!"); + } else if (srManager.deviceConfiguration().isEdgeDevice(cp1.deviceId()) && + srManager.deviceConfiguration().isEdgeDevice(cp2.deviceId())) { + leafSpinePw = false; + } else { + leafSpinePw = true; + } + } catch (DeviceConfigNotFoundException e) { + log.error("Device for pseudowire {} connection points does not exist in the configuration", l2TunnelId); + return Result.INTERNAL_ERROR + .appendError("Device for pseudowire connection points does not exist in the configuration"); + } + + // reverse the policy in order for leaf switch to be at CP1 + // this will help us for re-using SRLinkWeigher for computing valid paths + L2TunnelPolicy reversedPolicy = reverseL2TunnelPolicy(pw.l2TunnelPolicy()); + if (reversedPolicy == null) { + log.error("Error in reversing policy, device configuration was not found for pseudowire {}.", + l2TunnelId); + return INTERNAL_ERROR + .appendError("Device configuration not found when reversing the policy."); + } + pw.setL2TunnelPolicy(reversedPolicy); + + // get path here, need to use the same for fwd and rev direction + List path = getPath(pw.l2TunnelPolicy().cP1(), + pw.l2TunnelPolicy().cP2()); + if (path == null) { + log.error("Deploying process : No path between the connection points for pseudowire {}", l2TunnelId); + return PATH_NOT_FOUND.appendError("No path between the connection points for pseudowire!"); + } + + Link fwdNextHop; + Link revNextHop; + if (!isValidPath(path, leafSpinePw)) { + log.error("Deploying process : Path for pseudowire {} is not valid", l2TunnelId); + return INTERNAL_ERROR.appendError("Internal error : path for pseudowire is not valid!"); + } + // oneHope flag is used to determine if we need to + // install transit mpls rules + boolean oneHop = true; + if (path.size() > 1) { + oneHop = false; + } + + fwdNextHop = path.get(0); + revNextHop = reverseLink(path.get(path.size() - 1)); + + pw.l2Tunnel().setPath(path); + pw.l2Tunnel().setTransportVlan(determineTransportVlan(leafSpinePw)); + + // next hops for next objectives + log.info("Deploying process : Establishing forward direction for pseudowire {}", l2TunnelId); + + VlanId egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP1OuterTag(), + pw.l2TunnelPolicy().cP1InnerTag(), + pw.l2TunnelPolicy().cP2OuterTag(), + pw.l2TunnelPolicy().cP2InnerTag()); + result = deployPseudoWireInit(pw.l2Tunnel(), + pw.l2TunnelPolicy().cP1(), + pw.l2TunnelPolicy().cP2(), + FWD, + fwdNextHop, + leafSpinePw, + oneHop, + egressVlan); + if (result != SUCCESS) { + log.error("Deploying process : Error in deploying pseudowire {} initiation for CP1", l2TunnelId); + return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire initiation for CP1"); + } + + result = deployPolicy(l2TunnelId, + pw.l2TunnelPolicy().cP1(), + pw.l2TunnelPolicy().cP1InnerTag(), + pw.l2TunnelPolicy().cP1OuterTag(), + egressVlan, + result.getNextId()); + if (result != SUCCESS) { + log.error("Deploying process : Error in deploying pseudowire {} policy for CP1", l2TunnelId); + return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire policy for CP1"); + } + + PortNumber termPort = pw.l2Tunnel().pathUsed().get(pw.l2Tunnel().pathUsed().size() - 1).dst().port(); + result = deployPseudoWireTerm(pw.l2Tunnel(), + pw.l2TunnelPolicy().cP2(), + egressVlan, + FWD, + leafSpinePw, + oneHop, + termPort); + + if (result != SUCCESS) { + log.error("Deploying process : Error in deploying pseudowire {} termination for CP1", l2TunnelId); + return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP1"); + } + + // We establish the reverse tunnel. + log.info("Deploying process : Establishing reverse direction for pseudowire {}", l2TunnelId); + egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP2OuterTag(), + pw.l2TunnelPolicy().cP2InnerTag(), + pw.l2TunnelPolicy().cP1OuterTag(), + pw.l2TunnelPolicy().cP1InnerTag()); + + result = deployPseudoWireInit(pw.l2Tunnel(), + pw.l2TunnelPolicy().cP2(), + pw.l2TunnelPolicy().cP1(), + REV, + revNextHop, + leafSpinePw, + oneHop, + egressVlan); + if (result != SUCCESS) { + log.error("Deploying process : Error in deploying pseudowire {} initiation for CP2", l2TunnelId); + return Result.INTERNAL_ERROR + .appendError("Error in deploying pseudowire initiation for CP2"); + } + + result = deployPolicy(l2TunnelId, + pw.l2TunnelPolicy().cP2(), + pw.l2TunnelPolicy().cP2InnerTag(), + pw.l2TunnelPolicy().cP2OuterTag(), + egressVlan, + result.getNextId()); + if (result != SUCCESS) { + log.error("Deploying process : Error in deploying policy {} for CP2", l2TunnelId); + return Result.INTERNAL_ERROR + .appendError("Deploying process : Error in deploying policy for CP2"); + } + + termPort = pw.l2Tunnel().pathUsed().get(0).src().port(); + result = deployPseudoWireTerm(pw.l2Tunnel(), + pw.l2TunnelPolicy().cP1(), + egressVlan, + REV, + leafSpinePw, + oneHop, + termPort); + + if (result != SUCCESS) { + log.error("Deploying process : Error in deploying pseudowire {} termination for CP2", l2TunnelId); + return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP2"); + } + + result = manageIntermediateFiltering(pw, leafSpinePw); + if (result != SUCCESS) { + log.error("Deploying process : Error in installing intermediate rules for " + + "tagged transport for pseudowire {}", l2TunnelId); + return Result.INTERNAL_ERROR.appendError("Error in installing intermediate rules for tagged transport"); + } + + log.info("Deploying process : Updating relevant information for pseudowire {}", l2TunnelId); + + // Populate stores as the final step of the process + l2TunnelStore.put(Long.toString(l2TunnelId), pw.l2Tunnel()); + l2PolicyStore.put(Long.toString(l2TunnelId), pw.l2TunnelPolicy()); + + return Result.SUCCESS; + } catch (StorageException.Timeout e) { + log.error("Can not acquire distributed lock for pseudowire {}!", pw.l2Tunnel().tunnelId()); + return Result.INTERNAL_ERROR.appendError("Can not acquire distributed lock!"); + } finally { + // release the lock + pwLock.unlock(); } - - // reverse the policy in order for leaf switch to be at CP1 - // this will help us for re-using SRLinkWeigher for computing valid paths - L2TunnelPolicy reversedPolicy = reverseL2TunnelPolicy(pw.l2TunnelPolicy()); - if (reversedPolicy == null) { - log.error("Error in reversing policy, device configuration was not found!"); - return INTERNAL_ERROR - .appendError("Device configuration not found when reversing the policy."); - } - pw.setL2TunnelPolicy(reversedPolicy); - - // get path here, need to use the same for fwd and rev direction - List path = getPath(pw.l2TunnelPolicy().cP1(), - pw.l2TunnelPolicy().cP2()); - if (path == null) { - log.error("Deploying process : No path between the connection points for pseudowire {}", l2TunnelId); - return PATH_NOT_FOUND.appendError("No path between the connection points for pseudowire!"); - } - - Link fwdNextHop; - Link revNextHop; - if (!isValidPath(path, leafSpinePw)) { - log.error("Deploying process : Path for pseudowire {} is not valid", - l2TunnelId); - return INTERNAL_ERROR.appendError("Internal error : path for pseudowire is not valid!"); - } - - // oneHope flag is used to determine if we need to - // install transit mpls rules - boolean oneHop = true; - if (path.size() > 1) { - oneHop = false; - } - - fwdNextHop = path.get(0); - revNextHop = reverseLink(path.get(path.size() - 1)); - - pw.l2Tunnel().setPath(path); - pw.l2Tunnel().setTransportVlan(determineTransportVlan(leafSpinePw)); - - // next hops for next objectives - log.info("Deploying process : Establishing forward direction for pseudowire {}", l2TunnelId); - - VlanId egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP1OuterTag(), - pw.l2TunnelPolicy().cP1InnerTag(), - pw.l2TunnelPolicy().cP2OuterTag(), - pw.l2TunnelPolicy().cP2InnerTag()); - // We establish the tunnel. - // result.nextId will be used in fwd - result = deployPseudoWireInit(pw.l2Tunnel(), - pw.l2TunnelPolicy().cP1(), - pw.l2TunnelPolicy().cP2(), - FWD, - fwdNextHop, - leafSpinePw, - oneHop, - egressVlan); - if (result != SUCCESS) { - log.info("Deploying process : Error in deploying pseudowire initiation for CP1"); - return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire initiation for CP1"); - } - - // We create the policy. - result = deployPolicy(l2TunnelId, - pw.l2TunnelPolicy().cP1(), - pw.l2TunnelPolicy().cP1InnerTag(), - pw.l2TunnelPolicy().cP1OuterTag(), - egressVlan, - result.getNextId()); - if (result != SUCCESS) { - log.info("Deploying process : Error in deploying pseudowire policy for CP1"); - return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire policy for CP1"); - } - - // We terminate the tunnel - result = deployPseudoWireTerm(pw.l2Tunnel(), - pw.l2TunnelPolicy().cP2(), - egressVlan, - FWD, - leafSpinePw, - oneHop); - - if (result != SUCCESS) { - log.info("Deploying process : Error in deploying pseudowire termination for CP1"); - return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP1"); - } - - log.info("Deploying process : Establishing reverse direction for pseudowire {}", l2TunnelId); - - egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP2OuterTag(), - pw.l2TunnelPolicy().cP2InnerTag(), - pw.l2TunnelPolicy().cP1OuterTag(), - pw.l2TunnelPolicy().cP1InnerTag()); - - // We establish the reverse tunnel. - result = deployPseudoWireInit(pw.l2Tunnel(), - pw.l2TunnelPolicy().cP2(), - pw.l2TunnelPolicy().cP1(), - REV, - revNextHop, - leafSpinePw, - oneHop, - egressVlan); - if (result != SUCCESS) { - log.info("Deploying process : Error in deploying pseudowire initiation for CP2"); - return Result.INTERNAL_ERROR - .appendError("Error in deploying pseudowire initiation for CP2"); - } - - - result = deployPolicy(l2TunnelId, - pw.l2TunnelPolicy().cP2(), - pw.l2TunnelPolicy().cP2InnerTag(), - pw.l2TunnelPolicy().cP2OuterTag(), - egressVlan, - result.getNextId()); - if (result != SUCCESS) { - log.info("Deploying process : Error in deploying policy for CP2"); - return Result.INTERNAL_ERROR - .appendError("Deploying process : Error in deploying policy for CP2"); - } - - result = deployPseudoWireTerm(pw.l2Tunnel(), - pw.l2TunnelPolicy().cP1(), - egressVlan, - REV, - leafSpinePw, - oneHop); - - if (result != SUCCESS) { - log.info("Deploying process : Error in deploying pseudowire termination for CP2"); - return Result.INTERNAL_ERROR.appendError("Error in deploying pseudowire termination for CP2"); - } - - result = manageIntermediateFiltering(pw, leafSpinePw); - if (result != SUCCESS) { - log.info("Deploying process : Error in installing intermediate rules for tagged transport"); - return Result.INTERNAL_ERROR.appendError("Error in installing intermediate rules for tagged transport"); - } - - log.info("Deploying process : Updating relevant information for pseudowire {}", l2TunnelId); - - // Populate stores as the final step of the process - l2TunnelStore.put(Long.toString(l2TunnelId), pw.l2Tunnel()); - l2PolicyStore.put(Long.toString(l2TunnelId), pw.l2TunnelPolicy()); - - return Result.SUCCESS; } @Override @@ -760,7 +779,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { CompletableFuture revTermNextFuture = new CompletableFuture<>(); if (l2TunnelId == 0) { - log.warn("Removal process : Tunnel id cannot be 0"); + log.error("Removal process : Tunnel id cannot be 0"); return Result.WRONG_PARAMETERS.appendError("Pseudowire id can not be 0."); } @@ -825,10 +844,13 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { fwdTermNextFuture.thenAcceptAsync(status -> { if (status == null) { + PortNumber termPort = pwToRemove.l2Tunnel().pathUsed() + .get(pwToRemove.l2Tunnel().pathUsed().size() - 1).dst().port(); tearDownPseudoWireTerm(pwToRemove.l2Tunnel(), pwToRemove.l2TunnelPolicy().cP2(), null, - FWD); + FWD, + termPort); } }); } @@ -861,10 +883,12 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { revTermNextFuture.thenAcceptAsync(status -> { if (status == null) { + PortNumber termPort = pwToRemove.l2Tunnel().pathUsed().get(0).src().port(); tearDownPseudoWireTerm(pwToRemove.l2Tunnel(), pwToRemove.l2TunnelPolicy().cP1(), null, - REV); + REV, + termPort); } }); } @@ -883,14 +907,25 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { */ public Result tearDownPseudowire(long l2TunnelId) { - if (checkIfPwExists(l2TunnelId, true) == Result.SUCCESS) { - return tearDownConnectionPoints(l2TunnelId, true, true, true); - } else if (checkIfPwExists(l2TunnelId, false) == Result.SUCCESS) { - return tearDownConnectionPoints(l2TunnelId, true, true, false); - } else { - return Result.WRONG_PARAMETERS.appendError("Pseudowire with " - + l2TunnelId - + " did not reside in any store!"); + try { + // take the lock + pwLock.lock(); + + if (checkIfPwExists(l2TunnelId, true) == Result.SUCCESS) { + return tearDownConnectionPoints(l2TunnelId, true, true, true); + } else if (checkIfPwExists(l2TunnelId, false) == Result.SUCCESS) { + return tearDownConnectionPoints(l2TunnelId, true, true, false); + } else { + return Result.WRONG_PARAMETERS.appendError("Pseudowire with " + + l2TunnelId + + " did not reside in any store!"); + } + } catch (StorageException.Timeout e) { + log.error("Can not acquire distributed lock for pseudowire {}!", l2TunnelId); + return Result.INTERNAL_ERROR.appendError("Can not acquire distributed lock!"); + } finally { + // release the lock + pwLock.unlock(); } } @@ -919,16 +954,17 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { * @param ingress the ingress point * @param ingressInner the ingress inner tag * @param ingressOuter the ingress outer tag - * @param nextId the next objective id * @param egressVlan Vlan-id to set, depends on ingress vlan * combinations. For example, if pw is double tagged * then this is the value of the outer vlan, if single * tagged then it is the new value of the single tag. * Should be None for untagged traffic. + * @param nextId the next objective id * @return the result of the operation */ private Result deployPolicy(long tunnelId, ConnectPoint ingress, VlanId ingressInner, VlanId ingressOuter, VlanId egressVlan, int nextId) { + log.debug("Starting deploying policy for pseudowire {}.", tunnelId); List objectives = Lists.newArrayList(); // We create the forwarding objective for supporting @@ -938,8 +974,9 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { ObjectiveContext context = new DefaultObjectiveContext((objective) -> log.debug("FwdObj for tunnel {} populated", tunnelId), (objective, error) -> - log.warn("Failed to populate fwdrObj " + - "for tunnel {}", tunnelId, error)); + log.warn("Failed to populate fwdObj " + + "for tunnel {} : {}", + tunnelId, error)); objectives.add(fwdBuilder.add(context)); // We create the filtering objective to define the @@ -956,7 +993,8 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { // We create and add objective context. context = new DefaultObjectiveContext((objective) -> log.debug("FilterObj for tunnel {} populated", tunnelId), (objective, error) -> log.warn("Failed to populate filterObj for " + - "tunnel {}", tunnelId, error)); + "tunnel {} : {}", + tunnelId, error)); objectives.add(filtBuilder.add(context)); for (Objective objective : objectives) { @@ -985,9 +1023,10 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { private Result deployPseudoWireInit(L2Tunnel l2Tunnel, ConnectPoint ingress, ConnectPoint egress, Direction direction, Link nextHop, boolean spinePw, boolean oneHop, VlanId termVlanId) { - + log.debug("Started deploying init next objectives for pseudowire {} for tunnel {} -> {}.", + l2Tunnel.tunnelId(), ingress, egress); if (nextHop == null) { - log.warn("No path between ingress and egress cps for tunnel {}", l2Tunnel.tunnelId()); + log.warn("No path between ingress and egress connection points for tunnel {}", l2Tunnel.tunnelId()); return WRONG_PARAMETERS; } @@ -1047,10 +1086,15 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { * @param egressVlan the expected vlan at egress * @param direction the direction * @param spinePw if the pseudowire involves a spine switch + * @param inputTermPort the input port at the termination point for the pseudowire, used for installing special + * filtering rules at the termination * @return the result of the operation */ private Result deployPseudoWireTerm(L2Tunnel l2Tunnel, ConnectPoint egress, - VlanId egressVlan, Direction direction, boolean spinePw, boolean oneHop) { + VlanId egressVlan, Direction direction, + boolean spinePw, boolean oneHop, PortNumber inputTermPort) { + log.debug("Started deploying termination objectives for pseudowire {} , direction {}.", + l2Tunnel.tunnelId(), direction == FWD ? "forward" : "reverse"); // We create the group relative to the termination. NextObjective.Builder nextObjectiveBuilder = createNextObjective(TERMINATION, egress, null, @@ -1093,7 +1137,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { context = new DefaultObjectiveContext((objective) -> log.debug("FwdObj for tunnel termination {} populated", l2Tunnel.tunnelId()), (objective, error) -> log.warn("Failed to populate fwdrObj" + - " for tunnel termination {}", + " 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 {}", @@ -1101,16 +1145,6 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { if (spinePw) { - // determine the input port at the - PortNumber inPort; - - if (egress.deviceId(). - equals(l2Tunnel.pathUsed().get(0).dst().deviceId())) { - inPort = l2Tunnel.pathUsed().get(0).dst().port(); - } else { - inPort = l2Tunnel.pathUsed().get(0).src().port(); - } - MacAddress dstMac; try { dstMac = srManager.deviceConfiguration().getDeviceMac(egress.deviceId()); @@ -1122,10 +1156,10 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { log.info("Populating filtering objective for pseudowire transport" + " with vlan = {}, port = {}, mac = {}", l2Tunnel.transportVlan(), - inPort, + inputTermPort, dstMac); FilteringObjective.Builder filteringObjectiveBuilder = - createNormalPipelineFiltObjective(inPort, l2Tunnel.transportVlan(), dstMac); + createNormalPipelineFiltObjective(inputTermPort, l2Tunnel.transportVlan(), dstMac); context = new DefaultObjectiveContext((objective) -> log.debug("Special filtObj for " + "for {} populated", l2Tunnel.tunnelId()), @@ -1139,7 +1173,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { srManager.flowObjectiveService.filter(egress.deviceId(), filteringObjectiveBuilder.add(context)); log.debug("Creating new special FiltObj for termination point with tunnel {} for port {}", l2Tunnel.tunnelId(), - inPort); + inputTermPort); } return SUCCESS; @@ -1157,7 +1191,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { VlanId vlanId, MacAddress dstMac) { - log.info("Creating filtering objective for pseudowire transport with vlan={}, port={}, mac={}", + log.debug("Creating filtering objective for pseudowire intermediate transport with vlan={}, port={}, mac={}", vlanId, inPort, dstMac); @@ -1186,7 +1220,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { */ private FilteringObjective.Builder createFiltObjective(PortNumber inPort, VlanId innerTag, VlanId outerTag) { - log.info("Creating filtering objective for vlans {} / {}", outerTag, innerTag); + log.debug("Creating connection point filtering objective for vlans {} / {}", outerTag, innerTag); return DefaultFilteringObjective .builder() .withKey(Criteria.matchInPort(inPort)) @@ -1209,6 +1243,8 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { private ForwardingObjective.Builder createTermFwdObjective(MplsLabel pwLabel, long tunnelId, PortNumber egressPort, int nextId) { + log.debug("Creating forwarding objective for termination for tunnel {} : pwLabel {}, egressPort {}, nextId {}", + tunnelId, pwLabel, egressPort, nextId); TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder(); TrafficTreatment.Builder trafficTreatment = DefaultTrafficTreatment.builder(); // The flow has to match on the pw label and bos @@ -1244,6 +1280,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { */ private ForwardingObjective.Builder createInitFwdObjective(long tunnelId, PortNumber inPort, int nextId) { + log.debug("Creating forwarding objective for tunnel {} : Port {} , nextId {}", tunnelId, inPort, nextId); TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder(); // The flow has to match on the mpls logical @@ -1282,6 +1319,9 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { ConnectPoint dstCp, L2Tunnel l2Tunnel, DeviceId egressId, boolean leafSpinePw, boolean oneHop, VlanId termVlanId) { + log.debug("Creating {} next objective for pseudowire {}.", + pipeline == TERMINATION ? "termination" : "inititation"); + NextObjective.Builder nextObjBuilder; TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder(); if (pipeline == INITIATION) { @@ -1292,7 +1332,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { // The pw label is the bottom of stack. It has to // be different -1. if (l2Tunnel.pwLabel().toInt() == MplsLabel.MAX_MPLS) { - log.warn("Pw label not configured"); + log.error("Pw label not configured"); return null; } treatmentBuilder.pushMpls(); @@ -1318,7 +1358,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { srLabel = MplsLabel.mplsLabel(srManager.deviceConfiguration().getPWRoutingLabel(egressId)); } catch (DeviceConfigNotFoundException e) { - log.warn("Sr label for pw traffic not configured"); + log.error("Sr label for pw traffic not configured"); return null; } @@ -1333,7 +1373,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { try { ingressMac = srManager.deviceConfiguration().getDeviceMac(srcCp.deviceId()); } catch (DeviceConfigNotFoundException e) { - log.warn("Was not able to find the ingress mac"); + log.error("Was not able to find the ingress mac"); return null; } treatmentBuilder.setEthSrc(ingressMac); @@ -1341,7 +1381,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { try { neighborMac = srManager.deviceConfiguration().getDeviceMac(dstCp.deviceId()); } catch (DeviceConfigNotFoundException e) { - log.warn("Was not able to find the neighbor mac"); + log.error("Was not able to find the neighbor mac"); return null; } treatmentBuilder.setEthDst(neighborMac); @@ -1349,7 +1389,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { // 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!"); + log.debug("We should carry traffic UNTAGGED for pseudowire {}", l2Tunnel.tunnelId()); treatmentBuilder.popVlan(); } @@ -1386,6 +1426,8 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { * current SRLinkWeigher */ private L2TunnelPolicy reverseL2TunnelPolicy(L2TunnelPolicy policy) { + + log.debug("Reversing policy for pseudowire."); try { // if cp1 is a leaf, just return if (srManager.deviceConfiguration().isEdgeDevice(policy.cP1().deviceId())) { @@ -1470,7 +1512,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { 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); + log.error("Abort delete of policy for tunnel {}: next does not exist in the store", tunnelId); if (future != null) { future.complete(null); } @@ -1492,7 +1534,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { @Override public void onError(Objective objective, ObjectiveError error) { - log.warn("Failed to remove previous fwdObj for policy {}: {}", tunnelId, error); + log.error("Failed to remove previous fwdObj for policy {}: {}", tunnelId, error); if (future != null) { future.complete(error); } @@ -1532,10 +1574,11 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { */ private void tearDownPseudoWireInit(long l2TunnelId, ConnectPoint ingress, CompletableFuture future, Direction direction) { - + log.debug("Starting tearing dowing initation of pseudowire {} for direction {}.", + l2TunnelId, direction == FWD ? "forward" : "reverse"); String key = generateKey(l2TunnelId, direction); if (!l2InitiationNextObjStore.containsKey(key)) { - log.info("Abort delete of {} for {}: next does not exist in the store", INITIATION, key); + log.error("Abort delete of {} for {}: next does not exist in the store", INITIATION, key); if (future != null) { future.complete(null); } @@ -1582,11 +1625,13 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { private void tearDownPseudoWireTerm(L2Tunnel l2Tunnel, ConnectPoint egress, CompletableFuture future, - Direction direction) { - + Direction direction, + PortNumber inPort) { + log.debug("Starting tearing down termination for pseudowire {} direction {}.", + l2Tunnel.tunnelId(), direction == FWD ? "forward" : "reverse"); String key = generateKey(l2Tunnel.tunnelId(), direction); if (!l2TerminationNextObjStore.containsKey(key)) { - log.info("Abort delete of {} for {}: next does not exist in the store", TERMINATION, key); + log.error("Abort delete of {} for {}: next does not exist in the store", TERMINATION, key); if (future != null) { future.complete(null); } @@ -1641,21 +1686,11 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { // spine-spine pws if (!l2Tunnel.transportVlan().equals(UNTAGGED_TRANSPORT_VLAN)) { - // determine the input port at the - PortNumber inPort; - - if (egress.deviceId(). - equals(l2Tunnel.pathUsed().get(0).dst().deviceId())) { - inPort = l2Tunnel.pathUsed().get(0).dst().port(); - } else { - inPort = l2Tunnel.pathUsed().get(0).src().port(); - } - MacAddress dstMac; try { dstMac = srManager.deviceConfiguration().getDeviceMac(egress.deviceId()); } catch (Exception e) { - log.info("Device not found in configuration, no programming of MAC address"); + log.error("Device not found in configuration, no programming of MAC address"); dstMac = null; } @@ -1668,9 +1703,11 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { createNormalPipelineFiltObjective(inPort, l2Tunnel.transportVlan(), dstMac); context = new DefaultObjectiveContext((objective) -> log.debug("Special filtObj for " + "for {} removed", - l2Tunnel.tunnelId()), (objective, error) -> - log.warn("Failed to populate " + "special filtObj " + - "rule for {}: {}", l2Tunnel.tunnelId(), error)); + 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(egress.deviceId(), filteringObjectiveBuilder.remove(context)); @@ -1693,5 +1730,4 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler { private String generateKey(long tunnelId, Direction direction) { return String.format("%s-%s", tunnelId, direction); } - } 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 1673cdef1b..ada38f4f88 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 @@ -32,6 +32,8 @@ import org.onosproject.net.intf.InterfaceService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static com.google.common.base.Preconditions.checkArgument; + /** * Utility class with static methods that help * parse pseudowire related information and also @@ -63,12 +65,7 @@ public final class PwaasUtil { } else if (vlan.equals("") || vlan.equals("None")) { return VlanId.vlanId("None"); } else { - try { - VlanId newVlan = VlanId.vlanId(vlan); - return newVlan; - } catch (IllegalArgumentException e) { - return null; - } + return VlanId.vlanId(vlan); } } @@ -78,11 +75,8 @@ public final class PwaasUtil { * @return the L2Mode if input is correct */ public static L2Mode parseMode(String mode) { - - if (!mode.equals("RAW") && !mode.equals("TAGGED")) { - return null; - } - + checkArgument(mode.equals("RAW") || mode.equals("TAGGED"), + "Invalid pseudowire mode of operation, should be TAGGED or RAW."); return L2Mode.valueOf(mode); } @@ -93,13 +87,7 @@ public final class PwaasUtil { * @throws IllegalArgumentException if label is invalid */ public static MplsLabel parsePWLabel(String label) { - - try { - MplsLabel pwLabel = MplsLabel.mplsLabel(label); - return pwLabel; - } catch (Exception e) { - return null; - } + return MplsLabel.mplsLabel(label); } /** @@ -109,14 +97,9 @@ public final class PwaasUtil { * @return The id of pw as an Integer or null if it failed the conversion. */ public static Integer parsePwId(String id) { - try { - return Integer.parseInt(id); - } catch (Exception e) { - return null; - } + return Integer.parseInt(id); } - /** * Helper method to verify if the tunnel is whether or not * supported. diff --git a/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireCodec.java b/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireCodec.java index 00d20a776e..8abfa71427 100644 --- a/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireCodec.java +++ b/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireCodec.java @@ -15,6 +15,7 @@ */ package org.onosproject.segmentrouting.web; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.apache.commons.lang3.tuple.Pair; @@ -27,9 +28,11 @@ import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel; import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription; import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy; import org.onosproject.segmentrouting.pwaas.L2Mode; +import org.onosproject.segmentrouting.pwaas.L2TunnelDescription; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; import java.util.List; import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*; @@ -69,13 +72,11 @@ public final class PseudowireCodec extends JsonCodec result.put(CP1_INNER_TAG, pseudowire.l2TunnelPolicy().cP1InnerTag().toString()); result.put(CP1_OUTER_TAG, pseudowire.l2TunnelPolicy().cP1OuterTag().toString()); - - result.put(CP2_INNER_TAG, pseudowire.l2TunnelPolicy().cP2InnerTag().toString()); result.put(CP2_OUTER_TAG, pseudowire.l2TunnelPolicy().cP2OuterTag().toString()); + result.put(SERVICE_DELIM_TAG, pseudowire.l2Tunnel().sdTag().toString()); result.put(MODE, pseudowire.l2Tunnel().pwMode() == L2Mode.RAW ? "RAW" : "TAGGED"); - result.put(SERVICE_DELIM_TAG, pseudowire.l2Tunnel().sdTag().toString()); result.put(PW_LABEL, pseudowire.l2Tunnel().pwLabel().toString()); return result; @@ -101,24 +102,76 @@ public final class PseudowireCodec extends JsonCodec } /** - * Returns a JSON containing the failed pseudowires and the reason that its one failed. + * Encoded in an Object Node the undecoed pseudowire and the specificError it failed. + * + * @param failedPW The failed pseudowire in json format + * @param specificError The specificError it failed + * @param context Our context + * @return A node containing the information we provided + */ + public ObjectNode encodeError(JsonNode failedPW, String specificError, + CodecContext context) { + ObjectNode result = context.mapper().createObjectNode(); + + result.set(FAILED_PW, failedPW); + result.put(REASON, specificError); + + return result; + } + + /** + * Returns a JSON containing the failed pseudowires and the reason that they failed. * * @param failedPws Pairs of pws and reasons. + * @param undecodedPws Pairs of pws that we could not decode with reason being illegal arguments. * @param context The context * @return ObjectNode representing the json to return */ public ObjectNode encodeFailedPseudowires( List> failedPws, + List> undecodedPws, CodecContext context) { ArrayNode failedNodes = context.mapper().createArrayNode(); failedPws.stream() .forEach(failed -> failedNodes.add(encodeError(failed.getKey(), failed.getValue(), context))); + undecodedPws.stream() + .forEach(failed -> failedNodes.add(encodeError(failed.getKey(), failed.getValue(), context))); final ObjectNode toReturn = context.mapper().createObjectNode(); toReturn.set(FAILED_PWS, failedNodes); return toReturn; } + /** + * + * @param json The json containing the pseudowires. + * @param context The context + * @return A pair of lists. + * First list contains pseudowires that we were not able to decode + * along with the reason we could not decode them. + * Second list contains successfully decoded pseudowires which we are + * going to instantiate. + */ + public Pair>, List> decodePws(ArrayNode json, + CodecContext context) { + + List decodedPws = new ArrayList<>(); + List> notDecodedPws = new ArrayList<>(); + for (JsonNode node : json) { + DefaultL2TunnelDescription l2Description; + try { + l2Description = decode((ObjectNode) node, context); + decodedPws.add(l2Description); + } catch (IllegalArgumentException e) { + // the reason why we could not decode this pseudowire is encoded in the + // exception, we need to store it now + notDecodedPws.add(Pair.of(node, e.getMessage())); + } + } + + return Pair.of(notDecodedPws, decodedPws); + } + /** * Decodes a json containg a single field with the pseudowire id. * @@ -127,8 +180,10 @@ public final class PseudowireCodec extends JsonCodec */ public static Integer decodeId(ObjectNode json) { - Integer id = parsePwId(json.path(PW_ID).asText()); - if (id == null) { + Integer id; + try { + id = parsePwId(json.path(PW_ID).asText()); + } catch (IllegalArgumentException e) { log.error("Pseudowire id is not an integer!"); return null; } @@ -139,66 +194,25 @@ public final class PseudowireCodec extends JsonCodec @Override public DefaultL2TunnelDescription decode(ObjectNode json, CodecContext context) { - String tempString; - Integer id = parsePwId(json.path(PW_ID).asText()); - if (id == null) { - log.error("Pseudowire id is not an integer"); - return null; - } ConnectPoint cP1, cP2; - try { - tempString = json.path(CP1).asText(); - cP1 = ConnectPoint.deviceConnectPoint(tempString); - } catch (Exception e) { - log.error("cP1 is not a valid connect point!"); - return null; - } + cP1 = ConnectPoint.deviceConnectPoint(json.path(CP1).asText()); + cP2 = ConnectPoint.deviceConnectPoint(json.path(CP2).asText()); - try { - tempString = json.path(CP2).asText(); - cP2 = ConnectPoint.deviceConnectPoint(tempString); - } catch (Exception e) { - log.error("cP2 is not a valid connect point!"); - return null; - } - - VlanId cP1InnerVlan = parseVlan(json.path(CP1_INNER_TAG).asText()); - VlanId cP1OuterVlan = parseVlan(json.path(CP1_OUTER_TAG).asText()); - VlanId cP2InnerVlan = parseVlan(json.path(CP2_INNER_TAG).asText()); - VlanId cP2OuterVlan = parseVlan(json.path(CP2_OUTER_TAG).asText()); - if ((cP1InnerVlan == null) || (cP1OuterVlan == null) || - (cP2InnerVlan == null) || (cP2OuterVlan == null)) { - log.error("One or more vlan for cp1 or cp2 is malformed, it shouldbe an integer / Any / None / *"); - return null; - } + VlanId cP1InnerVlan, cP1OuterVlan, cP2InnerVlan, cP2OuterVlan, sdTag; + cP1InnerVlan = parseVlan(json.path(CP1_INNER_TAG).asText()); + cP1OuterVlan = parseVlan(json.path(CP1_OUTER_TAG).asText()); + cP2InnerVlan = parseVlan(json.path(CP2_INNER_TAG).asText()); + cP2OuterVlan = parseVlan(json.path(CP2_OUTER_TAG).asText()); + sdTag = parseVlan(json.path(SERVICE_DELIM_TAG).asText()); L2Mode mode = parseMode(json.path(MODE).asText()); - if (mode == null) { - log.error("Mode should be RAW or TAGGED!"); - return null; - } - - VlanId sdTag = parseVlan(json.path(SERVICE_DELIM_TAG).asText()); - if (sdTag == null) { - log.error("SD tag is malformed, it should be an integer / Any / None / *"); - return null; - } - MplsLabel pwLabel = parsePWLabel(json.path(PW_LABEL).asText()); - if (pwLabel == null) { - log.error("PW label is malformed, should be an integer!"); - return null; - } - DefaultL2Tunnel l2Tunnel; - DefaultL2TunnelPolicy l2Policy; - - l2Tunnel = new DefaultL2Tunnel(mode, sdTag, id, pwLabel); - l2Policy = new DefaultL2TunnelPolicy(id, cP1, cP1InnerVlan, cP1OuterVlan, + DefaultL2Tunnel l2Tunnel = new DefaultL2Tunnel(mode, sdTag, id, pwLabel); + DefaultL2TunnelPolicy l2Policy = new DefaultL2TunnelPolicy(id, cP1, cP1InnerVlan, cP1OuterVlan, cP2, cP2InnerVlan, cP2OuterVlan); - return new DefaultL2TunnelDescription(l2Tunnel, l2Policy); } diff --git a/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireWebResource.java b/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireWebResource.java index 854697bb44..4867c908cd 100644 --- a/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireWebResource.java +++ b/apps/segmentrouting/web/src/main/java/org/onosproject/segmentrouting/web/PseudowireWebResource.java @@ -24,6 +24,7 @@ import org.onlab.util.ItemNotFoundException; import org.onosproject.rest.AbstractWebResource; import org.onosproject.segmentrouting.SegmentRoutingService; import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription; +import org.onosproject.segmentrouting.pwaas.L2TunnelDescription; import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy; import org.onosproject.segmentrouting.pwaas.L2Tunnel; import org.onosproject.segmentrouting.pwaas.L2TunnelHandler; @@ -111,28 +112,36 @@ public class PseudowireWebResource extends AbstractWebResource { ObjectMapper mapper = new ObjectMapper(); ObjectNode pseudowireJson = readTreeFromStream(mapper, input); SegmentRoutingService srService = get(SegmentRoutingService.class); + List> failed = new ArrayList<>(); + List> undecoded = new ArrayList<>(); - DefaultL2TunnelDescription pseudowire = PSEUDOWIRE_CODEC.decode(pseudowireJson, this); - if (pseudowire == null) { - return Response.serverError().status(Response.Status.BAD_REQUEST).build(); + DefaultL2TunnelDescription pseudowire; + try { + pseudowire = PSEUDOWIRE_CODEC.decode(pseudowireJson, this); + + // pseudowire decoded, try to instantiate it, if we fail add it to failed list + long tunId = pseudowire.l2Tunnel().tunnelId(); + log.debug("Creating pseudowire {} from rest api!", tunId); + + L2TunnelHandler.Result res = srService.addPseudowire(pseudowire); + if (res != L2TunnelHandler.Result.SUCCESS) { + log.error("Could not create pseudowire {} : {}", pseudowire.l2Tunnel().tunnelId(), + res.getSpecificError()); + failed.add(Pair.of(pseudowire, res.getSpecificError())); + } + } catch (IllegalArgumentException e) { + log.debug("Pseudowire could not be decoded : {}", e.getMessage()); + undecoded.add(Pair.of(pseudowireJson, e.getMessage())); } - long tunId = pseudowire.l2Tunnel().tunnelId(); - log.debug("Creating pseudowire {} from rest api!", tunId); - - L2TunnelHandler.Result res = srService.addPseudowire(pseudowire); - switch (res) { - case WRONG_PARAMETERS: - case CONFIGURATION_ERROR: - case PATH_NOT_FOUND: - case INTERNAL_ERROR: - log.error("Pseudowire {} could not be added : {}", tunId, res.getSpecificError()); - return Response.serverError().status(Response.Status.INTERNAL_SERVER_ERROR).build(); - case SUCCESS: - log.info("Pseudowire {} succesfully deployed!", pseudowire.l2Tunnel().tunnelId()); - return Response.ok().build(); - default: - return Response.ok().build(); + if ((failed.size() == 0) && (undecoded.size() == 0)) { + // pseudowire instantiated correctly + return Response.ok().build(); + } else { + // failed to decode or instantiate pseudowire, return the reason + PseudowireCodec pwCodec = new PseudowireCodec(); + ObjectNode result = pwCodec.encodeFailedPseudowires(failed, undecoded, this); + return Response.serverError().entity(result).build(); } } @@ -152,33 +161,36 @@ public class PseudowireWebResource extends AbstractWebResource { ObjectMapper mapper = new ObjectMapper(); ObjectNode pseudowireJson = readTreeFromStream(mapper, input); SegmentRoutingService srService = get(SegmentRoutingService.class); - List pseudowires; + Pair>, List> pseudowires; try { ArrayNode pseudowiresArray = nullIsIllegal((ArrayNode) pseudowireJson.get(PWS), PWS_KEY_ERROR); - pseudowires = PSEUDOWIRE_CODEC.decode(pseudowiresArray, this); + // get two lists, first one contains pseudowires that we were unable to decode + // that have faulty arguments, second one contains pseudowires that we decoded + // succesfully + pseudowires = PSEUDOWIRE_CODEC.decodePws(pseudowiresArray, this); } catch (ItemNotFoundException e) { return Response.serverError().status(Response.Status.BAD_REQUEST).build(); } log.debug("Creating pseudowires {} from rest api!", pseudowires); List> failed = new ArrayList<>(); - - for (DefaultL2TunnelDescription pw : pseudowires) { + for (L2TunnelDescription pw : pseudowires.getRight()) { L2TunnelHandler.Result res = srService.addPseudowire(pw); - if (!(res == L2TunnelHandler.Result.SUCCESS)) { - log.trace("Could not create pseudowire {} : {}", pw.l2Tunnel().tunnelId(), res.getSpecificError()); - failed.add(Pair.of(pw, res.getSpecificError())); + if (res != L2TunnelHandler.Result.SUCCESS) { + log.error("Could not create pseudowire {} : {}", pw.l2Tunnel().tunnelId(), res.getSpecificError()); + failed.add(Pair.of((DefaultL2TunnelDescription) pw, res.getSpecificError())); } } + List> undecodedPws = pseudowires.getLeft(); - if (failed.size() == 0) { - // all pseudowires were instantiated + if ((failed.size() == 0) && (undecodedPws.size() == 0)) { + // all pseudowires were decoded and instantiated succesfully return Response.ok().build(); } else { PseudowireCodec pwCodec = new PseudowireCodec(); // some failed, need to report them to user - ObjectNode result = pwCodec.encodeFailedPseudowires(failed, this); + ObjectNode result = pwCodec.encodeFailedPseudowires(failed, undecodedPws, this); return Response.serverError().entity(result).build(); } }