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
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index d951b53..b9912ac 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -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.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.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.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 @@
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 @@
}
};
- 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 @@
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 @@
cfgService.unregisterConfigFactory(appConfigFactory);
cfgService.unregisterConfigFactory(xConnectConfigFactory);
cfgService.unregisterConfigFactory(mcastConfigFactory);
- cfgService.unregisterConfigFactory(pwaasConfigFactory);
compCfgService.unregisterProperties(getClass(), false);
hostService.removeListener(hostListener);
@@ -567,55 +557,90 @@
}
@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 @@
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 @@
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;
}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
index 6f115e4..fa7b7d6 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingService.java
@@ -25,6 +25,7 @@
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 @@
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.
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
index d916823..ab80aff 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireAddCommand.java
@@ -19,8 +19,17 @@
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 @@
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;
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java
index 098bbf9..0f027b2 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/cli/PseudowireRemoveCommand.java
@@ -23,6 +23,8 @@
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 @@
// 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!");
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/config/PwaasConfig.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/config/PwaasConfig.java
deleted file mode 100644
index 31cad7e..0000000
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/config/PwaasConfig.java
+++ /dev/null
@@ -1,671 +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.config;
-
-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;
-
-/**
- * App configuration object for Pwaas.
- */
-public class PwaasConfig extends Config<ApplicationId> {
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- public DeviceService deviceService;
-
- @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
- public InterfaceService intfService;
-
- 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;
- }
-
- 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.
- *
- * 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.
- */
- @Override
- public boolean isValid() {
-
- 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;
- }
- }
-
- /**
- * 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) {
-
- // 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()));
- }
-
- // 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()));
- }
-
- // Raw mode without service delimiting tag
- // is the only mode supported for now.
- }
-
- /**
- * Helper method to verify if the policy is whether or not
- * supported and if policy will be successfully instantiated in the
- * network.
- *
- * @param ingressInner the ingress inner tag
- * @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,
- ConnectPoint cP2,
- VlanId ingressInner,
- VlanId ingressOuter,
- VlanId egressInner,
- VlanId egressOuter,
- Long tunnelId) {
-
- 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));
- }
-
- // We can have multiple tags, all of them can be NONE,
- // indicating untagged traffic, however, the outer tag can
- // 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));
- }
-
- 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)));
- }
-
- if (ingressInner.equals(VlanId.ANY) ||
- ingressOuter.equals(VlanId.ANY) ||
- egressInner.equals(VlanId.ANY) ||
- egressOuter.equals(VlanId.ANY)) {
- throw new IllegalArgumentException(String.valueOf(String.format("Wildcard VLAN matching not yet " +
- "supported for pseudowire %d.",
- tunnelId)));
- }
-
- if (((!ingressOuter.equals(VlanId.NONE) && !ingressInner.equals(VlanId.NONE)) &&
- (egressOuter.equals(VlanId.NONE) && egressInner.equals(VlanId.NONE)))
- || ((ingressOuter.equals(VlanId.NONE) && ingressInner.equals(VlanId.NONE)) &&
- (!egressOuter.equals(VlanId.NONE) && !egressInner.equals(VlanId.NONE)))) {
- throw new IllegalArgumentException(String.valueOf(String.format("Support for double tag <-> untag is not" +
- "supported for pseudowire %d.",
- tunnelId)));
- }
- if ((!ingressInner.equals(VlanId.NONE) &&
- ingressOuter.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)));
- }
-
- 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)));
- }
-
-
- 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)));
- }
-
- // 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(),
- 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(),
- 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(),
- 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.",
- cP2.port(), cP2.deviceId(), tunnelId)));
- }
- }
-
- /**
- * Verifies that the pseudowires will not conflict with each other.
- *
- * Further, check if vlans for connect points are already used.
- *
- * @param tunnel Tunnel for pw
- * @param policy Policy for pw
- * @param labelSet Label set used so far with this configuration
- * @param vlanSet Vlan set used with this configuration
- * @param tunnelSet Tunnel set used with this configuration
- */
- private void verifyGlobalValidity(L2Tunnel tunnel,
- L2TunnelPolicy policy,
- Set<MplsLabel> labelSet,
- Map<ConnectPoint, Set<VlanId>> vlanSet,
- Set<Long> tunnelSet) {
-
- 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(),
- tunnel.tunnelId())));
- }
- tunnelSet.add(tunnel.tunnelId());
-
- // check if tunnel id is used again
- ConnectPoint cP1 = policy.cP1();
- ConnectPoint cP2 = policy.cP2();
-
- // insert cps to hashmap if this is the first time seen
- if (!vlanSet.containsKey(cP1)) {
- vlanSet.put(cP1, new HashSet<VlanId>());
- }
- if (!vlanSet.containsKey(cP2)) {
- vlanSet.put(cP2, new HashSet<VlanId>());
- }
-
- // if single tagged or untagged vlan is the inner
- // if double tagged vlan is the outer
- VlanId vlanToCheckCP1;
- if (policy.cP1OuterTag().equals(VlanId.NONE)) {
- vlanToCheckCP1 = policy.cP1InnerTag();
- } else {
- vlanToCheckCP1 = policy.cP1OuterTag();
- }
-
- VlanId vlanToCheckCP2;
- if (policy.cP2OuterTag().equals(VlanId.NONE)) {
- vlanToCheckCP2 = policy.cP2InnerTag();
- } else {
- vlanToCheckCP2 = policy.cP2OuterTag();
- }
-
- if (labelSet.contains(tunnel.pwLabel())) {
- throw new IllegalArgumentException(String.valueOf(String.format("Label %s already used by another" +
- " 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,
- 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,
- tunnel.tunnelId())));
- }
- vlanSet.get(cP2).add(vlanToCheckCP2);
-
- // check that vlans for the connect points are not used
- intfService.getInterfacesByPort(cP1).stream()
- .forEach(intf -> {
-
- // 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!",
- vlanToCheckCP1, cP1,
- tunnel.tunnelId())));
- }
-
- // if vlanNative != null this interface is configured with untagged traffic also
- // 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())));
- }
-
- // 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())));
- }
- });
-
- 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!",
- vlanToCheckCP2, cP2,
- tunnel.tunnelId())));
- }
-
- // 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!",
- cP2, tunnel.tunnelId())));
- }
-
- // if vlanUntagged != null this interface is configured only with untagged traffic
- // 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!",
- cP2, tunnel.tunnelId())));
- }
- });
-
- }
-
- /**
- * 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,
- Set<MplsLabel> labelSet,
- Map<ConnectPoint, Set<VlanId>> vlanset,
- Set<Long> tunnelSet) {
-
- L2Tunnel l2Tunnel = l2TunnelDescription.l2Tunnel();
- L2TunnelPolicy l2TunnelPolicy = l2TunnelDescription.l2TunnelPolicy();
-
- verifyTunnel(l2Tunnel);
-
- verifyPolicy(
- l2TunnelPolicy.cP1(),
- l2TunnelPolicy.cP2(),
- l2TunnelPolicy.cP1InnerTag(),
- l2TunnelPolicy.cP1OuterTag(),
- l2TunnelPolicy.cP2InnerTag(),
- l2TunnelPolicy.cP2OuterTag(),
- l2Tunnel.tunnelId()
- );
-
- verifyGlobalValidity(l2Tunnel,
- l2TunnelPolicy,
- labelSet,
- vlanset,
- tunnelSet);
-
- }
-
- /**
- * 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) {
-
- // structures to keep pw information
- // in order to see if instantiating them will create
- // problems
- Set<Long> tunIds = new HashSet<>();
- 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);
- }
-
- 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;
- }
-}
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
index 2dc9de2..4b3272d 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
@@ -30,7 +30,6 @@
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.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.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 @@
}
/**
- * 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 @@
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 @@
}
/**
- * 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 @@
/**
* 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 @@
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 @@
}
}
-
- @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 @@
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 @@
});
}
- @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 @@
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);
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
index 044ad41..5fce137 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
@@ -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;
@@ -48,27 +47,6 @@
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>
* This method should for the mastership of the device because it is
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
new file mode 100644
index 0000000..fa2807e
--- /dev/null
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/PwaasUtil.java
@@ -0,0 +1,478 @@
+/*
+ * 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.pwaas;
+
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.intf.InterfaceService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class with static methods that help
+ * parse pseudowire related information and also
+ * verify that a pseudowire combination is valid.
+ */
+public final class PwaasUtil {
+
+ private static final Logger log = LoggerFactory.getLogger(PwaasUtil.class);
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ public static DeviceService deviceService = AbstractShellCommand.get(DeviceService.class);;
+
+ @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+ public static InterfaceService intfService = AbstractShellCommand.get(InterfaceService.class);
+
+ private PwaasUtil() {
+ return;
+ }
+
+ /**
+ * 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 null if error
+ */
+ public static 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) {
+ 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
+ */
+ 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()));
+ }
+
+ // 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()));
+ }
+
+ // Raw mode without service delimiting tag
+ // is the only mode supported for now.
+ }
+
+ /**
+ * Helper method to verify if the policy is whether or not
+ * supported and if policy will be successfully instantiated in the
+ * network.
+ *
+ * @param ingressInner the ingress inner tag
+ * @param ingressOuter the ingress outer tag
+ * @param egressInner the egress inner tag
+ * @param egressOuter the egress outer tag
+ */
+ private static void verifyPolicy(ConnectPoint cP1,
+ ConnectPoint cP2,
+ VlanId ingressInner,
+ VlanId ingressOuter,
+ VlanId egressInner,
+ VlanId egressOuter,
+ Long tunnelId) {
+
+ 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));
+ }
+
+ // We can have multiple tags, all of them can be NONE,
+ // indicating untagged traffic, however, the outer tag can
+ // 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));
+ }
+
+ 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)));
+ }
+
+ if (ingressInner.equals(VlanId.ANY) ||
+ ingressOuter.equals(VlanId.ANY) ||
+ egressInner.equals(VlanId.ANY) ||
+ egressOuter.equals(VlanId.ANY)) {
+ throw new IllegalArgumentException(String.valueOf(String.format("Wildcard VLAN matching not yet " +
+ "supported for pseudowire %d.",
+ tunnelId)));
+ }
+
+ if (((!ingressOuter.equals(VlanId.NONE) && !ingressInner.equals(VlanId.NONE)) &&
+ (egressOuter.equals(VlanId.NONE) && egressInner.equals(VlanId.NONE)))
+ || ((ingressOuter.equals(VlanId.NONE) && ingressInner.equals(VlanId.NONE)) &&
+ (!egressOuter.equals(VlanId.NONE) && !egressInner.equals(VlanId.NONE)))) {
+ throw new IllegalArgumentException(String.valueOf(String.format("Support for double tag <-> untag is not" +
+ "supported for pseudowire %d.",
+ tunnelId)));
+ }
+ if ((!ingressInner.equals(VlanId.NONE) &&
+ ingressOuter.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)));
+ }
+
+ 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)));
+ }
+
+
+ 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)));
+ }
+
+ // 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(),
+ 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(),
+ 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(),
+ 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.",
+ cP2.port(), cP2.deviceId(), tunnelId)));
+ }
+ }
+
+ /**
+ * Verifies that the pseudowires will not conflict with each other.
+ *
+ * Further, check if vlans for connect points are already used.
+ *
+ * @param tunnel Tunnel for pw
+ * @param policy Policy for pw
+ * @param labelSet Label set used so far with this configuration
+ * @param vlanSet Vlan set used with this configuration
+ * @param tunnelSet Tunnel set used with this configuration
+ */
+ private static void verifyGlobalValidity(L2Tunnel tunnel,
+ L2TunnelPolicy policy,
+ Set<MplsLabel> labelSet,
+ Map<ConnectPoint, Set<VlanId>> vlanSet,
+ Set<Long> tunnelSet) {
+
+ 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(),
+ tunnel.tunnelId())));
+ }
+ tunnelSet.add(tunnel.tunnelId());
+
+ // check if tunnel id is used again
+ ConnectPoint cP1 = policy.cP1();
+ ConnectPoint cP2 = policy.cP2();
+
+ // insert cps to hashmap if this is the first time seen
+ if (!vlanSet.containsKey(cP1)) {
+ vlanSet.put(cP1, new HashSet<VlanId>());
+ }
+ if (!vlanSet.containsKey(cP2)) {
+ vlanSet.put(cP2, new HashSet<VlanId>());
+ }
+
+ // if single tagged or untagged vlan is the inner
+ // if double tagged vlan is the outer
+ VlanId vlanToCheckCP1;
+ if (policy.cP1OuterTag().equals(VlanId.NONE)) {
+ vlanToCheckCP1 = policy.cP1InnerTag();
+ } else {
+ vlanToCheckCP1 = policy.cP1OuterTag();
+ }
+
+ VlanId vlanToCheckCP2;
+ if (policy.cP2OuterTag().equals(VlanId.NONE)) {
+ vlanToCheckCP2 = policy.cP2InnerTag();
+ } else {
+ vlanToCheckCP2 = policy.cP2OuterTag();
+ }
+
+ if (labelSet.contains(tunnel.pwLabel())) {
+ throw new IllegalArgumentException(String.valueOf(String.format("Label %s already used by another" +
+ " 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,
+ 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,
+ tunnel.tunnelId())));
+ }
+ vlanSet.get(cP2).add(vlanToCheckCP2);
+
+ // check that vlans for the connect points are not used
+ intfService.getInterfacesByPort(cP1).stream()
+ .forEach(intf -> {
+
+ // 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!",
+ vlanToCheckCP1, cP1,
+ tunnel.tunnelId())));
+ }
+
+ // if vlanNative != null this interface is configured with untagged traffic also
+ // 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())));
+ }
+
+ // 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())));
+ }
+ });
+
+ intfService.getInterfacesByPort(cP2).stream()
+ .forEach(intf -> {
+ if (intf.vlanTagged().contains(vlanToCheckCP2)) {
+ throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP2 %s " +
+ " used for " +
+ "this interface, " +
+ "in pseudowire %d!",
+ vlanToCheckCP2, cP2,
+ tunnel.tunnelId())));
+ }
+
+ // 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!",
+ cP2, tunnel.tunnelId())));
+ }
+
+ // if vlanUntagged != null this interface is configured only with untagged traffic
+ // 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!",
+ cP2, tunnel.tunnelId())));
+ }
+ });
+
+ }
+
+ /**
+ * Helper method to verify the integrity of the pseudo wire.
+ *
+ * @param l2TunnelDescription the pseudo wire description
+ */
+ private static void verifyPseudoWire(L2TunnelDescription l2TunnelDescription,
+ Set<MplsLabel> labelSet,
+ Map<ConnectPoint, Set<VlanId>> vlanset,
+ Set<Long> tunnelSet) {
+
+ L2Tunnel l2Tunnel = l2TunnelDescription.l2Tunnel();
+ L2TunnelPolicy l2TunnelPolicy = l2TunnelDescription.l2TunnelPolicy();
+
+ verifyTunnel(l2Tunnel);
+
+ verifyPolicy(
+ l2TunnelPolicy.cP1(),
+ l2TunnelPolicy.cP2(),
+ l2TunnelPolicy.cP1InnerTag(),
+ l2TunnelPolicy.cP1OuterTag(),
+ l2TunnelPolicy.cP2InnerTag(),
+ l2TunnelPolicy.cP2OuterTag(),
+ l2Tunnel.tunnelId()
+ );
+
+ verifyGlobalValidity(l2Tunnel,
+ l2TunnelPolicy,
+ labelSet,
+ vlanset,
+ tunnelSet);
+
+ }
+
+ public static boolean configurationValidity(Set<L2TunnelDescription> pseudowires) {
+
+ // structures to keep pw information
+ // in order to see if instantiating them will create
+ // problems
+ Set<Long> tunIds = new HashSet<>();
+ Set<MplsLabel> labelsUsed = new HashSet<>();
+ Map<ConnectPoint, Set<VlanId>> vlanIds = new HashMap<>();
+
+ // 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;
+ }
+
+}