blob: 31cad7e3dd963882a3aebc8edab4094c87f9d45a [file] [log] [blame]
Pier Ventre6b19e482016-11-07 16:21:04 -08001/*
Brian O'Connor0947d7e2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Pier Ventre6b19e482016-11-07 16:21:04 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.segmentrouting.config;
18
19import com.fasterxml.jackson.databind.JsonNode;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070020import com.fasterxml.jackson.databind.node.JsonNodeFactory;
Pier Ventre6b19e482016-11-07 16:21:04 -080021import com.fasterxml.jackson.databind.node.ObjectNode;
22import com.google.common.collect.ImmutableSet;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070023import org.apache.felix.scr.annotations.Reference;
24import org.apache.felix.scr.annotations.ReferenceCardinality;
Pier Ventre6b19e482016-11-07 16:21:04 -080025import org.onlab.packet.MplsLabel;
26import org.onlab.packet.VlanId;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070027import org.onosproject.cli.AbstractShellCommand;
Pier Ventre6b19e482016-11-07 16:21:04 -080028import org.onosproject.core.ApplicationId;
29import org.onosproject.net.ConnectPoint;
30import org.onosproject.net.config.Config;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070031import org.onosproject.net.device.DeviceService;
32import org.onosproject.net.intf.InterfaceService;
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -080033import org.onosproject.segmentrouting.pwaas.L2Tunnel;
34import org.onosproject.segmentrouting.pwaas.L2TunnelDescription;
35import org.onosproject.segmentrouting.pwaas.L2TunnelPolicy;
Pier Ventre6b19e482016-11-07 16:21:04 -080036import org.onosproject.segmentrouting.pwaas.DefaultL2Tunnel;
37import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelDescription;
38import org.onosproject.segmentrouting.pwaas.DefaultL2TunnelPolicy;
39import org.onosproject.segmentrouting.pwaas.L2Mode;
40import org.slf4j.Logger;
41import org.slf4j.LoggerFactory;
42
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070043import java.util.HashMap;
44import java.util.HashSet;
45import java.util.Map;
Pier Ventre6b19e482016-11-07 16:21:04 -080046import java.util.Set;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070047import java.util.stream.Collectors;
Pier Ventre6b19e482016-11-07 16:21:04 -080048
49/**
50 * App configuration object for Pwaas.
51 */
52public class PwaasConfig extends Config<ApplicationId> {
53
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070054 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
55 public DeviceService deviceService;
56
57 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
58 public InterfaceService intfService;
59
Pier Ventre6b19e482016-11-07 16:21:04 -080060 private static Logger log = LoggerFactory
61 .getLogger(PwaasConfig.class);
62
63 private static final String SRC_CP = "cP1";
64 private static final String DST_CP = "cP2";
65 private static final String SRC_OUTER_TAG = "cP1OuterTag";
66 private static final String DST_OUTER_TAG = "cP2OuterTag";
67 private static final String SRC_INNER_TAG = "cP1InnerTag";
68 private static final String DST_INNER_TAG = "cP2InnerTag";
69 private static final String MODE = "mode";
Pier Ventre6b19e482016-11-07 16:21:04 -080070 private static final String SD_TAG = "sdTag";
71 private static final String PW_LABEL = "pwLabel";
72
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070073 public PwaasConfig(DeviceService devS, InterfaceService intfS) {
74
75 super();
76
77 deviceService = devS;
78 intfService = intfS;
79 }
80
81 public PwaasConfig() {
82
83 super();
84
85 deviceService = AbstractShellCommand.get(DeviceService.class);
86 intfService = AbstractShellCommand.get(InterfaceService.class);
87 }
Pier Ventre6b19e482016-11-07 16:21:04 -080088 /**
89 * Error message for missing parameters.
90 */
91 private static final String MISSING_PARAMS = "Missing parameters in pseudo wire description";
92
93 /**
94 * Error message for invalid l2 mode.
95 */
96 private static final String INVALID_L2_MODE = "Invalid pseudo wire mode";
97
98 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070099 * Error message for invalid VLAN.
100 */
101 private static final String INVALID_VLAN = "Vlan should be either int or */-";
102
103 /**
104 * Error message for invalid PW label.
105 */
106 private static final String INVALID_PW_LABEL = "Pseudowire label should be an integer";
107
108 /**
Pier Ventre6b19e482016-11-07 16:21:04 -0800109 * Verify if the pwaas configuration block is valid.
110 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700111 * Here we try to ensure that the provided pseudowires will get instantiated
112 * correctly in the network. We also check for any collisions with already used
113 * interfaces and also between different pseudowires. Most of the restrictions stem
114 * from the fact that all vlan matching is done in table 10 of ofdpa.
115 *
Pier Ventre6b19e482016-11-07 16:21:04 -0800116 * @return true, if the configuration block is valid.
117 * False otherwise.
118 */
119 @Override
120 public boolean isValid() {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700121
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800122 Set<L2TunnelDescription> pseudowires;
Pier Ventre6b19e482016-11-07 16:21:04 -0800123 try {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700124 pseudowires = getPwIds().stream()
125 .map(this::getPwDescription)
126 .collect(Collectors.toSet());
127
Andreas Pantelopoulosb3e45a32018-01-16 11:51:32 -0800128 // check semantics now and return
129 return configurationValidity(pseudowires);
130
Pier Ventre6b19e482016-11-07 16:21:04 -0800131 } catch (IllegalArgumentException e) {
132 log.warn("{}", e.getMessage());
133 return false;
134 }
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700135 }
136
137 /**
138 * Helper method to verify if the tunnel is whether or not
139 * supported.
140 *
141 * @param l2Tunnel the tunnel to verify
142 * @return the result of the verification
143 */
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800144 private void verifyTunnel(L2Tunnel l2Tunnel) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700145
146 // Service delimiting tag not supported yet.
147 if (!l2Tunnel.sdTag().equals(VlanId.NONE)) {
148 throw new IllegalArgumentException(String.format("Service delimiting tag not supported yet for " +
149 "pseudowire %d.", l2Tunnel.tunnelId()));
150 }
151
152 // Tag mode not supported yet.
153 if (l2Tunnel.pwMode() == L2Mode.TAGGED) {
154 throw new IllegalArgumentException(String.format("Tagged mode not supported yet for pseudowire %d.",
155 l2Tunnel.tunnelId()));
156 }
157
158 // Raw mode without service delimiting tag
159 // is the only mode supported for now.
160 }
161
162 /**
163 * Helper method to verify if the policy is whether or not
164 * supported and if policy will be successfully instantiated in the
165 * network.
166 *
167 * @param ingressInner the ingress inner tag
168 * @param ingressOuter the ingress outer tag
169 * @param egressInner the egress inner tag
170 * @param egressOuter the egress outer tag
171 * @return the result of verification
172 */
173 private void verifyPolicy(ConnectPoint cP1,
174 ConnectPoint cP2,
175 VlanId ingressInner,
176 VlanId ingressOuter,
177 VlanId egressInner,
178 VlanId egressOuter,
179 Long tunnelId) {
180
181 if (cP1.deviceId().equals(cP2.deviceId())) {
182 throw new IllegalArgumentException(String.format("Pseudowire connection points can not reside in the " +
183 "same node, in pseudowire %d.", tunnelId));
184 }
185
186 // We can have multiple tags, all of them can be NONE,
187 // indicating untagged traffic, however, the outer tag can
188 // not have value if the inner tag is None
189 if (ingressInner.equals(VlanId.NONE) && !ingressOuter.equals(VlanId.NONE)) {
190 throw new IllegalArgumentException(String.format("Inner tag should not be empty when " +
191 "outer tag is set for pseudowire %d for cP1.",
192 tunnelId));
193 }
194
195 if (egressInner.equals(VlanId.NONE) && !egressOuter.equals(VlanId.NONE)) {
196 throw new IllegalArgumentException(String.valueOf(String.format("Inner tag should not be empty when" +
197 " outer tag is set for pseudowire %d " +
198 "for cP2.", tunnelId)));
199 }
200
201 if (ingressInner.equals(VlanId.ANY) ||
202 ingressOuter.equals(VlanId.ANY) ||
203 egressInner.equals(VlanId.ANY) ||
204 egressOuter.equals(VlanId.ANY)) {
205 throw new IllegalArgumentException(String.valueOf(String.format("Wildcard VLAN matching not yet " +
206 "supported for pseudowire %d.",
207 tunnelId)));
208 }
209
Yuta HIGUCHI6f31b3c2018-01-24 23:39:06 -0800210 if (((!ingressOuter.equals(VlanId.NONE) && !ingressInner.equals(VlanId.NONE)) &&
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700211 (egressOuter.equals(VlanId.NONE) && egressInner.equals(VlanId.NONE)))
Yuta HIGUCHI6f31b3c2018-01-24 23:39:06 -0800212 || ((ingressOuter.equals(VlanId.NONE) && ingressInner.equals(VlanId.NONE)) &&
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700213 (!egressOuter.equals(VlanId.NONE) && !egressInner.equals(VlanId.NONE)))) {
214 throw new IllegalArgumentException(String.valueOf(String.format("Support for double tag <-> untag is not" +
215 "supported for pseudowire %d.",
216 tunnelId)));
217 }
218 if ((!ingressInner.equals(VlanId.NONE) &&
219 ingressOuter.equals(VlanId.NONE) &&
220 !egressOuter.equals(VlanId.NONE))
Ray Milkey9b80fba2018-02-01 17:40:39 -0800221 || (egressOuter.equals(VlanId.NONE) &&
222 !egressInner.equals(VlanId.NONE) &&
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700223 !ingressOuter.equals(VlanId.NONE))) {
224 throw new IllegalArgumentException(String.valueOf(String.format("Support for double-tag<->" +
225 "single-tag is not supported" +
226 " for pseudowire %d.", tunnelId)));
227 }
228
229 if ((ingressInner.equals(VlanId.NONE) && !egressInner.equals(VlanId.NONE))
230 || (!ingressInner.equals(VlanId.NONE) && egressInner.equals(VlanId.NONE))) {
231 throw new IllegalArgumentException(String.valueOf(String.format("single-tag <-> untag is not supported" +
232 " for pseudowire %d.", tunnelId)));
233 }
234
235
236 if (!ingressInner.equals(egressInner) && !ingressOuter.equals(egressOuter)) {
237 throw new IllegalArgumentException(String.valueOf(String.format("We do not support changing both tags " +
238 "in double tagged pws, only the outer," +
239 " for pseudowire %d.", tunnelId)));
240 }
241
242 // check if cp1 and port of cp1 exist
243 if (deviceService.getDevice(cP1.deviceId()) == null) {
244 throw new IllegalArgumentException(String.valueOf(String.format("cP1 device %s does not exist for" +
245 " pseudowire %d.", cP1.deviceId(),
246 tunnelId)));
247 }
248
249 if (deviceService.getPort(cP1) == null) {
250 throw new IllegalArgumentException(String.valueOf(String.format("Port %s for cP1 device %s does not" +
251 " exist for pseudowire %d.", cP1.port(),
252 cP1.deviceId(), tunnelId)));
253 }
254
255 // check if cp2 and port of cp2 exist
256 if (deviceService.getDevice(cP2.deviceId()) == null) {
257 throw new IllegalArgumentException(String.valueOf(String.format("cP2 device %s does not exist for" +
258 " pseudowire %d.", cP2.deviceId(),
259 tunnelId)));
260 }
261
262 if (deviceService.getPort(cP2) == null) {
263 throw new IllegalArgumentException(String.valueOf(String.format("Port %s for cP2 device %s does " +
264 "not exist for pseudowire %d.",
265 cP2.port(), cP2.deviceId(), tunnelId)));
266 }
267 }
268
269 /**
270 * Verifies that the pseudowires will not conflict with each other.
271 *
272 * Further, check if vlans for connect points are already used.
273 *
274 * @param tunnel Tunnel for pw
275 * @param policy Policy for pw
276 * @param labelSet Label set used so far with this configuration
277 * @param vlanSet Vlan set used with this configuration
278 * @param tunnelSet Tunnel set used with this configuration
279 */
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800280 private void verifyGlobalValidity(L2Tunnel tunnel,
281 L2TunnelPolicy policy,
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700282 Set<MplsLabel> labelSet,
283 Map<ConnectPoint, Set<VlanId>> vlanSet,
284 Set<Long> tunnelSet) {
285
286 if (tunnelSet.contains(tunnel.tunnelId())) {
287 throw new IllegalArgumentException(String.valueOf(String.format("Tunnel Id %d already used by" +
288 " another pseudowire, in " +
289 "pseudowire %d!", tunnel.tunnelId(),
290 tunnel.tunnelId())));
291 }
292 tunnelSet.add(tunnel.tunnelId());
293
294 // check if tunnel id is used again
295 ConnectPoint cP1 = policy.cP1();
296 ConnectPoint cP2 = policy.cP2();
297
298 // insert cps to hashmap if this is the first time seen
299 if (!vlanSet.containsKey(cP1)) {
300 vlanSet.put(cP1, new HashSet<VlanId>());
301 }
302 if (!vlanSet.containsKey(cP2)) {
303 vlanSet.put(cP2, new HashSet<VlanId>());
304 }
305
306 // if single tagged or untagged vlan is the inner
307 // if double tagged vlan is the outer
308 VlanId vlanToCheckCP1;
309 if (policy.cP1OuterTag().equals(VlanId.NONE)) {
310 vlanToCheckCP1 = policy.cP1InnerTag();
311 } else {
312 vlanToCheckCP1 = policy.cP1OuterTag();
313 }
314
315 VlanId vlanToCheckCP2;
316 if (policy.cP2OuterTag().equals(VlanId.NONE)) {
317 vlanToCheckCP2 = policy.cP2InnerTag();
318 } else {
319 vlanToCheckCP2 = policy.cP2OuterTag();
320 }
321
322 if (labelSet.contains(tunnel.pwLabel())) {
323 throw new IllegalArgumentException(String.valueOf(String.format("Label %s already used by another" +
324 " pseudowire, in pseudowire %d!",
325 tunnel.pwLabel(), tunnel.tunnelId())));
326 }
327 labelSet.add(tunnel.pwLabel());
328
329 if (vlanSet.get(cP1).contains(vlanToCheckCP1)) {
330 throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP1 %s already used " +
331 "by another pseudowire, in pseudowire" +
332 " %d!", vlanToCheckCP1, cP1,
333 tunnel.tunnelId())));
334 }
335 vlanSet.get(cP1).add(vlanToCheckCP1);
336
337 if (vlanSet.get(cP2).contains(vlanToCheckCP2)) {
338 throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP2 %s already used" +
339 " by another pseudowire, in" +
340 " pseudowire %d!", vlanToCheckCP2, cP2,
341 tunnel.tunnelId())));
342 }
343 vlanSet.get(cP2).add(vlanToCheckCP2);
344
345 // check that vlans for the connect points are not used
346 intfService.getInterfacesByPort(cP1).stream()
347 .forEach(intf -> {
348
349 // check if tagged pw affects tagged interface
350 if (intf.vlanTagged().contains(vlanToCheckCP1)) {
351 throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP1 %s already" +
352 " used for this interface, in" +
353 " pseudowire %d!",
354 vlanToCheckCP1, cP1,
355 tunnel.tunnelId())));
356 }
357
358 // if vlanNative != null this interface is configured with untagged traffic also
359 // check if it collides with untagged interface
360 if ((intf.vlanNative() != null) && vlanToCheckCP1.equals(VlanId.NONE)) {
361 throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for cP1 " +
362 "%s already used for this " +
363 "interface, in pseudowire " +
364 "%d!", cP1,
365 tunnel.tunnelId())));
366 }
367
368 // if vlanUntagged != null this interface is configured only with untagged traffic
369 // check if it collides with untagged interface
370 if ((intf.vlanUntagged() != null) && vlanToCheckCP1.equals(VlanId.NONE)) {
371 throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for " +
372 "cP1 %s already" +
373 " used for this interface," +
374 " in pseudowire %d!",
375 cP1, tunnel.tunnelId())));
376 }
377 });
378
379 intfService.getInterfacesByPort(cP2).stream()
380 .forEach(intf -> {
381 if (intf.vlanTagged().contains(vlanToCheckCP2)) {
382 throw new IllegalArgumentException(String.valueOf(String.format("Vlan '%s' for cP2 %s already" +
383 " used for this interface, " +
384 "in pseudowire %d!",
385 vlanToCheckCP2, cP2,
386 tunnel.tunnelId())));
387 }
388
389 // if vlanNative != null this interface is configured with untagged traffic also
390 // check if it collides with untagged interface
391 if ((intf.vlanNative() != null) && vlanToCheckCP2.equals(VlanId.NONE)) {
392 throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for cP2 %s " +
393 "already used for this" +
394 " interface, " +
395 "in pseudowire %d!",
396 cP2, tunnel.tunnelId())));
397 }
398
399 // if vlanUntagged != null this interface is configured only with untagged traffic
400 // check if it collides with untagged interface
401 if ((intf.vlanUntagged() != null) && vlanToCheckCP2.equals(VlanId.NONE)) {
402 throw new IllegalArgumentException(String.valueOf(String.format("Untagged traffic for cP2 %s" +
403 " already" +
404 " used for this interface, " +
405 "in pseudowire %d!",
406 cP2, tunnel.tunnelId())));
407 }
408 });
409
410 }
411
412 /**
413 * Helper method to verify the integrity of the pseudo wire.
414 *
415 * @param l2TunnelDescription the pseudo wire description
416 * @return the result of the check
417 */
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800418 private void verifyPseudoWire(L2TunnelDescription l2TunnelDescription,
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700419 Set<MplsLabel> labelSet,
420 Map<ConnectPoint, Set<VlanId>> vlanset,
421 Set<Long> tunnelSet) {
422
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800423 L2Tunnel l2Tunnel = l2TunnelDescription.l2Tunnel();
424 L2TunnelPolicy l2TunnelPolicy = l2TunnelDescription.l2TunnelPolicy();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700425
426 verifyTunnel(l2Tunnel);
427
428 verifyPolicy(
429 l2TunnelPolicy.cP1(),
430 l2TunnelPolicy.cP2(),
431 l2TunnelPolicy.cP1InnerTag(),
432 l2TunnelPolicy.cP1OuterTag(),
433 l2TunnelPolicy.cP2InnerTag(),
434 l2TunnelPolicy.cP2OuterTag(),
435 l2Tunnel.tunnelId()
436 );
437
438 verifyGlobalValidity(l2Tunnel,
439 l2TunnelPolicy,
440 labelSet,
441 vlanset,
442 tunnelSet);
443
444 }
445
446 /**
447 * Checks if the configured pseudowires will create problems in the network.
448 * If yes, then no pseudowires is deployed from this configuration.
449 *
450 * @param pseudowires Set of pseudowries to validate
451 * @return returns true if everything goes well.
452 */
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800453 public boolean configurationValidity(Set<L2TunnelDescription> pseudowires) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700454
455 // structures to keep pw information
456 // in order to see if instantiating them will create
457 // problems
458 Set<Long> tunIds = new HashSet<>();
459 Set<MplsLabel> labelsUsed = new HashSet<>();
460 Map<ConnectPoint, Set<VlanId>> vlanIds = new HashMap<>();
461
462 // check that pseudowires can be instantiated in the network
463 // we try to guarantee that all the pws will work before
464 // instantiating any of them
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800465 for (L2TunnelDescription pw : pseudowires) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700466 verifyPseudoWire(pw, labelsUsed, vlanIds, tunIds);
467 }
468
469 return true;
Pier Ventre6b19e482016-11-07 16:21:04 -0800470 }
471
472 /**
473 * Returns all pseudo wire keys.
474 *
475 * @return all keys (tunnels id)
476 * @throws IllegalArgumentException if wrong format
477 */
478 public Set<Long> getPwIds() {
479 ImmutableSet.Builder<Long> builder = ImmutableSet.builder();
480 object.fields().forEachRemaining(entry -> {
481 Long tunnelId = Long.parseLong(entry.getKey());
482 builder.add(tunnelId);
483 });
484 return builder.build();
485 }
486
487 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700488 * Parses a vlan as a string. Returns the VlanId if
489 * provided String can be parsed as an integer or is '' / '*'
490 *
491 * @param vlan string as read from configuration
492 * @return VlanId
493 * @throws IllegalArgumentException if wrong format of vlan
494 */
495 public VlanId parseVlan(String vlan) {
496
497 if (vlan.equals("*") || vlan.equals("Any")) {
498 return VlanId.vlanId("Any");
499 } else if (vlan.equals("") || vlan.equals("None")) {
500 return VlanId.vlanId("None");
501 } else {
502 try {
503 VlanId newVlan = VlanId.vlanId(vlan);
504 return newVlan;
505 } catch (IllegalArgumentException e) {
506 throw new IllegalArgumentException(INVALID_VLAN);
507 }
508 }
509 }
510
511 /**
512 *
513 * @param mode RAW or TAGGED
514 * @return the L2Mode if input is correct
515 * @throws IllegalArgumentException if not supported mode
516 */
517 public L2Mode parseMode(String mode) {
518
519 if (!mode.equals("RAW") && !mode.equals("TAGGED")) {
520 throw new IllegalArgumentException(INVALID_L2_MODE);
521 }
522
523 return L2Mode.valueOf(mode);
524 }
525
526 /**
527 *
528 * @param label the mpls label of the pseudowire
529 * @return the MplsLabel
530 * @throws IllegalArgumentException if label is invalid
531 */
532 public MplsLabel parsePWLabel(String label) {
533
534 try {
535 MplsLabel pwLabel = MplsLabel.mplsLabel(label);
536 return pwLabel;
537 } catch (Exception e) {
538 throw new IllegalArgumentException(INVALID_PW_LABEL);
539 }
540 }
541
542 /**
Pier Ventre6b19e482016-11-07 16:21:04 -0800543 * Returns pw description of given pseudo wire id.
544 *
545 * @param tunnelId pseudo wire key
546 * @return set of l2 tunnel descriptions
547 * @throws IllegalArgumentException if wrong format
548 */
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800549 public L2TunnelDescription getPwDescription(Long tunnelId) {
Pier Ventre6b19e482016-11-07 16:21:04 -0800550 JsonNode pwDescription = object.get(tunnelId.toString());
551 if (!hasFields((ObjectNode) pwDescription,
552 SRC_CP, SRC_INNER_TAG, SRC_OUTER_TAG,
553 DST_CP, DST_INNER_TAG, DST_OUTER_TAG,
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700554 MODE, SD_TAG, PW_LABEL)) {
Pier Ventre6b19e482016-11-07 16:21:04 -0800555 throw new IllegalArgumentException(MISSING_PARAMS);
556 }
557 String tempString;
558
559 tempString = pwDescription.get(SRC_CP).asText();
560 ConnectPoint srcCp = ConnectPoint.deviceConnectPoint(tempString);
561
562 tempString = pwDescription.get(DST_CP).asText();
563 ConnectPoint dstCp = ConnectPoint.deviceConnectPoint(tempString);
564
565 tempString = pwDescription.get(SRC_INNER_TAG).asText();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700566 VlanId srcInnerTag = parseVlan(tempString);
Pier Ventre6b19e482016-11-07 16:21:04 -0800567
568 tempString = pwDescription.get(SRC_OUTER_TAG).asText();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700569 VlanId srcOuterTag = parseVlan(tempString);
Pier Ventre6b19e482016-11-07 16:21:04 -0800570
571 tempString = pwDescription.get(DST_INNER_TAG).asText();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700572 VlanId dstInnerTag = parseVlan(tempString);
Pier Ventre6b19e482016-11-07 16:21:04 -0800573
574 tempString = pwDescription.get(DST_OUTER_TAG).asText();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700575 VlanId dstOuterTag = parseVlan(tempString);
Pier Ventre6b19e482016-11-07 16:21:04 -0800576
577 tempString = pwDescription.get(MODE).asText();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700578 L2Mode l2Mode = parseMode(tempString);
Pier Ventre6b19e482016-11-07 16:21:04 -0800579
580 tempString = pwDescription.get(SD_TAG).asText();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700581 VlanId sdTag = parseVlan(tempString);
Pier Ventre6b19e482016-11-07 16:21:04 -0800582
583 tempString = pwDescription.get(PW_LABEL).asText();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700584 MplsLabel pwLabel = parsePWLabel(tempString);
Pier Ventre6b19e482016-11-07 16:21:04 -0800585
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800586 L2Tunnel l2Tunnel = new DefaultL2Tunnel(
Pier Ventre6b19e482016-11-07 16:21:04 -0800587 l2Mode,
588 sdTag,
589 tunnelId,
590 pwLabel
591 );
592
Andreas Pantelopoulos4c7de132018-02-22 12:32:42 -0800593 L2TunnelPolicy l2TunnelPolicy = new DefaultL2TunnelPolicy(
Pier Ventre6b19e482016-11-07 16:21:04 -0800594 tunnelId,
595 srcCp,
596 srcInnerTag,
597 srcOuterTag,
598 dstCp,
599 dstInnerTag,
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700600 dstOuterTag
Pier Ventre6b19e482016-11-07 16:21:04 -0800601 );
602
603 return new DefaultL2TunnelDescription(l2Tunnel, l2TunnelPolicy);
604 }
605
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700606 /**
607 * Removes a pseudowire from the configuration tree.
608 * @param pwId Pseudowire id
609 * @return null if pwId did not exist, or the object representing the
610 * udpated configuration tree
611 */
612 public ObjectNode removePseudowire(String pwId) {
613
614 JsonNode value = object.remove(pwId);
615 if (value == null) {
616 return (ObjectNode) value;
617 } else {
618 return object;
619 }
620 }
621
622 /**
623 * Adds a pseudowire to the configuration tree of pwwas. It also checks
624 * if the configuration is valid, if not return null and does not add the node,
625 * if yes return the new configuration. Caller will propagate update events.
626 *
627 * If the pseudowire already exists in the configuration it gets updated.
628 *
629 * @param tunnelId Id of tunnel
630 * @param pwLabel PW label of tunnel
631 * @param cP1 Connection point 1
632 * @param cP1InnerVlan Inner vlan of cp1
633 * @param cP1OuterVlan Outer vlan of cp2
634 * @param cP2 Connection point 2
635 * @param cP2InnerVlan Inner vlan of cp2
636 * @param cP2OuterVlan Outer vlan of cp2
637 * @param mode Mode for the pw
638 * @param sdTag Service delimiting tag for the pw
639 * @return The ObjectNode config if configuration is valid with the new pseudowire
640 * or null.
641 */
642 public ObjectNode addPseudowire(String tunnelId, String pwLabel, String cP1,
643 String cP1InnerVlan, String cP1OuterVlan, String cP2,
644 String cP2InnerVlan, String cP2OuterVlan,
645 String mode, String sdTag) {
646
647
648 ObjectNode newPw = new ObjectNode(JsonNodeFactory.instance);
649
650 // add fields for pseudowire
651 newPw.put(SRC_CP, cP1);
652 newPw.put(DST_CP, cP2);
653 newPw.put(PW_LABEL, pwLabel);
654 newPw.put(SRC_INNER_TAG, cP1InnerVlan);
655 newPw.put(SRC_OUTER_TAG, cP1OuterVlan);
656 newPw.put(DST_INNER_TAG, cP2InnerVlan);
657 newPw.put(DST_OUTER_TAG, cP2OuterVlan);
658 newPw.put(SD_TAG, sdTag);
659 newPw.put(MODE, mode);
660
661 object.set(tunnelId, newPw);
Andreas Pantelopoulosb3e45a32018-01-16 11:51:32 -0800662
663 if (!isValid()) {
664 log.info("Pseudowire could not be created : {}");
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700665 object.remove(tunnelId);
666 return null;
667 }
668
669 return object;
670 }
Pier Ventre6b19e482016-11-07 16:21:04 -0800671}