mirror of
https://github.com/opennetworkinglab/onos.git
synced 2026-05-05 04:06:49 +02:00
REST API for pseudowire addition / deletion.
Refactored pseudowire code to use REST in order to add or delete pseudowires individually. Previous implementation used the network configuration, which is now completely removed from the code. Further, I re-organized the code and create a utility class that holds all the necessary functionality for verifying pseudowires. Further, I removed all mastership checks in the pw code since now a specific pseudowire creation is sent to a single instance, which will handle the call. Change-Id: I1eb5e7cc7730ad792ea84dd389475768153e2b68
This commit is contained in:
parent
a9ae6e662c
commit
cd3395992d
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.onosproject.segmentrouting;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
@ -94,7 +92,6 @@ import org.onosproject.routeservice.RouteListener;
|
||||
import org.onosproject.routeservice.RouteService;
|
||||
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
|
||||
import org.onosproject.segmentrouting.config.DeviceConfiguration;
|
||||
import org.onosproject.segmentrouting.config.PwaasConfig;
|
||||
import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
|
||||
import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
|
||||
import org.onosproject.segmentrouting.config.XConnectConfig;
|
||||
@ -104,9 +101,13 @@ import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelHandler;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
|
||||
|
||||
import org.onosproject.segmentrouting.pwaas.L2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
|
||||
|
||||
import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.McastStoreKey;
|
||||
import org.onosproject.segmentrouting.storekey.PortNextObjectiveStoreKey;
|
||||
@ -142,6 +143,7 @@ import static org.onlab.packet.Ethernet.TYPE_ARP;
|
||||
import static org.onlab.util.Tools.groupedThreads;
|
||||
import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REGISTERED;
|
||||
import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UNREGISTERED;
|
||||
import static org.onosproject.segmentrouting.pwaas.PwaasUtil.configurationValidity;
|
||||
|
||||
/**
|
||||
* Segment routing manager.
|
||||
@ -234,7 +236,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
private RouteHandler routeHandler = null;
|
||||
LinkHandler linkHandler = null;
|
||||
private SegmentRoutingNeighbourDispatcher neighbourHandler = null;
|
||||
private L2TunnelHandler l2TunnelHandler = null;
|
||||
private DefaultL2TunnelHandler l2TunnelHandler = null;
|
||||
private InternalEventHandler eventHandler = new InternalEventHandler();
|
||||
private final InternalHostListener hostListener = new InternalHostListener();
|
||||
private final InternalConfigListener cfgListener = new InternalConfigListener(this);
|
||||
@ -314,16 +316,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
}
|
||||
};
|
||||
|
||||
private final ConfigFactory<ApplicationId, PwaasConfig> pwaasConfigFactory =
|
||||
new ConfigFactory<ApplicationId, PwaasConfig>(
|
||||
SubjectFactories.APP_SUBJECT_FACTORY,
|
||||
PwaasConfig.class, "pwaas") {
|
||||
@Override
|
||||
public PwaasConfig createConfig() {
|
||||
return new PwaasConfig();
|
||||
}
|
||||
};
|
||||
|
||||
private static final Object THREAD_SCHED_LOCK = new Object();
|
||||
private static int numOfEventsQueued = 0;
|
||||
private static int numOfEventsExecuted = 0;
|
||||
@ -430,7 +422,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
cfgService.registerConfigFactory(appConfigFactory);
|
||||
cfgService.registerConfigFactory(xConnectConfigFactory);
|
||||
cfgService.registerConfigFactory(mcastConfigFactory);
|
||||
cfgService.registerConfigFactory(pwaasConfigFactory);
|
||||
log.info("Configuring network before adding listeners");
|
||||
cfgListener.configureNetwork();
|
||||
|
||||
@ -474,7 +465,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
cfgService.unregisterConfigFactory(appConfigFactory);
|
||||
cfgService.unregisterConfigFactory(xConnectConfigFactory);
|
||||
cfgService.unregisterConfigFactory(mcastConfigFactory);
|
||||
cfgService.unregisterConfigFactory(pwaasConfigFactory);
|
||||
compCfgService.unregisterProperties(getClass(), false);
|
||||
|
||||
hostService.removeListener(hostListener);
|
||||
@ -567,55 +557,90 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2TunnelHandler.Result addPseudowire(String tunnelId, String pwLabel, String cP1,
|
||||
String cP1InnerVlan, String cP1OuterVlan, String cP2,
|
||||
String cP2InnerVlan, String cP2OuterVlan,
|
||||
String mode, String sdTag) {
|
||||
// Try to inject an empty Pwaas config if it is not found for the first time
|
||||
PwaasConfig config = cfgService.getConfig(appId(), PwaasConfig.class);
|
||||
if (config == null) {
|
||||
log.debug("Pwaas config not found. Try to create an empty one.");
|
||||
cfgService.applyConfig(appId(), PwaasConfig.class, new ObjectMapper().createObjectNode());
|
||||
config = cfgService.getConfig(appId(), PwaasConfig.class);
|
||||
public L2TunnelHandler.Result addPseudowire(L2TunnelDescription l2TunnelDescription) {
|
||||
|
||||
List<L2Tunnel> tunnels = getL2Tunnels();
|
||||
List<L2TunnelPolicy> policies = getL2Policies();
|
||||
|
||||
// combine polices and tunnels to pseudowires
|
||||
List<L2TunnelDescription> pseudowires = tunnels.stream()
|
||||
.map(l2Tunnel -> {
|
||||
L2TunnelPolicy policy = null;
|
||||
for (L2TunnelPolicy l2Policy : policies) {
|
||||
if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
|
||||
policy = l2Policy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new DefaultL2TunnelDescription(l2Tunnel, policy);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
||||
// creating a new list with the new pseudowire
|
||||
Set<L2TunnelDescription> newPseudowires = new HashSet<>(pseudowires);
|
||||
|
||||
// corner case where we try to add the exact same pseudowire
|
||||
if (newPseudowires.contains(l2TunnelDescription)) {
|
||||
log.info("Pseudowire with {} already exists!", l2TunnelDescription);
|
||||
return L2TunnelHandler.Result.SUCCESS;
|
||||
}
|
||||
|
||||
ObjectNode object = config.addPseudowire(tunnelId, pwLabel,
|
||||
cP1, cP1InnerVlan, cP1OuterVlan,
|
||||
cP2, cP2InnerVlan, cP2OuterVlan,
|
||||
mode, sdTag);
|
||||
if (object == null) {
|
||||
log.warn("Could not add pseudowire to the configuration!");
|
||||
// add the new pseudowire to the Set
|
||||
newPseudowires.add(l2TunnelDescription);
|
||||
|
||||
// validate the new set of pseudowires
|
||||
boolean res = configurationValidity(newPseudowires);
|
||||
if (res) {
|
||||
|
||||
// deploy a set with ONLY the new pseudowire
|
||||
newPseudowires = new HashSet<>();
|
||||
newPseudowires.add(l2TunnelDescription);
|
||||
l2TunnelHandler.deploy(newPseudowires);
|
||||
|
||||
log.info("Pseudowire with {} deployment started, check log for any errors in this process!",
|
||||
l2TunnelDescription.l2Tunnel().tunnelId());
|
||||
return L2TunnelHandler.Result.SUCCESS;
|
||||
} else {
|
||||
|
||||
log.error("Pseudowire with {} can not be added!", l2TunnelDescription.l2Tunnel().tunnelId());
|
||||
return L2TunnelHandler.Result.ADDITION_ERROR;
|
||||
}
|
||||
|
||||
// inform everyone about the valid change in the pw configuration
|
||||
cfgService.applyConfig(appId(), PwaasConfig.class, object);
|
||||
return L2TunnelHandler.Result.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public L2TunnelHandler.Result removePseudowire(String pwId) {
|
||||
public L2TunnelHandler.Result removePseudowire(Integer pwId) {
|
||||
|
||||
PwaasConfig config = cfgService.getConfig(appId(), PwaasConfig.class);
|
||||
if (config == null) {
|
||||
log.warn("Configuration for Pwaas class could not be found!");
|
||||
return L2TunnelHandler.Result.CONFIG_NOT_FOUND;
|
||||
}
|
||||
List<L2Tunnel> tunnels = getL2Tunnels();
|
||||
List<L2TunnelPolicy> policies = getL2Policies();
|
||||
|
||||
ObjectNode object = config.removePseudowire(pwId);
|
||||
if (object == null) {
|
||||
log.warn("Could not delete pseudowire from configuration!");
|
||||
// get the pseudowire, if it exists
|
||||
List<L2TunnelDescription> pseudowires = tunnels.stream().map(l2Tunnel -> {
|
||||
L2TunnelPolicy policy = null;
|
||||
for (L2TunnelPolicy l2Policy : policies) {
|
||||
if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
|
||||
policy = l2Policy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return new DefaultL2TunnelDescription(l2Tunnel, policy);
|
||||
}).filter(l2desc ->
|
||||
l2desc.l2Tunnel().tunnelId() == pwId
|
||||
).collect(Collectors.toList());
|
||||
|
||||
if (pseudowires.size() == 0) {
|
||||
log.error("Pseudowire with id {} does not exist", pwId);
|
||||
return L2TunnelHandler.Result.REMOVAL_ERROR;
|
||||
} else {
|
||||
|
||||
l2TunnelHandler.tearDown(new HashSet<>(pseudowires));
|
||||
|
||||
log.info("Removal of pseudowire with {} started, check log for any errors in this process!",
|
||||
pwId);
|
||||
return L2TunnelHandler.Result.SUCCESS;
|
||||
}
|
||||
|
||||
// sanity check, this should never fail since we removed a pw
|
||||
// and we always check when we update the configuration
|
||||
config.isValid();
|
||||
|
||||
// inform everyone
|
||||
cfgService.applyConfig(appId(), PwaasConfig.class, object);
|
||||
|
||||
return L2TunnelHandler.Result.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1411,21 +1436,6 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (event.configClass().equals(PwaasConfig.class)) {
|
||||
checkState(l2TunnelHandler != null, "DefaultL2TunnelHandler is not initialized");
|
||||
switch (event.type()) {
|
||||
case CONFIG_ADDED:
|
||||
l2TunnelHandler.processPwaasConfigAdded(event);
|
||||
break;
|
||||
case CONFIG_UPDATED:
|
||||
l2TunnelHandler.processPwaasConfigUpdated(event);
|
||||
break;
|
||||
case CONFIG_REMOVED:
|
||||
l2TunnelHandler.processPwaasConfigRemoved(event);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1440,8 +1450,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
|
||||
if (!event.configClass().equals(SegmentRoutingDeviceConfig.class) &&
|
||||
!event.configClass().equals(SegmentRoutingAppConfig.class) &&
|
||||
!event.configClass().equals(InterfaceConfig.class) &&
|
||||
!event.configClass().equals(XConnectConfig.class) &&
|
||||
!event.configClass().equals(PwaasConfig.class)) {
|
||||
!event.configClass().equals(XConnectConfig.class)) {
|
||||
log.debug("Ignore event {} due to class mismatch", event);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -25,6 +25,7 @@ import org.onosproject.segmentrouting.grouphandler.NextNeighbors;
|
||||
import org.onosproject.segmentrouting.pwaas.L2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
|
||||
import org.onosproject.segmentrouting.storekey.DestinationSetNextObjectiveStoreKey;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@ -101,33 +102,20 @@ public interface SegmentRoutingService {
|
||||
List<L2TunnelPolicy> getL2Policies();
|
||||
|
||||
/**
|
||||
* Removes pw. Essentially updates configuration for PwaasConfig
|
||||
* and sends event for removal. The rest are handled by DefaultL2TunnelHandler
|
||||
* Removes pseudowire. Used ONLY by the REST api.
|
||||
*
|
||||
* @param pwId The pseudowire id
|
||||
* @param pwId The id of the pseudowire.
|
||||
* @return SUCCESS if operation successful or a descriptive error otherwise.
|
||||
*/
|
||||
L2TunnelHandler.Result removePseudowire(String pwId);
|
||||
L2TunnelHandler.Result removePseudowire(Integer pwId);
|
||||
|
||||
/**
|
||||
* Adds a Pseudowire to the configuration.
|
||||
*
|
||||
* @param tunnelId The pseudowire id
|
||||
* @param pwLabel Pw label
|
||||
* @param cP1 Connection Point 1 of pw
|
||||
* @param cP1InnerVlan Outer vlan of cp2
|
||||
* @param cP1OuterVlan Outer vlan of cp1
|
||||
* @param cP2 Connection Point 2 of pw
|
||||
* @param cP2InnerVlan Inner vlan of cp2
|
||||
* @param cP2OuterVlan Outer vlan of cp1
|
||||
* @param mode Mode of pw
|
||||
* @param sdTag Service Delimiting tag of pw
|
||||
* @param tunnel The pseudowire tunnel.
|
||||
* @return SUCCESS if operation is successful or a descriptive error otherwise.
|
||||
*/
|
||||
L2TunnelHandler.Result addPseudowire(String tunnelId, String pwLabel, String cP1,
|
||||
String cP1InnerVlan, String cP1OuterVlan, String cP2,
|
||||
String cP2InnerVlan, String cP2OuterVlan,
|
||||
String mode, String sdTag);
|
||||
L2TunnelHandler.Result addPseudowire(L2TunnelDescription tunnel);
|
||||
|
||||
/**
|
||||
* Creates a policy.
|
||||
|
||||
@ -19,8 +19,17 @@ package org.onosproject.segmentrouting.cli;
|
||||
import org.apache.karaf.shell.commands.Argument;
|
||||
import org.apache.karaf.shell.commands.Command;
|
||||
import org.onosproject.cli.AbstractShellCommand;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.segmentrouting.SegmentRoutingService;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
|
||||
import org.onosproject.segmentrouting.pwaas.L2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
|
||||
|
||||
import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*;
|
||||
|
||||
|
||||
/**
|
||||
@ -86,16 +95,36 @@ public class PseudowireAddCommand extends AbstractShellCommand {
|
||||
SegmentRoutingService srService =
|
||||
AbstractShellCommand.get(SegmentRoutingService.class);
|
||||
|
||||
L2TunnelHandler.Result res = srService.addPseudowire(pwId, pwLabel,
|
||||
cP1, cP1InnerVlan, cP1OuterVlan,
|
||||
cP2, cP2InnerVlan, cP2OuterVlan,
|
||||
mode, sDTag);
|
||||
L2Tunnel tun;
|
||||
L2TunnelPolicy policy;
|
||||
|
||||
try {
|
||||
tun = new DefaultL2Tunnel(parseMode(mode), parseVlan(sDTag), parsePwId(pwId), parsePWLabel(pwLabel));
|
||||
} catch (Exception e) {
|
||||
print("Exception while parsing L2Tunnel : {}", e);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
policy = new DefaultL2TunnelPolicy(parsePwId(pwId),
|
||||
ConnectPoint.deviceConnectPoint(cP1), parseVlan(cP1InnerVlan),
|
||||
parseVlan(cP1OuterVlan), ConnectPoint.deviceConnectPoint(cP2),
|
||||
parseVlan(cP2InnerVlan), parseVlan(cP2OuterVlan));
|
||||
|
||||
} catch (Exception e) {
|
||||
print("Exception while parsing L2TunnelPolicy : {}", e);
|
||||
return;
|
||||
}
|
||||
|
||||
L2TunnelDescription pw = new DefaultL2TunnelDescription(tun, policy);
|
||||
L2TunnelHandler.Result res = srService.addPseudowire(pw);
|
||||
|
||||
switch (res) {
|
||||
case ADDITION_ERROR:
|
||||
print("Pseudowire could not be added, error in configuration, please check logs for more details!");
|
||||
print("Pseudowire could not be added, please check logs for more details!");
|
||||
break;
|
||||
case CONFIG_NOT_FOUND:
|
||||
print("Configuration for pwaas was not found! Initialize the configuration first through netcfg.");
|
||||
case SUCCESS:
|
||||
print("Pseudowire was added succesfully!");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
@ -23,6 +23,8 @@ import org.onosproject.segmentrouting.SegmentRoutingManager;
|
||||
import org.onosproject.segmentrouting.SegmentRoutingService;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
|
||||
|
||||
import static org.onosproject.segmentrouting.pwaas.PwaasUtil.parsePwId;
|
||||
|
||||
|
||||
/**
|
||||
* Command to remove a pseudowire.
|
||||
@ -44,8 +46,15 @@ public class PseudowireRemoveCommand extends AbstractShellCommand {
|
||||
|
||||
// remove the pseudowire
|
||||
SegmentRoutingManager mngr = (SegmentRoutingManager) srService;
|
||||
L2TunnelHandler.Result res = mngr.removePseudowire(pwId);
|
||||
int pwIntId;
|
||||
try {
|
||||
pwIntId = parsePwId(pwId);
|
||||
} catch (Exception e) {
|
||||
print("Exception while parsing pseudowire id : {}", e);
|
||||
return;
|
||||
}
|
||||
|
||||
L2TunnelHandler.Result res = mngr.removePseudowire(pwIntId);
|
||||
switch (res) {
|
||||
case REMOVAL_ERROR:
|
||||
error("Error in deletion, pseudowire not found!");
|
||||
|
||||
@ -30,7 +30,6 @@ import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.Path;
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.config.NetworkConfigEvent;
|
||||
import org.onosproject.net.flow.DefaultTrafficSelector;
|
||||
import org.onosproject.net.flow.DefaultTrafficTreatment;
|
||||
import org.onosproject.net.flow.TrafficSelector;
|
||||
@ -49,7 +48,6 @@ import org.onosproject.net.flowobjective.ObjectiveError;
|
||||
import org.onosproject.segmentrouting.SegmentRoutingManager;
|
||||
import org.onosproject.segmentrouting.SegmentRoutingService;
|
||||
import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
|
||||
import org.onosproject.segmentrouting.config.PwaasConfig;
|
||||
import org.onosproject.store.serializers.KryoNamespaces;
|
||||
import org.onosproject.store.service.ConsistentMap;
|
||||
import org.onosproject.store.service.DistributedSet;
|
||||
@ -64,7 +62,6 @@ import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static org.onosproject.net.flowobjective.ForwardingObjective.Flag.VERSATILE;
|
||||
import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.INITIATION;
|
||||
import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.TERMINATION;
|
||||
@ -168,28 +165,14 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Deploys any pre-existing pseudowires in the configuration.
|
||||
* Used by manager only in initialization.
|
||||
*/
|
||||
@Override
|
||||
public void init() {
|
||||
|
||||
PwaasConfig config = srManager.cfgService.getConfig(srManager.appId(), PwaasConfig.class);
|
||||
if (config == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("Deploying existing pseudowires");
|
||||
|
||||
// gather pseudowires
|
||||
Set<L2TunnelDescription> pwToAdd = config
|
||||
.getPwIds()
|
||||
.stream()
|
||||
.map(config::getPwDescription)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// deploy pseudowires
|
||||
deploy(pwToAdd);
|
||||
// Since we have no pseudowires in netcfg there
|
||||
// is nothing to do in initialization.
|
||||
// I leave it here because potentially we might need to
|
||||
// use it in the future.
|
||||
}
|
||||
|
||||
/**
|
||||
@ -254,25 +237,6 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
pwToUpdate.forEach(tun -> updatePw(tun, tun));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processPwaasConfigAdded(NetworkConfigEvent event) {
|
||||
checkArgument(event.config().isPresent(),
|
||||
"Config is not presented in PwaasConfigAdded event {}", event);
|
||||
|
||||
log.info("Network event : Pseudowire configuration added!");
|
||||
PwaasConfig config = (PwaasConfig) event.config().get();
|
||||
|
||||
// gather pseudowires
|
||||
Set<L2TunnelDescription> pwToAdd = config
|
||||
.getPwIds()
|
||||
.stream()
|
||||
.map(config::getPwDescription)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// deploy pseudowires
|
||||
deploy(pwToAdd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new vlan id for an ingress point of a
|
||||
* pseudowire. For double tagged, it is the outer,
|
||||
@ -334,10 +298,7 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a single pseudowire from leaf to a leaf.
|
||||
* This method can be called from cli commands
|
||||
* without configuration updates, thus it does not check for mastership
|
||||
* of the ingress pseudowire device.
|
||||
* Adds a single pseudowire.
|
||||
*
|
||||
* @param pw The pseudowire
|
||||
* @param spinePw True if pseudowire is from leaf to spine
|
||||
@ -490,15 +451,10 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
|
||||
/**
|
||||
* To deploy a number of pseudo wires.
|
||||
* <p>
|
||||
* Called ONLY when configuration changes, thus the check
|
||||
* for the mastership of the device.
|
||||
* <p>
|
||||
* Only the master of CP1 will deploy this pseudowire.
|
||||
*
|
||||
* @param pwToAdd the set of pseudo wires to add
|
||||
*/
|
||||
private void deploy(Set<L2TunnelDescription> pwToAdd) {
|
||||
public void deploy(Set<L2TunnelDescription> pwToAdd) {
|
||||
|
||||
Result result;
|
||||
|
||||
@ -507,11 +463,6 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
ConnectPoint cp2 = currentL2Tunnel.l2TunnelPolicy().cP2();
|
||||
long tunnelId = currentL2Tunnel.l2TunnelPolicy().tunnelId();
|
||||
|
||||
// only the master of CP1 will program this pseudowire
|
||||
if (!srManager.isMasterOf(cp1)) {
|
||||
log.debug("Not the master of {}. Ignore pseudo wire deployment id={}", cp1, tunnelId);
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
// differentiate between leaf-leaf pseudowires and leaf-spine
|
||||
@ -550,57 +501,6 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void processPwaasConfigUpdated(NetworkConfigEvent event) {
|
||||
checkArgument(event.config().isPresent(),
|
||||
"Config is not presented in PwaasConfigUpdated event {}", event);
|
||||
checkArgument(event.prevConfig().isPresent(),
|
||||
"PrevConfig is not presented in PwaasConfigUpdated event {}", event);
|
||||
|
||||
log.info("Pseudowire configuration updated.");
|
||||
|
||||
// We retrieve the old pseudo wires.
|
||||
PwaasConfig prevConfig = (PwaasConfig) event.prevConfig().get();
|
||||
Set<Long> prevPws = prevConfig.getPwIds();
|
||||
|
||||
// We retrieve the new pseudo wires.
|
||||
PwaasConfig config = (PwaasConfig) event.config().get();
|
||||
Set<Long> newPws = config.getPwIds();
|
||||
|
||||
// We compute the pseudo wires to update.
|
||||
Set<Long> updPws = newPws.stream()
|
||||
.filter(tunnelId -> prevPws.contains(tunnelId)
|
||||
&& !config.getPwDescription(tunnelId).equals(prevConfig.getPwDescription(tunnelId)))
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// The pseudo wires to remove.
|
||||
Set<Long> rmvPWs = prevPws.stream()
|
||||
.filter(tunnelId -> !newPws.contains(tunnelId)).collect(Collectors.toSet());
|
||||
|
||||
Set<L2TunnelDescription> pwToRemove = rmvPWs.stream()
|
||||
.map(prevConfig::getPwDescription)
|
||||
.collect(Collectors.toSet());
|
||||
tearDown(pwToRemove);
|
||||
|
||||
// The pseudo wires to add.
|
||||
Set<Long> addedPWs = newPws.stream()
|
||||
.filter(tunnelId -> !prevPws.contains(tunnelId))
|
||||
.collect(Collectors.toSet());
|
||||
Set<L2TunnelDescription> pwToAdd = addedPWs.stream()
|
||||
.map(config::getPwDescription)
|
||||
.collect(Collectors.toSet());
|
||||
deploy(pwToAdd);
|
||||
|
||||
|
||||
// The pseudo wires to update.
|
||||
updPws.forEach(tunnelId -> updatePw(prevConfig.getPwDescription(tunnelId),
|
||||
config.getPwDescription(tunnelId)));
|
||||
|
||||
log.info("Pseudowires removed : {}, Pseudowires updated : {}, Pseudowires added : {}", rmvPWs,
|
||||
updPws, addedPWs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to update a pw.
|
||||
* <p>
|
||||
@ -621,11 +521,6 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
ConnectPoint oldCp1 = oldPw.l2TunnelPolicy().cP1();
|
||||
long tunnelId = oldPw.l2Tunnel().tunnelId();
|
||||
|
||||
// only the master of CP1 will update this pseudowire
|
||||
if (!srManager.isMasterOf(oldPw.l2TunnelPolicy().cP1())) {
|
||||
log.debug("Not the master of {}. Ignore pseudo wire update id={}", oldCp1, tunnelId);
|
||||
return;
|
||||
}
|
||||
// only determine if the new pseudowire is leaf-spine, because
|
||||
// removal process is the same for both leaf-leaf and leaf-spine pws
|
||||
boolean newPwSpine;
|
||||
@ -815,24 +710,6 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processPwaasConfigRemoved(NetworkConfigEvent event) {
|
||||
checkArgument(event.prevConfig().isPresent(),
|
||||
"PrevConfig is not presented in PwaasConfigRemoved event {}", event);
|
||||
|
||||
log.info("Network event : Pseudowire configuration removed!");
|
||||
PwaasConfig config = (PwaasConfig) event.prevConfig().get();
|
||||
|
||||
Set<L2TunnelDescription> pwToRemove = config
|
||||
.getPwIds()
|
||||
.stream()
|
||||
.map(config::getPwDescription)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// We teardown all the pseudo wire deployed
|
||||
tearDown(pwToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for removing a single pseudowire.
|
||||
* <p>
|
||||
@ -957,12 +834,6 @@ public class DefaultL2TunnelHandler implements L2TunnelHandler {
|
||||
ConnectPoint cp2 = currentL2Tunnel.l2TunnelPolicy().cP2();
|
||||
long tunnelId = currentL2Tunnel.l2TunnelPolicy().tunnelId();
|
||||
|
||||
// only the master of CP1 will program this pseudowire
|
||||
if (!srManager.isMasterOf(cp1)) {
|
||||
log.debug("Not the master of {}. Ignore pseudo wire removal id={}", cp1, tunnelId);
|
||||
continue;
|
||||
}
|
||||
|
||||
// no need to differentiate here between leaf-leaf and leaf-spine, because
|
||||
// the only change is in the groups, which we do not remove either way
|
||||
log.info("Removing pseudowire {}", tunnelId);
|
||||
|
||||
@ -17,7 +17,6 @@
|
||||
package org.onosproject.segmentrouting.pwaas;
|
||||
|
||||
import org.onosproject.net.Link;
|
||||
import org.onosproject.net.config.NetworkConfigEvent;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -47,27 +46,6 @@ public interface L2TunnelHandler {
|
||||
*/
|
||||
void processLinkDown(Link link);
|
||||
|
||||
/**
|
||||
* Processes Pwaas Config added event.
|
||||
*
|
||||
* @param event network config add event
|
||||
*/
|
||||
void processPwaasConfigAdded(NetworkConfigEvent event);
|
||||
|
||||
/**
|
||||
* Processes PWaaS Config updated event.
|
||||
*
|
||||
* @param event network config updated event
|
||||
*/
|
||||
void processPwaasConfigUpdated(NetworkConfigEvent event);
|
||||
|
||||
/**
|
||||
* Processes Pwaas Config removed event.
|
||||
*
|
||||
* @param event network config removed event
|
||||
*/
|
||||
void processPwaasConfigRemoved(NetworkConfigEvent event);
|
||||
|
||||
/**
|
||||
* Helper function to handle the pw removal.
|
||||
* <p>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-present Open Networking Foundation
|
||||
* Copyright 2015-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -14,145 +14,130 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.onosproject.segmentrouting.config;
|
||||
package org.onosproject.segmentrouting.pwaas;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.apache.felix.scr.annotations.Reference;
|
||||
import org.apache.felix.scr.annotations.ReferenceCardinality;
|
||||
import org.onlab.packet.MplsLabel;
|
||||
import org.onlab.packet.VlanId;
|
||||
import org.onosproject.cli.AbstractShellCommand;
|
||||
import org.onosproject.core.ApplicationId;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.config.Config;
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.intf.InterfaceService;
|
||||
import org.onosproject.segmentrouting.pwaas.L2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.intf.InterfaceService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* App configuration object for Pwaas.
|
||||
* Utility class with static methods that help
|
||||
* parse pseudowire related information and also
|
||||
* verify that a pseudowire combination is valid.
|
||||
*/
|
||||
public class PwaasConfig extends Config<ApplicationId> {
|
||||
public final class PwaasUtil {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PwaasUtil.class);
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
public DeviceService deviceService;
|
||||
public static DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);;
|
||||
|
||||
@Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
|
||||
public InterfaceService intfService;
|
||||
public static InterfaceService intfService = AbstractShellCommand.get(InterfaceService.class);
|
||||
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(PwaasConfig.class);
|
||||
|
||||
private static final String SRC_CP = "cP1";
|
||||
private static final String DST_CP = "cP2";
|
||||
private static final String SRC_OUTER_TAG = "cP1OuterTag";
|
||||
private static final String DST_OUTER_TAG = "cP2OuterTag";
|
||||
private static final String SRC_INNER_TAG = "cP1InnerTag";
|
||||
private static final String DST_INNER_TAG = "cP2InnerTag";
|
||||
private static final String MODE = "mode";
|
||||
private static final String SD_TAG = "sdTag";
|
||||
private static final String PW_LABEL = "pwLabel";
|
||||
|
||||
public PwaasConfig(DeviceService devS, InterfaceService intfS) {
|
||||
|
||||
super();
|
||||
|
||||
deviceService = devS;
|
||||
intfService = intfS;
|
||||
private PwaasUtil() {
|
||||
return;
|
||||
}
|
||||
|
||||
public PwaasConfig() {
|
||||
|
||||
super();
|
||||
|
||||
deviceService = AbstractShellCommand.get(DeviceService.class);
|
||||
intfService = AbstractShellCommand.get(InterfaceService.class);
|
||||
}
|
||||
/**
|
||||
* Error message for missing parameters.
|
||||
*/
|
||||
private static final String MISSING_PARAMS = "Missing parameters in pseudo wire description";
|
||||
|
||||
/**
|
||||
* Error message for invalid l2 mode.
|
||||
*/
|
||||
private static final String INVALID_L2_MODE = "Invalid pseudo wire mode";
|
||||
|
||||
/**
|
||||
* Error message for invalid VLAN.
|
||||
*/
|
||||
private static final String INVALID_VLAN = "Vlan should be either int or */-";
|
||||
|
||||
/**
|
||||
* Error message for invalid PW label.
|
||||
*/
|
||||
private static final String INVALID_PW_LABEL = "Pseudowire label should be an integer";
|
||||
|
||||
/**
|
||||
* Verify if the pwaas configuration block is valid.
|
||||
* Parses a vlan as a string. Returns the VlanId if
|
||||
* provided String can be parsed as an integer or is '' / '*'
|
||||
*
|
||||
* Here we try to ensure that the provided pseudowires will get instantiated
|
||||
* correctly in the network. We also check for any collisions with already used
|
||||
* interfaces and also between different pseudowires. Most of the restrictions stem
|
||||
* from the fact that all vlan matching is done in table 10 of ofdpa.
|
||||
*
|
||||
* @return true, if the configuration block is valid.
|
||||
* False otherwise.
|
||||
* @param vlan string as read from configuration
|
||||
* @return VlanId null if error
|
||||
*/
|
||||
@Override
|
||||
public boolean isValid() {
|
||||
public static VlanId parseVlan(String vlan) {
|
||||
|
||||
Set<L2TunnelDescription> pseudowires;
|
||||
try {
|
||||
pseudowires = getPwIds().stream()
|
||||
.map(this::getPwDescription)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// check semantics now and return
|
||||
return configurationValidity(pseudowires);
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.warn("{}", e.getMessage());
|
||||
return false;
|
||||
if (vlan.equals("*") || vlan.equals("Any")) {
|
||||
return VlanId.vlanId("Any");
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mode RAW or TAGGED
|
||||
* @return the L2Mode if input is correct
|
||||
*/
|
||||
public static L2Mode parseMode(String mode) {
|
||||
|
||||
if (!mode.equals("RAW") && !mode.equals("TAGGED")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return L2Mode.valueOf(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param label the mpls label of the pseudowire
|
||||
* @return the MplsLabel
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string as a pseudowire id - which is an integer.
|
||||
*
|
||||
* @param id The id of pw in string form
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper method to verify if the tunnel is whether or not
|
||||
* supported.
|
||||
*
|
||||
* @param l2Tunnel the tunnel to verify
|
||||
* @return the result of the verification
|
||||
*/
|
||||
private void verifyTunnel(L2Tunnel l2Tunnel) {
|
||||
private static void verifyTunnel(L2Tunnel l2Tunnel) {
|
||||
|
||||
// Service delimiting tag not supported yet.
|
||||
if (!l2Tunnel.sdTag().equals(VlanId.NONE)) {
|
||||
throw new IllegalArgumentException(String.format("Service delimiting tag not supported yet for " +
|
||||
"pseudowire %d.", l2Tunnel.tunnelId()));
|
||||
"pseudowire %d.", l2Tunnel.tunnelId()));
|
||||
}
|
||||
|
||||
// Tag mode not supported yet.
|
||||
if (l2Tunnel.pwMode() == L2Mode.TAGGED) {
|
||||
throw new IllegalArgumentException(String.format("Tagged mode not supported yet for pseudowire %d.",
|
||||
l2Tunnel.tunnelId()));
|
||||
l2Tunnel.tunnelId()));
|
||||
}
|
||||
|
||||
// Raw mode without service delimiting tag
|
||||
@ -168,9 +153,8 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
* @param ingressOuter the ingress outer tag
|
||||
* @param egressInner the egress inner tag
|
||||
* @param egressOuter the egress outer tag
|
||||
* @return the result of verification
|
||||
*/
|
||||
private void verifyPolicy(ConnectPoint cP1,
|
||||
private static void verifyPolicy(ConnectPoint cP1,
|
||||
ConnectPoint cP2,
|
||||
VlanId ingressInner,
|
||||
VlanId ingressOuter,
|
||||
@ -180,7 +164,7 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
|
||||
if (cP1.deviceId().equals(cP2.deviceId())) {
|
||||
throw new IllegalArgumentException(String.format("Pseudowire connection points can not reside in the " +
|
||||
"same node, in pseudowire %d.", tunnelId));
|
||||
"same node, in pseudowire %d.", tunnelId));
|
||||
}
|
||||
|
||||
// We can have multiple tags, all of them can be NONE,
|
||||
@ -188,14 +172,15 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
// not have value if the inner tag is None
|
||||
if (ingressInner.equals(VlanId.NONE) && !ingressOuter.equals(VlanId.NONE)) {
|
||||
throw new IllegalArgumentException(String.format("Inner tag should not be empty when " +
|
||||
"outer tag is set for pseudowire %d for cP1.",
|
||||
tunnelId));
|
||||
"outer tag is set for pseudowire %d for cP1.",
|
||||
tunnelId));
|
||||
}
|
||||
|
||||
if (egressInner.equals(VlanId.NONE) && !egressOuter.equals(VlanId.NONE)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Inner tag should not be empty when" +
|
||||
" outer tag is set for pseudowire %d " +
|
||||
"for cP2.", tunnelId)));
|
||||
" outer tag is set for " +
|
||||
"pseudowire %d " +
|
||||
"for cP2.", tunnelId)));
|
||||
}
|
||||
|
||||
if (ingressInner.equals(VlanId.ANY) ||
|
||||
@ -203,7 +188,7 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
egressInner.equals(VlanId.ANY) ||
|
||||
egressOuter.equals(VlanId.ANY)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Wildcard VLAN matching not yet " +
|
||||
"supported for pseudowire %d.",
|
||||
"supported for pseudowire %d.",
|
||||
tunnelId)));
|
||||
}
|
||||
|
||||
@ -218,50 +203,52 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
if ((!ingressInner.equals(VlanId.NONE) &&
|
||||
ingressOuter.equals(VlanId.NONE) &&
|
||||
!egressOuter.equals(VlanId.NONE))
|
||||
|| (egressOuter.equals(VlanId.NONE) &&
|
||||
|| (egressOuter.equals(VlanId.NONE) &&
|
||||
!egressInner.equals(VlanId.NONE) &&
|
||||
!ingressOuter.equals(VlanId.NONE))) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Support for double-tag<->" +
|
||||
"single-tag is not supported" +
|
||||
" for pseudowire %d.", tunnelId)));
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Support for double-tag<->" +
|
||||
"single-tag is not supported" +
|
||||
" for pseudowire %d.", tunnelId)));
|
||||
}
|
||||
|
||||
if ((ingressInner.equals(VlanId.NONE) && !egressInner.equals(VlanId.NONE))
|
||||
|| (!ingressInner.equals(VlanId.NONE) && egressInner.equals(VlanId.NONE))) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("single-tag <-> untag is not supported" +
|
||||
" for pseudowire %d.", tunnelId)));
|
||||
" for pseudowire %d.", tunnelId)));
|
||||
}
|
||||
|
||||
|
||||
if (!ingressInner.equals(egressInner) && !ingressOuter.equals(egressOuter)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("We do not support changing both tags " +
|
||||
"in double tagged pws, only the outer," +
|
||||
" for pseudowire %d.", tunnelId)));
|
||||
"in double tagged pws, only the " +
|
||||
"outer," +
|
||||
" for pseudowire %d.", tunnelId)));
|
||||
}
|
||||
|
||||
// check if cp1 and port of cp1 exist
|
||||
if (deviceService.getDevice(cP1.deviceId()) == null) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("cP1 device %s does not exist for" +
|
||||
" pseudowire %d.", cP1.deviceId(),
|
||||
" pseudowire %d.", cP1.deviceId(),
|
||||
tunnelId)));
|
||||
}
|
||||
|
||||
if (deviceService.getPort(cP1) == null) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Port %s for cP1 device %s does not" +
|
||||
" exist for pseudowire %d.", cP1.port(),
|
||||
" exist for pseudowire %d.",
|
||||
cP1.port(),
|
||||
cP1.deviceId(), tunnelId)));
|
||||
}
|
||||
|
||||
// check if cp2 and port of cp2 exist
|
||||
if (deviceService.getDevice(cP2.deviceId()) == null) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("cP2 device %s does not exist for" +
|
||||
" pseudowire %d.", cP2.deviceId(),
|
||||
" pseudowire %d.", cP2.deviceId(),
|
||||
tunnelId)));
|
||||
}
|
||||
|
||||
if (deviceService.getPort(cP2) == null) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Port %s for cP2 device %s does " +
|
||||
"not exist for pseudowire %d.",
|
||||
"not exist for pseudowire %d.",
|
||||
cP2.port(), cP2.deviceId(), tunnelId)));
|
||||
}
|
||||
}
|
||||
@ -277,7 +264,7 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
* @param vlanSet Vlan set used with this configuration
|
||||
* @param tunnelSet Tunnel set used with this configuration
|
||||
*/
|
||||
private void verifyGlobalValidity(L2Tunnel tunnel,
|
||||
private static void verifyGlobalValidity(L2Tunnel tunnel,
|
||||
L2TunnelPolicy policy,
|
||||
Set<MplsLabel> labelSet,
|
||||
Map<ConnectPoint, Set<VlanId>> vlanSet,
|
||||
@ -285,8 +272,9 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
|
||||
if (tunnelSet.contains(tunnel.tunnelId())) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Tunnel Id %d already used by" +
|
||||
" another pseudowire, in " +
|
||||
"pseudowire %d!", tunnel.tunnelId(),
|
||||
" another pseudowire, in " +
|
||||
"pseudowire %d!",
|
||||
tunnel.tunnelId(),
|
||||
tunnel.tunnelId())));
|
||||
}
|
||||
tunnelSet.add(tunnel.tunnelId());
|
||||
@ -321,23 +309,25 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
|
||||
if (labelSet.contains(tunnel.pwLabel())) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Label %s already used by another" +
|
||||
" pseudowire, in pseudowire %d!",
|
||||
" pseudowire, in pseudowire %d!",
|
||||
tunnel.pwLabel(), tunnel.tunnelId())));
|
||||
}
|
||||
labelSet.add(tunnel.pwLabel());
|
||||
|
||||
if (vlanSet.get(cP1).contains(vlanToCheckCP1)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP1 %s already used " +
|
||||
"by another pseudowire, in pseudowire" +
|
||||
" %d!", vlanToCheckCP1, cP1,
|
||||
"by another pseudowire, in " +
|
||||
"pseudowire" +
|
||||
" %d!", vlanToCheckCP1, cP1,
|
||||
tunnel.tunnelId())));
|
||||
}
|
||||
vlanSet.get(cP1).add(vlanToCheckCP1);
|
||||
|
||||
if (vlanSet.get(cP2).contains(vlanToCheckCP2)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP2 %s already used" +
|
||||
" by another pseudowire, in" +
|
||||
" pseudowire %d!", vlanToCheckCP2, cP2,
|
||||
" by another pseudowire, in" +
|
||||
" pseudowire %d!", vlanToCheckCP2,
|
||||
cP2,
|
||||
tunnel.tunnelId())));
|
||||
}
|
||||
vlanSet.get(cP2).add(vlanToCheckCP2);
|
||||
@ -349,8 +339,9 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
// check if tagged pw affects tagged interface
|
||||
if (intf.vlanTagged().contains(vlanToCheckCP1)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP1 %s already" +
|
||||
" used for this interface, in" +
|
||||
" pseudowire %d!",
|
||||
" used for this" +
|
||||
" interface, in" +
|
||||
" pseudowire %d!",
|
||||
vlanToCheckCP1, cP1,
|
||||
tunnel.tunnelId())));
|
||||
}
|
||||
@ -359,29 +350,33 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
// check if it collides with untagged interface
|
||||
if ((intf.vlanNative() != null) && vlanToCheckCP1.equals(VlanId.NONE)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for cP1 " +
|
||||
"%s already used for this " +
|
||||
"interface, in pseudowire " +
|
||||
"%d!", cP1,
|
||||
tunnel.tunnelId())));
|
||||
"%s already used " +
|
||||
"for this " +
|
||||
"interface, in " +
|
||||
"pseudowire " +
|
||||
"%d!", cP1,
|
||||
tunnel.tunnelId())));
|
||||
}
|
||||
|
||||
// if vlanUntagged != null this interface is configured only with untagged traffic
|
||||
// check if it collides with untagged interface
|
||||
if ((intf.vlanUntagged() != null) && vlanToCheckCP1.equals(VlanId.NONE)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for " +
|
||||
"cP1 %s already" +
|
||||
" used for this interface," +
|
||||
" in pseudowire %d!",
|
||||
cP1, tunnel.tunnelId())));
|
||||
"cP1 %s already" +
|
||||
" used for this" +
|
||||
" interface," +
|
||||
" in pseudowire %d!",
|
||||
cP1, tunnel.tunnelId())));
|
||||
}
|
||||
});
|
||||
|
||||
intfService.getInterfacesByPort(cP2).stream()
|
||||
.forEach(intf -> {
|
||||
if (intf.vlanTagged().contains(vlanToCheckCP2)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP2 %s already" +
|
||||
" used for this interface, " +
|
||||
"in pseudowire %d!",
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP2 %s " +
|
||||
" used for " +
|
||||
"this interface, " +
|
||||
"in pseudowire %d!",
|
||||
vlanToCheckCP2, cP2,
|
||||
tunnel.tunnelId())));
|
||||
}
|
||||
@ -389,10 +384,12 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
// if vlanNative != null this interface is configured with untagged traffic also
|
||||
// check if it collides with untagged interface
|
||||
if ((intf.vlanNative() != null) && vlanToCheckCP2.equals(VlanId.NONE)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for cP2 %s " +
|
||||
"already used for this" +
|
||||
" interface, " +
|
||||
"in pseudowire %d!",
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic " +
|
||||
"for cP2 %s " +
|
||||
"already " +
|
||||
"used for this" +
|
||||
" interface, " +
|
||||
"in pseudowire %d!",
|
||||
cP2, tunnel.tunnelId())));
|
||||
}
|
||||
|
||||
@ -400,9 +397,10 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
// check if it collides with untagged interface
|
||||
if ((intf.vlanUntagged() != null) && vlanToCheckCP2.equals(VlanId.NONE)) {
|
||||
throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for cP2 %s" +
|
||||
" already" +
|
||||
" used for this interface, " +
|
||||
"in pseudowire %d!",
|
||||
" already" +
|
||||
" used for " +
|
||||
"this interface, " +
|
||||
"in pseudowire %d!",
|
||||
cP2, tunnel.tunnelId())));
|
||||
}
|
||||
});
|
||||
@ -413,9 +411,8 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
* Helper method to verify the integrity of the pseudo wire.
|
||||
*
|
||||
* @param l2TunnelDescription the pseudo wire description
|
||||
* @return the result of the check
|
||||
*/
|
||||
private void verifyPseudoWire(L2TunnelDescription l2TunnelDescription,
|
||||
private static void verifyPseudoWire(L2TunnelDescription l2TunnelDescription,
|
||||
Set<MplsLabel> labelSet,
|
||||
Map<ConnectPoint, Set<VlanId>> vlanset,
|
||||
Set<Long> tunnelSet) {
|
||||
@ -443,14 +440,7 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the configured pseudowires will create problems in the network.
|
||||
* If yes, then no pseudowires is deployed from this configuration.
|
||||
*
|
||||
* @param pseudowires Set of pseudowries to validate
|
||||
* @return returns true if everything goes well.
|
||||
*/
|
||||
public boolean configurationValidity(Set<L2TunnelDescription> pseudowires) {
|
||||
public static boolean configurationValidity(Set<L2TunnelDescription> pseudowires) {
|
||||
|
||||
// structures to keep pw information
|
||||
// in order to see if instantiating them will create
|
||||
@ -459,213 +449,30 @@ public class PwaasConfig extends Config<ApplicationId> {
|
||||
Set<MplsLabel> labelsUsed = new HashSet<>();
|
||||
Map<ConnectPoint, Set<VlanId>> vlanIds = new HashMap<>();
|
||||
|
||||
// check that pseudowires can be instantiated in the network
|
||||
// we try to guarantee that all the pws will work before
|
||||
// instantiating any of them
|
||||
for (L2TunnelDescription pw : pseudowires) {
|
||||
verifyPseudoWire(pw, labelsUsed, vlanIds, tunIds);
|
||||
// TODO : I know we should not use exceptions for flow control,
|
||||
// however this code was originally implemented in the configuration
|
||||
// addition where the exceptions were propagated and the configuration was
|
||||
// deemed not valid. I plan in the future to refactor the parts that
|
||||
// check the pseudowire validity.
|
||||
//
|
||||
// Ideally we would like to return a String which could also return to
|
||||
// the user issuing the rest request for adding the pseudowire.
|
||||
try {
|
||||
|
||||
// check that pseudowires can be instantiated in the network
|
||||
// we try to guarantee that all the pws will work before
|
||||
// instantiating any of them
|
||||
for (L2TunnelDescription pw : pseudowires) {
|
||||
verifyPseudoWire(pw, labelsUsed, vlanIds, tunIds);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
log.error("Caught exception while validating pseudowire : {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
|
||||
// return true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all pseudo wire keys.
|
||||
*
|
||||
* @return all keys (tunnels id)
|
||||
* @throws IllegalArgumentException if wrong format
|
||||
*/
|
||||
public Set<Long> getPwIds() {
|
||||
ImmutableSet.Builder<Long> builder = ImmutableSet.builder();
|
||||
object.fields().forEachRemaining(entry -> {
|
||||
Long tunnelId = Long.parseLong(entry.getKey());
|
||||
builder.add(tunnelId);
|
||||
});
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a vlan as a string. Returns the VlanId if
|
||||
* provided String can be parsed as an integer or is '' / '*'
|
||||
*
|
||||
* @param vlan string as read from configuration
|
||||
* @return VlanId
|
||||
* @throws IllegalArgumentException if wrong format of vlan
|
||||
*/
|
||||
public VlanId parseVlan(String vlan) {
|
||||
|
||||
if (vlan.equals("*") || vlan.equals("Any")) {
|
||||
return VlanId.vlanId("Any");
|
||||
} else if (vlan.equals("") || vlan.equals("None")) {
|
||||
return VlanId.vlanId("None");
|
||||
} else {
|
||||
try {
|
||||
VlanId newVlan = VlanId.vlanId(vlan);
|
||||
return newVlan;
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException(INVALID_VLAN);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param mode RAW or TAGGED
|
||||
* @return the L2Mode if input is correct
|
||||
* @throws IllegalArgumentException if not supported mode
|
||||
*/
|
||||
public L2Mode parseMode(String mode) {
|
||||
|
||||
if (!mode.equals("RAW") && !mode.equals("TAGGED")) {
|
||||
throw new IllegalArgumentException(INVALID_L2_MODE);
|
||||
}
|
||||
|
||||
return L2Mode.valueOf(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param label the mpls label of the pseudowire
|
||||
* @return the MplsLabel
|
||||
* @throws IllegalArgumentException if label is invalid
|
||||
*/
|
||||
public MplsLabel parsePWLabel(String label) {
|
||||
|
||||
try {
|
||||
MplsLabel pwLabel = MplsLabel.mplsLabel(label);
|
||||
return pwLabel;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(INVALID_PW_LABEL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns pw description of given pseudo wire id.
|
||||
*
|
||||
* @param tunnelId pseudo wire key
|
||||
* @return set of l2 tunnel descriptions
|
||||
* @throws IllegalArgumentException if wrong format
|
||||
*/
|
||||
public L2TunnelDescription getPwDescription(Long tunnelId) {
|
||||
JsonNode pwDescription = object.get(tunnelId.toString());
|
||||
if (!hasFields((ObjectNode) pwDescription,
|
||||
SRC_CP, SRC_INNER_TAG, SRC_OUTER_TAG,
|
||||
DST_CP, DST_INNER_TAG, DST_OUTER_TAG,
|
||||
MODE, SD_TAG, PW_LABEL)) {
|
||||
throw new IllegalArgumentException(MISSING_PARAMS);
|
||||
}
|
||||
String tempString;
|
||||
|
||||
tempString = pwDescription.get(SRC_CP).asText();
|
||||
ConnectPoint srcCp = ConnectPoint.deviceConnectPoint(tempString);
|
||||
|
||||
tempString = pwDescription.get(DST_CP).asText();
|
||||
ConnectPoint dstCp = ConnectPoint.deviceConnectPoint(tempString);
|
||||
|
||||
tempString = pwDescription.get(SRC_INNER_TAG).asText();
|
||||
VlanId srcInnerTag = parseVlan(tempString);
|
||||
|
||||
tempString = pwDescription.get(SRC_OUTER_TAG).asText();
|
||||
VlanId srcOuterTag = parseVlan(tempString);
|
||||
|
||||
tempString = pwDescription.get(DST_INNER_TAG).asText();
|
||||
VlanId dstInnerTag = parseVlan(tempString);
|
||||
|
||||
tempString = pwDescription.get(DST_OUTER_TAG).asText();
|
||||
VlanId dstOuterTag = parseVlan(tempString);
|
||||
|
||||
tempString = pwDescription.get(MODE).asText();
|
||||
L2Mode l2Mode = parseMode(tempString);
|
||||
|
||||
tempString = pwDescription.get(SD_TAG).asText();
|
||||
VlanId sdTag = parseVlan(tempString);
|
||||
|
||||
tempString = pwDescription.get(PW_LABEL).asText();
|
||||
MplsLabel pwLabel = parsePWLabel(tempString);
|
||||
|
||||
L2Tunnel l2Tunnel = new DefaultL2Tunnel(
|
||||
l2Mode,
|
||||
sdTag,
|
||||
tunnelId,
|
||||
pwLabel
|
||||
);
|
||||
|
||||
L2TunnelPolicy l2TunnelPolicy = new DefaultL2TunnelPolicy(
|
||||
tunnelId,
|
||||
srcCp,
|
||||
srcInnerTag,
|
||||
srcOuterTag,
|
||||
dstCp,
|
||||
dstInnerTag,
|
||||
dstOuterTag
|
||||
);
|
||||
|
||||
return new DefaultL2TunnelDescription(l2Tunnel, l2TunnelPolicy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a pseudowire from the configuration tree.
|
||||
* @param pwId Pseudowire id
|
||||
* @return null if pwId did not exist, or the object representing the
|
||||
* udpated configuration tree
|
||||
*/
|
||||
public ObjectNode removePseudowire(String pwId) {
|
||||
|
||||
JsonNode value = object.remove(pwId);
|
||||
if (value == null) {
|
||||
return (ObjectNode) value;
|
||||
} else {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a pseudowire to the configuration tree of pwwas. It also checks
|
||||
* if the configuration is valid, if not return null and does not add the node,
|
||||
* if yes return the new configuration. Caller will propagate update events.
|
||||
*
|
||||
* If the pseudowire already exists in the configuration it gets updated.
|
||||
*
|
||||
* @param tunnelId Id of tunnel
|
||||
* @param pwLabel PW label of tunnel
|
||||
* @param cP1 Connection point 1
|
||||
* @param cP1InnerVlan Inner vlan of cp1
|
||||
* @param cP1OuterVlan Outer vlan of cp2
|
||||
* @param cP2 Connection point 2
|
||||
* @param cP2InnerVlan Inner vlan of cp2
|
||||
* @param cP2OuterVlan Outer vlan of cp2
|
||||
* @param mode Mode for the pw
|
||||
* @param sdTag Service delimiting tag for the pw
|
||||
* @return The ObjectNode config if configuration is valid with the new pseudowire
|
||||
* or null.
|
||||
*/
|
||||
public ObjectNode addPseudowire(String tunnelId, String pwLabel, String cP1,
|
||||
String cP1InnerVlan, String cP1OuterVlan, String cP2,
|
||||
String cP2InnerVlan, String cP2OuterVlan,
|
||||
String mode, String sdTag) {
|
||||
|
||||
|
||||
ObjectNode newPw = new ObjectNode(JsonNodeFactory.instance);
|
||||
|
||||
// add fields for pseudowire
|
||||
newPw.put(SRC_CP, cP1);
|
||||
newPw.put(DST_CP, cP2);
|
||||
newPw.put(PW_LABEL, pwLabel);
|
||||
newPw.put(SRC_INNER_TAG, cP1InnerVlan);
|
||||
newPw.put(SRC_OUTER_TAG, cP1OuterVlan);
|
||||
newPw.put(DST_INNER_TAG, cP2InnerVlan);
|
||||
newPw.put(DST_OUTER_TAG, cP2OuterVlan);
|
||||
newPw.put(SD_TAG, sdTag);
|
||||
newPw.put(MODE, mode);
|
||||
|
||||
object.set(tunnelId, newPw);
|
||||
|
||||
if (!isValid()) {
|
||||
log.info("Pseudowire could not be created : {}");
|
||||
object.remove(tunnelId);
|
||||
return null;
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
}
|
||||
@ -1,399 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.onosproject.segmentrouting;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.onlab.packet.IpAddress;
|
||||
import org.onlab.packet.IpPrefix;
|
||||
import org.onlab.packet.MacAddress;
|
||||
import org.onlab.packet.MplsLabel;
|
||||
import org.onlab.packet.VlanId;
|
||||
import org.onosproject.TestApplicationId;
|
||||
import org.onosproject.core.ApplicationId;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
import org.onosproject.net.DefaultAnnotations;
|
||||
import org.onosproject.net.DefaultHost;
|
||||
import org.onosproject.net.Device;
|
||||
import org.onosproject.net.DeviceId;
|
||||
import org.onosproject.net.Host;
|
||||
import org.onosproject.net.HostId;
|
||||
import org.onosproject.net.HostLocation;
|
||||
import org.onosproject.net.PortNumber;
|
||||
import org.onosproject.net.config.Config;
|
||||
import org.onosproject.net.config.ConfigApplyDelegate;
|
||||
import org.onosproject.net.device.DeviceService;
|
||||
import org.onosproject.net.host.InterfaceIpAddress;
|
||||
import org.onosproject.net.intf.Interface;
|
||||
import org.onosproject.net.intf.InterfaceService;
|
||||
import org.onosproject.net.provider.ProviderId;
|
||||
import org.onosproject.segmentrouting.config.PwaasConfig;
|
||||
|
||||
import org.onosproject.segmentrouting.pwaas.L2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
|
||||
import org.onosproject.segmentrouting.pwaas.L2Mode;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Unit tests for class {@link PwaasConfig}.
|
||||
*/
|
||||
public class PwaasConfigTest {
|
||||
|
||||
private static final String TUNNEL_ID_1 = "1";
|
||||
private static final String TUNNEL_ID_2 = "20";
|
||||
private static final String NOT_PRESENT_TUNNEL_ID = "2";
|
||||
private static final ConnectPoint INGRESS_1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
|
||||
private static final ConnectPoint INGRESS_2 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1");
|
||||
private static final ConnectPoint EGRESS_1 = ConnectPoint.deviceConnectPoint("of:0000000000000002/1");
|
||||
private static final ConnectPoint EGRESS_2 = ConnectPoint.deviceConnectPoint("of:0000000000000002/1");
|
||||
private static final VlanId INGRESS_INNER_TAG_1 = VlanId.vlanId("10");
|
||||
private static final VlanId INGRESS_INNER_TAG_2 = VlanId.vlanId("100");
|
||||
private static final VlanId INGRESS_OUTER_TAG_1 = VlanId.vlanId("20");
|
||||
private static final VlanId INGRESS_OUTER_TAG_2 = VlanId.vlanId("200");
|
||||
private static final VlanId EGRESS_INNER_TAG_1 = VlanId.vlanId("10");
|
||||
private static final VlanId EGRESS_INNER_TAG_2 = VlanId.vlanId("100");
|
||||
private static final VlanId EGRESS_OUTER_TAG_1 = VlanId.vlanId("21");
|
||||
private static final VlanId EGRESS_OUTER_TAG_2 = VlanId.vlanId("210");
|
||||
private static final String MODE_1 = "RAW";
|
||||
private static final String MODE_2 = "RAW";
|
||||
private static final VlanId SD_TAG_1 = VlanId.NONE;
|
||||
private static final VlanId SD_TAG_2 = VlanId.NONE;
|
||||
private static final MplsLabel PW_LABEL_1 = MplsLabel.mplsLabel("255");
|
||||
private static final MplsLabel PW_LABEL_2 = MplsLabel.mplsLabel("1255");
|
||||
|
||||
/*
|
||||
* Configuration below copied from host handler test.
|
||||
*/
|
||||
|
||||
// Host Mac, VLAN
|
||||
private static final ProviderId PROVIDER_ID = ProviderId.NONE;
|
||||
private static final MacAddress HOST_MAC = MacAddress.valueOf("00:00:00:00:00:01");
|
||||
private static final VlanId HOST_VLAN_UNTAGGED = VlanId.NONE;
|
||||
private static final HostId HOST_ID_UNTAGGED = HostId.hostId(HOST_MAC, HOST_VLAN_UNTAGGED);
|
||||
private static final VlanId HOST_VLAN_TAGGED = VlanId.vlanId((short) 20);
|
||||
private static final HostId HOST_ID_TAGGED = HostId.hostId(HOST_MAC, HOST_VLAN_TAGGED);
|
||||
// Host IP
|
||||
private static final IpAddress HOST_IP11 = IpAddress.valueOf("10.0.1.1");
|
||||
private static final IpAddress HOST_IP21 = IpAddress.valueOf("10.0.2.1");
|
||||
private static final IpAddress HOST_IP12 = IpAddress.valueOf("10.0.1.2");
|
||||
private static final IpAddress HOST_IP13 = IpAddress.valueOf("10.0.1.3");
|
||||
private static final IpAddress HOST_IP14 = IpAddress.valueOf("10.0.1.4");
|
||||
private static final IpAddress HOST_IP32 = IpAddress.valueOf("10.0.3.2");
|
||||
// Device
|
||||
private static final DeviceId DEV1 = DeviceId.deviceId("of:0000000000000001");
|
||||
private static final DeviceId DEV2 = DeviceId.deviceId("of:0000000000000002");
|
||||
private static final DeviceId DEV3 = DeviceId.deviceId("of:0000000000000003");
|
||||
private static final DeviceId DEV4 = DeviceId.deviceId("of:0000000000000004");
|
||||
private static final DeviceId DEV5 = DeviceId.deviceId("of:0000000000000005");
|
||||
private static final DeviceId DEV6 = DeviceId.deviceId("of:0000000000000006");
|
||||
// Port
|
||||
private static final PortNumber P1 = PortNumber.portNumber(1);
|
||||
private static final PortNumber P2 = PortNumber.portNumber(2);
|
||||
private static final PortNumber P3 = PortNumber.portNumber(3);
|
||||
private static final PortNumber P9 = PortNumber.portNumber(9);
|
||||
// Connect Point
|
||||
private static final ConnectPoint CP11 = new ConnectPoint(DEV1, P1);
|
||||
private static final HostLocation HOST_LOC11 = new HostLocation(CP11, 0);
|
||||
private static final ConnectPoint CP12 = new ConnectPoint(DEV1, P2);
|
||||
private static final HostLocation HOST_LOC12 = new HostLocation(CP12, 0);
|
||||
private static final ConnectPoint CP13 = new ConnectPoint(DEV1, P3);
|
||||
private static final HostLocation HOST_LOC13 = new HostLocation(CP13, 0);
|
||||
private static final ConnectPoint CP21 = new ConnectPoint(DEV2, P1);
|
||||
private static final HostLocation HOST_LOC21 = new HostLocation(CP21, 0);
|
||||
private static final ConnectPoint CP22 = new ConnectPoint(DEV2, P2);
|
||||
private static final HostLocation HOST_LOC22 = new HostLocation(CP22, 0);
|
||||
// Connect Point for dual-homed host failover
|
||||
private static final ConnectPoint CP31 = new ConnectPoint(DEV3, P1);
|
||||
private static final HostLocation HOST_LOC31 = new HostLocation(CP31, 0);
|
||||
private static final ConnectPoint CP32 = new ConnectPoint(DEV3, P2);
|
||||
private static final HostLocation HOST_LOC32 = new HostLocation(CP32, 0);
|
||||
private static final ConnectPoint CP41 = new ConnectPoint(DEV4, P1);
|
||||
private static final HostLocation HOST_LOC41 = new HostLocation(CP41, 0);
|
||||
private static final ConnectPoint CP39 = new ConnectPoint(DEV3, P9);
|
||||
private static final ConnectPoint CP49 = new ConnectPoint(DEV4, P9);
|
||||
// Conenct Point for mastership test
|
||||
private static final ConnectPoint CP51 = new ConnectPoint(DEV5, P1);
|
||||
private static final HostLocation HOST_LOC51 = new HostLocation(CP51, 0);
|
||||
private static final ConnectPoint CP61 = new ConnectPoint(DEV6, P1);
|
||||
private static final HostLocation HOST_LOC61 = new HostLocation(CP61, 0);
|
||||
// Interface VLAN
|
||||
private static final VlanId INTF_VLAN_UNTAGGED = VlanId.vlanId((short) 10);
|
||||
private static final Set<VlanId> INTF_VLAN_TAGGED = Sets.newHashSet(VlanId.vlanId((short) 20));
|
||||
private static final VlanId INTF_VLAN_NATIVE = VlanId.vlanId((short) 30);
|
||||
private static final Set<VlanId> INTF_VLAN_PAIR = Sets.newHashSet(VlanId.vlanId((short) 10),
|
||||
VlanId.vlanId((short) 20), VlanId.vlanId((short) 30));
|
||||
private static final VlanId INTF_VLAN_OTHER = VlanId.vlanId((short) 40);
|
||||
// Interface subnet
|
||||
private static final IpPrefix INTF_PREFIX1 = IpPrefix.valueOf("10.0.1.254/24");
|
||||
private static final IpPrefix INTF_PREFIX2 = IpPrefix.valueOf("10.0.2.254/24");
|
||||
private static final IpPrefix INTF_PREFIX3 = IpPrefix.valueOf("10.0.3.254/24");
|
||||
private static final InterfaceIpAddress INTF_IP1 =
|
||||
new InterfaceIpAddress(INTF_PREFIX1.address(), INTF_PREFIX1);
|
||||
private static final InterfaceIpAddress INTF_IP2 =
|
||||
new InterfaceIpAddress(INTF_PREFIX2.address(), INTF_PREFIX2);
|
||||
private static final InterfaceIpAddress INTF_IP3 =
|
||||
new InterfaceIpAddress(INTF_PREFIX3.address(), INTF_PREFIX3);
|
||||
// Interfaces
|
||||
private static final Interface INTF11 =
|
||||
new Interface(null, CP11, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
|
||||
INTF_VLAN_UNTAGGED, null, null);
|
||||
private static final Interface INTF12 =
|
||||
new Interface(null, CP12, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
|
||||
INTF_VLAN_UNTAGGED, null, null);
|
||||
private static final Interface INTF13 =
|
||||
new Interface(null, CP13, Lists.newArrayList(INTF_IP2), MacAddress.NONE, null,
|
||||
null, INTF_VLAN_TAGGED, INTF_VLAN_NATIVE);
|
||||
private static final Interface INTF21 =
|
||||
new Interface(null, CP21, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
|
||||
INTF_VLAN_UNTAGGED, null, null);
|
||||
private static final Interface INTF22 =
|
||||
new Interface(null, CP22, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
|
||||
INTF_VLAN_UNTAGGED, null, null);
|
||||
private static final Interface INTF31 =
|
||||
new Interface(null, CP31, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
|
||||
INTF_VLAN_UNTAGGED, null, null);
|
||||
private static final Interface INTF32 =
|
||||
new Interface(null, CP32, Lists.newArrayList(INTF_IP3), MacAddress.NONE, null,
|
||||
INTF_VLAN_OTHER, null, null);
|
||||
private static final Interface INTF39 =
|
||||
new Interface(null, CP39, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
|
||||
null, INTF_VLAN_PAIR, null);
|
||||
private static final Interface INTF41 =
|
||||
new Interface(null, CP41, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
|
||||
INTF_VLAN_UNTAGGED, null, null);
|
||||
private static final Interface INTF49 =
|
||||
new Interface(null, CP49, Lists.newArrayList(INTF_IP1), MacAddress.NONE, null,
|
||||
null, INTF_VLAN_PAIR, null);
|
||||
// Host
|
||||
private static final Host HOST1 = new DefaultHost(PROVIDER_ID, HOST_ID_UNTAGGED, HOST_MAC,
|
||||
HOST_VLAN_UNTAGGED,
|
||||
Sets.newHashSet(HOST_LOC11, HOST_LOC21),
|
||||
Sets.newHashSet(HOST_IP11),
|
||||
false);
|
||||
|
||||
// A set of hosts
|
||||
private static final Set<Host> HOSTS = Sets.newHashSet(HOST1);
|
||||
// A set of devices of which we have mastership
|
||||
private static final Set<DeviceId> LOCAL_DEVICES = Sets.newHashSet(DEV1, DEV2, DEV3, DEV4);
|
||||
// A set of interfaces
|
||||
private static final Set<Interface> INTERFACES = Sets.newHashSet(INTF11, INTF12, INTF13, INTF21,
|
||||
INTF22, INTF31, INTF32, INTF39, INTF41, INTF49);
|
||||
|
||||
private PwaasConfig config;
|
||||
private PwaasConfig invalidConfigVlan;
|
||||
private PwaasConfig invalidConfigMode;
|
||||
private PwaasConfig invalidConfigLabel;
|
||||
private PwaasConfig invalidConfigConflictingVlan;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
InputStream jsonStream = PwaasConfig.class
|
||||
.getResourceAsStream("/pwaas.json");
|
||||
InputStream jsonStreamInvalid1 = PwaasConfig.class
|
||||
.getResourceAsStream("/pwaas-invalid-mode.json");
|
||||
InputStream jsonStreamInvalid2 = PwaasConfig.class
|
||||
.getResourceAsStream("/pwaas-invalid-pwlabel.json");
|
||||
InputStream jsonStreamInvalid3 = PwaasConfig.class
|
||||
.getResourceAsStream("/pwaas-invalid-vlan.json");
|
||||
InputStream jsonStreamInvalid4 = PwaasConfig.class
|
||||
.getResourceAsStream("/pwaas-conflicting-vlan.json");
|
||||
|
||||
String key = SegmentRoutingManager.APP_NAME;
|
||||
ApplicationId subject = new TestApplicationId(key);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
|
||||
JsonNode jsonNode = mapper.readTree(jsonStream);
|
||||
JsonNode jsonNodeInvalid1 = mapper.readTree(jsonStreamInvalid1);
|
||||
JsonNode jsonNodeInvalid2 = mapper.readTree(jsonStreamInvalid2);
|
||||
JsonNode jsonNodeInvalid3 = mapper.readTree(jsonStreamInvalid3);
|
||||
JsonNode jsonNodeInvalid4 = mapper.readTree(jsonStreamInvalid4);
|
||||
|
||||
ConfigApplyDelegate delegate = new MockDelegate();
|
||||
|
||||
DeviceService devService = new MockDeviceService();
|
||||
InterfaceService infService = new MockInterfaceService(INTERFACES);
|
||||
|
||||
// create two devices and add them
|
||||
DefaultAnnotations.Builder builderDev1 = DefaultAnnotations.builder();
|
||||
DefaultAnnotations.Builder builderDev2 = DefaultAnnotations.builder();
|
||||
|
||||
Device dev1 = new MockDevice(DEV1, builderDev1.build());
|
||||
Device dev2 = new MockDevice(DEV2, builderDev2.build());
|
||||
((MockDeviceService) devService).addDevice(dev1);
|
||||
((MockDeviceService) devService).addDevice(dev2);
|
||||
|
||||
config = new PwaasConfig(devService, infService);
|
||||
invalidConfigVlan = new PwaasConfig(devService, infService);
|
||||
invalidConfigMode = new PwaasConfig(devService, infService);
|
||||
invalidConfigLabel = new PwaasConfig(devService, infService);
|
||||
invalidConfigConflictingVlan = new PwaasConfig(devService, infService);
|
||||
|
||||
config.init(subject, key, jsonNode, mapper, delegate);
|
||||
invalidConfigVlan.init(subject, key, jsonNodeInvalid1, mapper, delegate);
|
||||
invalidConfigMode.init(subject, key, jsonNodeInvalid2, mapper, delegate);
|
||||
invalidConfigLabel.init(subject, key, jsonNodeInvalid3, mapper, delegate);
|
||||
invalidConfigConflictingVlan.init(subject, key, jsonNodeInvalid4, mapper, delegate);
|
||||
|
||||
config.deviceService = devService;
|
||||
config.intfService = infService;
|
||||
|
||||
invalidConfigVlan.deviceService = devService;
|
||||
invalidConfigVlan.intfService = infService;
|
||||
|
||||
invalidConfigLabel.deviceService = devService;
|
||||
invalidConfigLabel.intfService = infService;
|
||||
|
||||
invalidConfigMode.deviceService = devService;
|
||||
invalidConfigMode.intfService = infService;
|
||||
|
||||
invalidConfigConflictingVlan.deviceService = devService;
|
||||
invalidConfigConflictingVlan.intfService = infService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests config validity.
|
||||
*/
|
||||
@Test
|
||||
public void testIsValid() {
|
||||
try {
|
||||
assertTrue(config.isValid());
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertTrue(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests config in-validity.
|
||||
*/
|
||||
@Test
|
||||
public void testValid1() {
|
||||
assertFalse(invalidConfigVlan.isValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValid2() {
|
||||
assertFalse(invalidConfigMode.isValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValid3() {
|
||||
assertFalse(invalidConfigLabel.isValid());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValid4() {
|
||||
assertFalse(invalidConfigConflictingVlan.isValid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPwIds.
|
||||
*/
|
||||
@Test
|
||||
public void testGetPwIds() {
|
||||
Set<Long> pwIds = config.getPwIds();
|
||||
|
||||
assertThat(pwIds.size(), is(2));
|
||||
assertTrue(pwIds.contains(Long.parseLong(TUNNEL_ID_1)));
|
||||
assertTrue(pwIds.contains(Long.parseLong(TUNNEL_ID_2)));
|
||||
assertFalse(pwIds.contains(Long.parseLong(NOT_PRESENT_TUNNEL_ID)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPwDescription.
|
||||
*/
|
||||
@Test
|
||||
public void testGetPwDescription() {
|
||||
L2TunnelDescription l2TunnelDescription = null;
|
||||
|
||||
L2Tunnel l2Tunnel = new DefaultL2Tunnel(
|
||||
L2Mode.valueOf(MODE_1),
|
||||
SD_TAG_1,
|
||||
Long.parseLong(TUNNEL_ID_1),
|
||||
PW_LABEL_1
|
||||
);
|
||||
L2TunnelPolicy l2TunnelPolicy = new DefaultL2TunnelPolicy(
|
||||
Long.parseLong(TUNNEL_ID_1),
|
||||
INGRESS_1,
|
||||
INGRESS_INNER_TAG_1,
|
||||
INGRESS_OUTER_TAG_1,
|
||||
EGRESS_1,
|
||||
EGRESS_INNER_TAG_1,
|
||||
EGRESS_OUTER_TAG_1
|
||||
);
|
||||
|
||||
l2TunnelDescription = config.getPwDescription(Long.parseLong(TUNNEL_ID_1));
|
||||
assertThat(l2TunnelDescription.l2Tunnel().pwMode(), is(l2Tunnel.pwMode()));
|
||||
assertThat(l2TunnelDescription.l2Tunnel().sdTag(), is(l2Tunnel.sdTag()));
|
||||
assertThat(l2TunnelDescription.l2Tunnel().tunnelId(), is(l2Tunnel.tunnelId()));
|
||||
assertThat(l2TunnelDescription.l2Tunnel().pwLabel(), is(l2Tunnel.pwLabel()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().tunnelId(), is(l2TunnelPolicy.tunnelId()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP1InnerTag(), is(l2TunnelPolicy.cP1InnerTag()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP1OuterTag(), is(l2TunnelPolicy.cP1OuterTag()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP2InnerTag(), is(l2TunnelPolicy.cP2InnerTag()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP2OuterTag(), is(l2TunnelPolicy.cP2OuterTag()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP1(), is(l2TunnelPolicy.cP1()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP2(), is(l2TunnelPolicy.cP2()));
|
||||
|
||||
l2Tunnel = new DefaultL2Tunnel(
|
||||
L2Mode.valueOf(MODE_2),
|
||||
SD_TAG_2,
|
||||
Long.parseLong(TUNNEL_ID_2),
|
||||
PW_LABEL_2
|
||||
);
|
||||
l2TunnelPolicy = new DefaultL2TunnelPolicy(
|
||||
Long.parseLong(TUNNEL_ID_2),
|
||||
INGRESS_2,
|
||||
INGRESS_INNER_TAG_2,
|
||||
INGRESS_OUTER_TAG_2,
|
||||
EGRESS_2,
|
||||
EGRESS_INNER_TAG_2,
|
||||
EGRESS_OUTER_TAG_2
|
||||
);
|
||||
|
||||
l2TunnelDescription = config.getPwDescription(Long.parseLong(TUNNEL_ID_2));
|
||||
assertThat(l2TunnelDescription.l2Tunnel().pwMode(), is(l2Tunnel.pwMode()));
|
||||
assertThat(l2TunnelDescription.l2Tunnel().sdTag(), is(l2Tunnel.sdTag()));
|
||||
assertThat(l2TunnelDescription.l2Tunnel().tunnelId(), is(l2Tunnel.tunnelId()));
|
||||
assertThat(l2TunnelDescription.l2Tunnel().pwLabel(), is(l2Tunnel.pwLabel()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().tunnelId(), is(l2TunnelPolicy.tunnelId()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP1InnerTag(), is(l2TunnelPolicy.cP1InnerTag()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP1OuterTag(), is(l2TunnelPolicy.cP1OuterTag()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP2OuterTag(), is(l2TunnelPolicy.cP2OuterTag()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP2OuterTag(), is(l2TunnelPolicy.cP2OuterTag()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP1(), is(l2TunnelPolicy.cP1()));
|
||||
assertThat(l2TunnelDescription.l2TunnelPolicy().cP2(), is(l2TunnelPolicy.cP2()));
|
||||
}
|
||||
|
||||
private class MockDelegate implements ConfigApplyDelegate {
|
||||
@Override
|
||||
public void onApply(Config config) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -15,6 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Segment routing application components.
|
||||
* Segment routing REST implementation.
|
||||
*/
|
||||
package org.onosproject.segmentrouting.web;
|
||||
@ -26,7 +26,6 @@ import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
@ -37,7 +36,7 @@ import java.util.List;
|
||||
/**
|
||||
* Query, create and remove segment routing plicies.
|
||||
*/
|
||||
@Path("policy")
|
||||
// @Path("policy")
|
||||
public class PolicyWebResource extends AbstractWebResource {
|
||||
|
||||
private static final PolicyCodec POLICY_CODEC = new PolicyCodec();
|
||||
|
||||
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2015-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.onosproject.segmentrouting.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.onlab.packet.MplsLabel;
|
||||
import org.onlab.packet.VlanId;
|
||||
import org.onosproject.codec.CodecContext;
|
||||
import org.onosproject.codec.JsonCodec;
|
||||
import org.onosproject.net.ConnectPoint;
|
||||
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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*;
|
||||
|
||||
/**
|
||||
* Codec of PseudowireCodec class.
|
||||
*/
|
||||
public final class PseudowireCodec extends JsonCodec<DefaultL2TunnelDescription> {
|
||||
|
||||
// JSON field names
|
||||
private static final String PW_ID = "pwId";
|
||||
private static final String CP1 = "cP1";
|
||||
private static final String CP2 = "cP2";
|
||||
private static final String CP1_INNER_TAG = "cP1InnerTag";
|
||||
private static final String CP1_OUTER_TAG = "cP1OuterTag";
|
||||
private static final String CP2_INNER_TAG = "cP2InnerTag";
|
||||
private static final String CP2_OUTER_TAG = "cP2OouterTag";
|
||||
private static final String MODE = "mode";
|
||||
private static final String SERVICE_DELIM_TAG = "serviceTag";
|
||||
private static final String PW_LABEL = "pwLabel";
|
||||
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(PseudowireCodec.class);
|
||||
|
||||
@Override
|
||||
public ObjectNode encode(DefaultL2TunnelDescription pseudowire, CodecContext context) {
|
||||
final ObjectNode result = context.mapper().createObjectNode()
|
||||
.put(PW_ID, pseudowire.l2Tunnel().tunnelId());
|
||||
|
||||
result.put(CP1, pseudowire.l2TunnelPolicy().cP1().toString());
|
||||
result.put(CP2, pseudowire.l2TunnelPolicy().cP2().toString());
|
||||
|
||||
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(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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a json containg a single field with the pseudowire id.
|
||||
*
|
||||
* @param json Json to decode.
|
||||
* @return The pseudowire id.
|
||||
*/
|
||||
public Integer decodeId(ObjectNode json) {
|
||||
|
||||
Integer id = parsePwId(json.path(PW_ID).asText());
|
||||
if (id == null) {
|
||||
log.error("Pseudowire id is not an integer!");
|
||||
return null;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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,
|
||||
cP2, cP2InnerVlan, cP2OuterVlan);
|
||||
|
||||
return new DefaultL2TunnelDescription(l2Tunnel, l2Policy);
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright 2015-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.onosproject.segmentrouting.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.onosproject.rest.AbstractWebResource;
|
||||
import org.onosproject.segmentrouting.SegmentRoutingService;
|
||||
import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
|
||||
import org.onosproject.segmentrouting.pwaas.L2Tunnel;
|
||||
import org.onosproject.segmentrouting.pwaas.L2TunnelHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Query, create and remove pseudowires.
|
||||
*/
|
||||
@Path("pseudowire")
|
||||
public class PseudowireWebResource extends AbstractWebResource {
|
||||
|
||||
private static final PseudowireCodec PSEUDOWIRE_CODEC = new PseudowireCodec();
|
||||
|
||||
private static Logger log = LoggerFactory
|
||||
.getLogger(PseudowireWebResource.class);
|
||||
|
||||
/**
|
||||
* Get all pseudowires.
|
||||
* Returns an array of pseudowires.
|
||||
*
|
||||
* @return status of OK
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.APPLICATION_JSON)
|
||||
public Response getPseudowire() {
|
||||
SegmentRoutingService srService = get(SegmentRoutingService.class);
|
||||
|
||||
log.debug("Fetching pseudowires form rest api!");
|
||||
|
||||
List<L2TunnelPolicy> policies = srService.getL2Policies();
|
||||
List<L2Tunnel> tunnels = srService.getL2Tunnels();
|
||||
List<DefaultL2TunnelDescription> pseudowires = tunnels.stream()
|
||||
.map(l2Tunnel -> {
|
||||
L2TunnelPolicy policy = null;
|
||||
for (L2TunnelPolicy l2Policy : policies) {
|
||||
if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
|
||||
policy = l2Policy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// return a copy
|
||||
return new DefaultL2TunnelDescription(l2Tunnel, policy);
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ObjectNode result = new ObjectMapper().createObjectNode();
|
||||
result.set("pseudowires", new PseudowireCodec().encode(pseudowires, this));
|
||||
|
||||
return ok(result.toString()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new pseudowire.
|
||||
*
|
||||
* @param input JSON stream for pseudowire to create
|
||||
* @return Response with appropriate status
|
||||
* @throws IOException Throws IO exception.
|
||||
* @onos.rsModel PseudowireCreate
|
||||
*/
|
||||
@POST
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response createPseudowire(InputStream input) throws IOException {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
ObjectNode pseudowireJson = (ObjectNode) mapper.readTree(input);
|
||||
SegmentRoutingService srService = get(SegmentRoutingService.class);
|
||||
|
||||
DefaultL2TunnelDescription pseudowire = PSEUDOWIRE_CODEC.decode(pseudowireJson, this);
|
||||
if (pseudowire == null) {
|
||||
return Response.serverError().status(Response.Status.BAD_REQUEST).build();
|
||||
}
|
||||
|
||||
log.info("Creating pseudowire {} from rest api!", pseudowire.l2Tunnel().tunnelId());
|
||||
|
||||
L2TunnelHandler.Result res = srService.addPseudowire(pseudowire);
|
||||
switch (res) {
|
||||
case ADDITION_ERROR:
|
||||
log.error("Pseudowire {} could not be added, error in configuration," +
|
||||
" please check logs for more details!",
|
||||
pseudowire.l2Tunnel().tunnelId());
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a pseudowire.
|
||||
*
|
||||
* @param input JSON stream for pseudowire to delete
|
||||
* @return Response with appropriate status
|
||||
* @throws IOException Throws IO exception.
|
||||
* @onos.rsModel PseudowireDelete
|
||||
*/
|
||||
@DELETE
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Response removePseudowire(InputStream input) throws IOException {
|
||||
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
ObjectNode pseudowireJson = (ObjectNode) mapper.readTree(input);
|
||||
SegmentRoutingService srService = get(SegmentRoutingService.class);
|
||||
|
||||
Integer pseudowireId = PSEUDOWIRE_CODEC.decodeId(pseudowireJson);
|
||||
if (pseudowireId == null) {
|
||||
return Response.serverError().status(Response.Status.BAD_REQUEST).build();
|
||||
}
|
||||
|
||||
log.info("Deleting pseudowire {} from rest api!", pseudowireId);
|
||||
|
||||
L2TunnelHandler.Result res = srService.removePseudowire(pseudowireId);
|
||||
switch (res) {
|
||||
case REMOVAL_ERROR:
|
||||
log.error("Pseudowire {} could not be removed, error in configuration," +
|
||||
" please check logs for more details!",
|
||||
pseudowireId);
|
||||
|
||||
return Response.noContent().build();
|
||||
case SUCCESS:
|
||||
log.info("Pseudowire {} was removed succesfully!", pseudowireId);
|
||||
return Response.noContent().build();
|
||||
default:
|
||||
return Response.noContent().build();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2015-present Open Networking Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.onosproject.segmentrouting.web;
|
||||
|
||||
import org.onlab.rest.AbstractWebApplication;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Segment Routing Web application.
|
||||
*/
|
||||
public class SegmentRoutingWebApplication extends AbstractWebApplication {
|
||||
@Override
|
||||
public Set<Class<?>> getClasses() {
|
||||
return getClasses(PseudowireWebResource.class);
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,6 @@ import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.DELETE;
|
||||
import javax.ws.rs.GET;
|
||||
import javax.ws.rs.POST;
|
||||
import javax.ws.rs.Path;
|
||||
import javax.ws.rs.Produces;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
@ -37,7 +36,7 @@ import java.util.List;
|
||||
/**
|
||||
* Query, create and remove segment routing tunnels.
|
||||
*/
|
||||
@Path("tunnel")
|
||||
// @Path("tunnel")
|
||||
public class TunnelWebResource extends AbstractWebResource {
|
||||
|
||||
private static final TunnelCodec TUNNEL_CODEC = new TunnelCodec();
|
||||
|
||||
@ -15,6 +15,6 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Set of resources implementing the segment routing application REST API.
|
||||
* Segment routing application components.
|
||||
*/
|
||||
package org.onosproject.segmentrouting.web;
|
||||
@ -0,0 +1,68 @@
|
||||
{
|
||||
"type": "object",
|
||||
"title": "pseudowire-creation",
|
||||
"required": [
|
||||
"pwId",
|
||||
"cP1",
|
||||
"cP2",
|
||||
"cP1InnerTag",
|
||||
"cP1OuterTag",
|
||||
"cP2InnerTag",
|
||||
"cP2OuterTag",
|
||||
"mode",
|
||||
"sdTag",
|
||||
"pwLabel"
|
||||
],
|
||||
"properties": {
|
||||
"pwId": {
|
||||
"type": "string",
|
||||
"example": "42",
|
||||
"description": "Id of pseudowire to create."
|
||||
},
|
||||
"cP1": {
|
||||
"type": "string",
|
||||
"example": "of:0000000000000227/25",
|
||||
"description": "Pseudowire connection point 1."
|
||||
},
|
||||
"cP2": {
|
||||
"type": "string",
|
||||
"example": "of:0000000000000226/25",
|
||||
"description": "Pseudowire connection point 2."
|
||||
},
|
||||
"cP1InnerTag": {
|
||||
"type": "string",
|
||||
"example": "101",
|
||||
"description": "Inner vlan for pseudowire connection point 1."
|
||||
},
|
||||
"cP1OuterTag": {
|
||||
"type": "string",
|
||||
"example": "",
|
||||
"description": "Outer vlan for pseudowire connection point 1."
|
||||
},
|
||||
"cP2InnerTag": {
|
||||
"type": "string",
|
||||
"example": "101",
|
||||
"description": "Inner vlan for pseudowire connection point 2."
|
||||
},
|
||||
"cP2OuterTag": {
|
||||
"type": "string",
|
||||
"example": "",
|
||||
"description": "Outer vlan for pseudowire connection point 2."
|
||||
},
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"example": "RAW",
|
||||
"description": "Working mode of pseudowire."
|
||||
},
|
||||
"sDTag": {
|
||||
"type": "string",
|
||||
"example": "",
|
||||
"description": "Service delimiting tag of the pseudowire"
|
||||
},
|
||||
"pwLabel": {
|
||||
"type": "256",
|
||||
"example": "",
|
||||
"description": "Pseudowire label."
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"type": "object",
|
||||
"title": "pseudowire-deletion",
|
||||
"required": [
|
||||
"pwId"
|
||||
],
|
||||
"properties": {
|
||||
"pwId": {
|
||||
"type": "string",
|
||||
"example": "42",
|
||||
"description": "Id of pseudowire to delete."
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,21 +14,38 @@
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://java.sun.com/xml/ns/javaee"
|
||||
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
|
||||
id="ONOS" version="2.5">
|
||||
<display-name>Segment Routing REST API v1.0</display-name>
|
||||
<display-name>Segment Routing Server REST API v1.0</display-name>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<web-resource-name>Secured</web-resource-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>admin</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<security-role>
|
||||
<role-name>admin</role-name>
|
||||
</security-role>
|
||||
|
||||
<login-config>
|
||||
<auth-method>BASIC</auth-method>
|
||||
<realm-name>karaf</realm-name>
|
||||
</login-config>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>JAX-RS Service</servlet-name>
|
||||
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
|
||||
<init-param>
|
||||
<param-name>jersey.config.server.provider.classnames</param-name>
|
||||
<param-value>
|
||||
org.onosproject.segmentrouting.web.TunnelWebResource,
|
||||
org.onosproject.segmentrouting.web.PolicyWebResource
|
||||
</param-value>
|
||||
<param-name>javax.ws.rs.Application</param-name>
|
||||
<param-value>org.onosproject.segmentrouting.web.SegmentRoutingWebApplication</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user