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:
Andreas Pantelopoulos 2018-02-23 14:18:00 -08:00 committed by Ray Milkey
parent a9ae6e662c
commit cd3395992d
18 changed files with 767 additions and 1023 deletions

View File

@ -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;
}

View File

@ -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.

View File

@ -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;

View File

@ -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!");

View File

@ -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);

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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) {
}
}
}

View File

@ -15,6 +15,6 @@
*/
/**
* Segment routing application components.
* Segment routing REST implementation.
*/
package org.onosproject.segmentrouting.web;

View File

@ -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();

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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);
}
}

View File

@ -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();

View File

@ -15,6 +15,6 @@
*/
/**
* Set of resources implementing the segment routing application REST API.
* Segment routing application components.
*/
package org.onosproject.segmentrouting.web;

View File

@ -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."
}
}
}

View File

@ -0,0 +1,14 @@
{
"type": "object",
"title": "pseudowire-deletion",
"required": [
"pwId"
],
"properties": {
"pwId": {
"type": "string",
"example": "42",
"description": "Id of pseudowire to delete."
}
}
}

View File

@ -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>