mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-04 19:56:49 +02:00
Various pseudowire fixes and improvements.
- Co-ordination when creating - removing pseudowires from different instances with a use of a DistributedLock. - Fixed REST API To return json with specific error for the single pw instantiation. - Fixed REST API to return specific error also for pseudowires that could not be decoded. - Minor bug fix to return appropriate error when instantiating a pw from the command line that could not be decoded. - Fixed bug when creating spine-leaf-leaf pseudowire where we observed flows in pending state. - Improved logging. Change-Id: I60dd0ebf8af63ca74d18cfe4801d01846641fb7b
This commit is contained in:
parent
0fe0cdb66d
commit
5bf1366410
@ -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",
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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<VlanId> 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<Link> path, boolean leafSpinePw) {
|
||||
|
||||
log.debug("Checking path validity for pseudowire.");
|
||||
List<DeviceId> 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<Link> 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<Link> 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<ObjectiveError> 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<Objective> 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<ObjectiveError> 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<ObjectiveError> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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<DefaultL2TunnelDescription>
|
||||
|
||||
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<DefaultL2TunnelDescription>
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<Pair<DefaultL2TunnelDescription, String>> failedPws,
|
||||
List<Pair<JsonNode, String>> 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<Pair<JsonNode, String>>, List<L2TunnelDescription>> decodePws(ArrayNode json,
|
||||
CodecContext context) {
|
||||
|
||||
List<L2TunnelDescription> decodedPws = new ArrayList<>();
|
||||
List<Pair<JsonNode, String>> 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<DefaultL2TunnelDescription>
|
||||
*/
|
||||
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<DefaultL2TunnelDescription>
|
||||
@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);
|
||||
|
||||
}
|
||||
|
||||
@ -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<Pair<DefaultL2TunnelDescription, String>> failed = new ArrayList<>();
|
||||
List<Pair<JsonNode, String>> 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<DefaultL2TunnelDescription> pseudowires;
|
||||
Pair<List<Pair<JsonNode, String>>, List<L2TunnelDescription>> 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<Pair<DefaultL2TunnelDescription, String>> 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<Pair<JsonNode, String>> 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();
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user