blob: 8b334ea6825464ce4879e2e492131fe49836fb1d [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.pwaas;
18
Pier Ventref3cf5b92016-11-09 14:17:26 -080019import com.google.common.collect.Iterables;
20import com.google.common.collect.Lists;
21import org.apache.commons.lang3.RandomUtils;
Pier Ventreac3e1d92016-11-17 22:26:29 -080022import org.onlab.packet.Ethernet;
Pier Ventref3cf5b92016-11-09 14:17:26 -080023import org.onlab.packet.MacAddress;
24import org.onlab.packet.MplsLabel;
25import org.onlab.packet.VlanId;
26import org.onlab.util.KryoNamespace;
27import org.onosproject.net.ConnectPoint;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070028import org.onosproject.net.DefaultLink;
Pier Ventref3cf5b92016-11-09 14:17:26 -080029import org.onosproject.net.DeviceId;
30import org.onosproject.net.DisjointPath;
31import org.onosproject.net.Link;
32import org.onosproject.net.PortNumber;
Pier Ventre6b19e482016-11-07 16:21:04 -080033import org.onosproject.net.config.NetworkConfigEvent;
Pier Ventref3cf5b92016-11-09 14:17:26 -080034import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.flow.TrafficTreatment;
38import org.onosproject.net.flow.criteria.Criteria;
39import org.onosproject.net.flowobjective.DefaultFilteringObjective;
40import org.onosproject.net.flowobjective.DefaultForwardingObjective;
41import org.onosproject.net.flowobjective.DefaultNextObjective;
42import org.onosproject.net.flowobjective.DefaultObjectiveContext;
43import org.onosproject.net.flowobjective.FilteringObjective;
44import org.onosproject.net.flowobjective.ForwardingObjective;
45import org.onosproject.net.flowobjective.NextObjective;
46import org.onosproject.net.flowobjective.Objective;
47import org.onosproject.net.flowobjective.ObjectiveContext;
48import org.onosproject.net.flowobjective.ObjectiveError;
Pier Ventre6b19e482016-11-07 16:21:04 -080049import org.onosproject.segmentrouting.SegmentRoutingManager;
Pier Ventref3cf5b92016-11-09 14:17:26 -080050import org.onosproject.segmentrouting.SegmentRoutingService;
51import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
Pier Ventre6b19e482016-11-07 16:21:04 -080052import org.onosproject.segmentrouting.config.PwaasConfig;
Pier Ventref3cf5b92016-11-09 14:17:26 -080053import org.onosproject.store.serializers.KryoNamespaces;
54import org.onosproject.store.service.ConsistentMap;
55import org.onosproject.store.service.Serializer;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070056import org.onosproject.store.service.Versioned;
Pier Ventre6b19e482016-11-07 16:21:04 -080057import org.slf4j.Logger;
58import org.slf4j.LoggerFactory;
59
Pier Ventref3cf5b92016-11-09 14:17:26 -080060import java.util.List;
61import java.util.Set;
62import java.util.concurrent.CompletableFuture;
63import java.util.stream.Collectors;
64
Pier Ventref3cf5b92016-11-09 14:17:26 -080065import static org.onosproject.net.flowobjective.ForwardingObjective.Flag.VERSATILE;
Pier Ventref3cf5b92016-11-09 14:17:26 -080066import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.INITIATION;
Pier Ventreac3e1d92016-11-17 22:26:29 -080067import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.TERMINATION;
Pier Ventref3cf5b92016-11-09 14:17:26 -080068import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Result.*;
Pier Ventreac3e1d92016-11-17 22:26:29 -080069import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.FWD;
70import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.REV;
Pier Ventref3cf5b92016-11-09 14:17:26 -080071
Pier Ventre6b19e482016-11-07 16:21:04 -080072/**
73 * Handles pwaas related events.
74 */
75public class L2TunnelHandler {
Pier Ventref3cf5b92016-11-09 14:17:26 -080076
Pier Ventre6b19e482016-11-07 16:21:04 -080077 private static final Logger log = LoggerFactory.getLogger(L2TunnelHandler.class);
Pier Ventref3cf5b92016-11-09 14:17:26 -080078
Pier Ventre6b19e482016-11-07 16:21:04 -080079 private final SegmentRoutingManager srManager;
Pier Ventref3cf5b92016-11-09 14:17:26 -080080 /**
Pier Ventreac3e1d92016-11-17 22:26:29 -080081 * To store the next objectives related to the initiation.
82 */
83 private final ConsistentMap<String, NextObjective> l2InitiationNextObjStore;
84 /**
85 * To store the next objectives related to the termination.
86 */
87 private final ConsistentMap<String, NextObjective> l2TerminationNextObjStore;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070088
Pier Ventreac3e1d92016-11-17 22:26:29 -080089 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070090 * To store policies.
Pier Ventref3cf5b92016-11-09 14:17:26 -080091 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -070092 private final ConsistentMap<String, DefaultL2TunnelPolicy> l2PolicyStore;
93
94 /**
95 * To store tunnels.
96 */
97 private final ConsistentMap<String, DefaultL2Tunnel> l2TunnelStore;
98
Pier Ventref3cf5b92016-11-09 14:17:26 -080099 private final KryoNamespace.Builder l2TunnelKryo;
100
101 /**
102 * Create a l2 tunnel handler for the deploy and
103 * for the tear down of pseudo wires.
104 *
105 * @param segmentRoutingManager the segment routing manager
106 */
107 public L2TunnelHandler(SegmentRoutingManager segmentRoutingManager) {
108 srManager = segmentRoutingManager;
109 l2TunnelKryo = new KryoNamespace.Builder()
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700110 .register(KryoNamespaces.API)
111 .register(DefaultL2Tunnel.class,
112 DefaultL2TunnelPolicy.class,
113 L2Mode.class,
114 MplsLabel.class,
115 VlanId.class,
116 ConnectPoint.class);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800117
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700118 l2InitiationNextObjStore = srManager.
119 storageService.
120 <String, NextObjective>consistentMapBuilder().
121 withName("onos-l2initiation-nextobj-store").
122 withSerializer(Serializer.using(l2TunnelKryo.build())).
123 build();
Pier Ventreac3e1d92016-11-17 22:26:29 -0800124
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700125 l2TerminationNextObjStore = srManager.storageService.
126 <String, NextObjective>consistentMapBuilder()
Pier Ventreac3e1d92016-11-17 22:26:29 -0800127 .withName("onos-l2termination-nextobj-store")
128 .withSerializer(Serializer.using(l2TunnelKryo.build()))
129 .build();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700130
131 l2PolicyStore = srManager.storageService
132 .<String, DefaultL2TunnelPolicy>consistentMapBuilder()
133 .withName("onos-l2-policy-store")
134 .withSerializer(Serializer.using(l2TunnelKryo.build()))
135 .build();
136
137 l2TunnelStore = srManager.storageService
138 .<String, DefaultL2Tunnel>consistentMapBuilder()
139 .withName("onos-l2-tunnel-store")
140 .withSerializer(Serializer.using(l2TunnelKryo.build()))
141 .build();
142 }
143
144 /**
145 * Returns all L2 Policies.
146 *
147 * @return List of policies
148 */
149 public List<DefaultL2TunnelPolicy> getL2Policies() {
150
151 return l2PolicyStore
152 .values()
153 .stream()
154 .map(Versioned::value)
155 .map(DefaultL2TunnelPolicy::new)
156 .collect(Collectors.toList());
157
158 }
159
160 /**
161 * Returns all L2 Tunnels.
162 *
163 * @return List of tunnels.
164 */
165 public List<DefaultL2Tunnel> getL2Tunnels() {
166
167 return l2TunnelStore
168 .values()
169 .stream()
170 .map(Versioned::value)
171 .map(DefaultL2Tunnel::new)
172 .collect(Collectors.toList());
173
174 }
175
176 /**
177 * Processes a link removal. Finds affected pseudowires and rewires them.
178 * TODO: Make it also take into account failures of links that are used for pw
179 * traffic in the spine.
180 * @param link The link that failed
181 */
182 public void processLinkDown(Link link) {
183
184 List<DefaultL2Tunnel> tunnels = getL2Tunnels();
185 List<DefaultL2TunnelPolicy> policies = getL2Policies();
186
187 // determine affected pseudowires and update them at once
188 Set<DefaultL2TunnelDescription> pwToUpdate = tunnels
189 .stream()
190 .filter(tun -> tun.pathUsed().contains(link))
191 .map(l2Tunnel -> {
192 DefaultL2TunnelPolicy policy = null;
193 for (DefaultL2TunnelPolicy l2Policy : policies) {
194 if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
195 policy = l2Policy;
196 break;
197 }
198 }
199
200 return new DefaultL2TunnelDescription(l2Tunnel, policy);
201 })
202 .collect(Collectors.toSet());
203
204
205 log.info("Pseudowires affected by link failure : {}, rerouting them...", pwToUpdate);
206
207 // update all pseudowires
208 pwToUpdate.forEach(tun -> updatePw(tun, tun));
Pier Ventre6b19e482016-11-07 16:21:04 -0800209 }
210
211 /**
212 * Processes Pwaas Config added event.
213 *
Pier Ventref3cf5b92016-11-09 14:17:26 -0800214 * @param event network config add event
Pier Ventre6b19e482016-11-07 16:21:04 -0800215 */
216 public void processPwaasConfigAdded(NetworkConfigEvent event) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700217
218 log.info("Network event : Pseudowire configuration added!");
Pier Ventre6b19e482016-11-07 16:21:04 -0800219 PwaasConfig config = (PwaasConfig) event.config().get();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700220
221 // gather pseudowires
222 Set<DefaultL2TunnelDescription> pwToAdd = config
223 .getPwIds()
Pier Ventref3cf5b92016-11-09 14:17:26 -0800224 .stream()
225 .map(config::getPwDescription)
226 .collect(Collectors.toSet());
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700227
228 // deploy pseudowires
Pier Ventref3cf5b92016-11-09 14:17:26 -0800229 deploy(pwToAdd);
230 }
231
Pier Ventreac3e1d92016-11-17 22:26:29 -0800232 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700233 * Returns the new vlan id for an ingress point of a
234 * pseudowire. For double tagged, it is the outer,
235 * For single tagged it is the single tag, and for
236 * inner it is None.
237 *
238 * @param ingressOuter vlanid of ingress outer
239 * @param ingressInner vlanid of ingress inner
240 * @param egressOuter vlanid of egress outer
241 * @param egressInner vlanid of egress inner
242 * @return returns the vlan id which will be installed at vlan table 1.
243 */
244 public VlanId determineEgressVlan(VlanId ingressOuter, VlanId ingressInner,
245 VlanId egressOuter, VlanId egressInner) {
246
247 // validity of vlan combinations was checked at verifyPseudowire
248 if (!(ingressOuter.equals(VlanId.NONE))) {
249 return egressOuter;
250 } else if (!(ingressInner.equals(VlanId.NONE))) {
251 return egressInner;
252 } else {
253 return VlanId.vlanId("None");
254 }
255 }
256
257 /**
258 * Adds a single pseudowire. This method can be called from cli commands
259 * without configration updates, thus it does not check for mastership
260 * of the ingress pseudowire device.
261 *
262 * @param pw The pseudowire
263 * @return
264 */
265 private Result deployPseudowire(DefaultL2TunnelDescription pw) {
266
267 Result result;
268 long l2TunnelId;
269
270 l2TunnelId = pw.l2Tunnel().tunnelId();
271
272 // The tunnel id cannot be 0.
273 if (l2TunnelId == 0) {
274 log.warn("Tunnel id id must be > 0");
275 return Result.ADDITION_ERROR;
276 }
277
278 // get path here, need to use the same for fwd and rev direction
279 List<Link> path = getPath(pw.l2TunnelPolicy().cP1(),
280 pw.l2TunnelPolicy().cP2());
281 if (path == null) {
282 log.info("Deploying process : No path between the connection points for pseudowire {}", l2TunnelId);
283 return WRONG_PARAMETERS;
284 }
285
286 pw.l2Tunnel().setPath(path);
287
288 // next hops for next objectives
289 Link fwdNextHop = path.get(0);
290 Link revNextHop = reverseLink(path.get(1));
291
292 log.info("Deploying process : Establishing forward direction for pseudowire {}", l2TunnelId);
293
294 // We establish the tunnel.
295 // result.nextId will be used in fwd
296 result = deployPseudoWireInit(pw.l2Tunnel(),
297 pw.l2TunnelPolicy().cP1(),
298 pw.l2TunnelPolicy().cP2(),
299 FWD,
300 fwdNextHop);
301 if (result != SUCCESS) {
302 log.info("Deploying process : Error in deploying pseudowire initiation for CP1");
303 return Result.ADDITION_ERROR;
304 }
305
306 VlanId egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP1OuterTag(),
307 pw.l2TunnelPolicy().cP1InnerTag(),
308 pw.l2TunnelPolicy().cP2OuterTag(),
309 pw.l2TunnelPolicy().cP2InnerTag());
310
311 // We create the policy.
312 result = deployPolicy(l2TunnelId,
313 pw.l2TunnelPolicy().cP1(),
314 pw.l2TunnelPolicy().cP1InnerTag(),
315 pw.l2TunnelPolicy().cP1OuterTag(),
316 egressVlan,
317 result.nextId);
318 if (result != SUCCESS) {
319 log.info("Deploying process : Error in deploying pseudowire policy for CP1");
320 return Result.ADDITION_ERROR;
321 }
322
323 // We terminate the tunnel
324 result = deployPseudoWireTerm(pw.l2Tunnel(),
325 pw.l2TunnelPolicy().cP2(),
326 pw.l2TunnelPolicy().cP2OuterTag(),
327 FWD);
328
329 if (result != SUCCESS) {
330 log.info("Deploying process : Error in deploying pseudowire termination for CP1");
331 return Result.ADDITION_ERROR;
332
333 }
334
335 log.info("Deploying process : Establishing reverse direction for pseudowire {}", l2TunnelId);
336
337 // We establish the reverse tunnel.
338 result = deployPseudoWireInit(pw.l2Tunnel(),
339 pw.l2TunnelPolicy().cP2(),
340 pw.l2TunnelPolicy().cP1(),
341 REV,
342 revNextHop);
343 if (result != SUCCESS) {
344 log.info("Deploying process : Error in deploying pseudowire initiation for CP2");
345 return Result.ADDITION_ERROR;
346 }
347
348 egressVlan = determineEgressVlan(pw.l2TunnelPolicy().cP2OuterTag(),
349 pw.l2TunnelPolicy().cP2InnerTag(),
350 pw.l2TunnelPolicy().cP1OuterTag(),
351 pw.l2TunnelPolicy().cP1InnerTag());
352 result = deployPolicy(l2TunnelId,
353 pw.l2TunnelPolicy().cP2(),
354 pw.l2TunnelPolicy().cP2InnerTag(),
355 pw.l2TunnelPolicy().cP2OuterTag(),
356 egressVlan,
357 result.nextId);
358 if (result != SUCCESS) {
359 log.info("Deploying process : Error in deploying policy for CP2");
360 return Result.ADDITION_ERROR;
361 }
362
363 result = deployPseudoWireTerm(pw.l2Tunnel(),
364 pw.l2TunnelPolicy().cP1(),
365 pw.l2TunnelPolicy().cP1OuterTag(),
366 REV);
367
368 if (result != SUCCESS) {
369 log.info("Deploying process : Error in deploying pseudowire termination for CP2");
370 return Result.ADDITION_ERROR;
371 }
372
373 log.info("Deploying process : Updating relevant information for pseudowire {}", l2TunnelId);
374
375 // Populate stores
376 l2TunnelStore.put(Long.toString(l2TunnelId), pw.l2Tunnel());
377 l2PolicyStore.put(Long.toString(l2TunnelId), pw.l2TunnelPolicy());
378
379 return Result.SUCCESS;
380 }
381
382 /**
Pier Ventreac3e1d92016-11-17 22:26:29 -0800383 * To deploy a number of pseudo wires.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700384 * <p>
385 * Called ONLY when configuration changes, thus the check
386 * for the mastership of the device.
387 * <p>
388 * Only the master of CP1 will deploy this pseudowire.
Pier Ventreac3e1d92016-11-17 22:26:29 -0800389 *
390 * @param pwToAdd the set of pseudo wires to add
391 */
Pier Ventref3cf5b92016-11-09 14:17:26 -0800392 private void deploy(Set<DefaultL2TunnelDescription> pwToAdd) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700393
Pier Ventref3cf5b92016-11-09 14:17:26 -0800394 Result result;
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700395
Pier Ventref3cf5b92016-11-09 14:17:26 -0800396 for (DefaultL2TunnelDescription currentL2Tunnel : pwToAdd) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700397
398 // only the master of CP1 will program this pseudowire
399 if (!srManager.isMasterOf(currentL2Tunnel.l2TunnelPolicy().cP1())) {
Pier Ventref3cf5b92016-11-09 14:17:26 -0800400 continue;
401 }
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700402
403 log.info("Deploying pseudowire {}", currentL2Tunnel.l2Tunnel().tunnelId());
404
405 result = deployPseudowire(currentL2Tunnel);
406 switch (result) {
407 case WRONG_PARAMETERS:
408 log.warn("Could not deploy pseudowire {}, wrong parameters!",
409 currentL2Tunnel.l2Tunnel().tunnelId());
410 break;
411 case ADDITION_ERROR:
412 log.warn("Could not deploy pseudowire {}, error in populating rules!",
413 currentL2Tunnel.l2Tunnel().tunnelId());
414 break;
415 default:
416 log.info("Pseudowire with {} succesfully deployed!",
417 currentL2Tunnel.l2Tunnel().tunnelId());
418 break;
Pier Ventref3cf5b92016-11-09 14:17:26 -0800419 }
Pier Ventref3cf5b92016-11-09 14:17:26 -0800420 }
Pier Ventre6b19e482016-11-07 16:21:04 -0800421 }
422
423 /**
Pier Ventreac3e1d92016-11-17 22:26:29 -0800424 * Processes PWaaS Config updated event.
Pier Ventre6b19e482016-11-07 16:21:04 -0800425 *
426 * @param event network config updated event
427 */
428 public void processPwaasConfigUpdated(NetworkConfigEvent event) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700429
430 log.info("Pseudowire configuration updated.");
431
Pier Ventref3cf5b92016-11-09 14:17:26 -0800432 // We retrieve the old pseudo wires.
433 PwaasConfig prevConfig = (PwaasConfig) event.prevConfig().get();
434 Set<Long> prevPws = prevConfig.getPwIds();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700435
Pier Ventref3cf5b92016-11-09 14:17:26 -0800436 // We retrieve the new pseudo wires.
Pier Ventre6b19e482016-11-07 16:21:04 -0800437 PwaasConfig config = (PwaasConfig) event.config().get();
Pier Ventref3cf5b92016-11-09 14:17:26 -0800438 Set<Long> newPws = config.getPwIds();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700439
Pier Ventref3cf5b92016-11-09 14:17:26 -0800440 // We compute the pseudo wires to update.
441 Set<Long> updPws = newPws.stream()
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700442 .filter(tunnelId -> prevPws.contains(tunnelId)
443 && !config.getPwDescription(tunnelId).equals(prevConfig.getPwDescription(tunnelId)))
Pier Ventref3cf5b92016-11-09 14:17:26 -0800444 .collect(Collectors.toSet());
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700445
Pier Ventref3cf5b92016-11-09 14:17:26 -0800446 // The pseudo wires to remove.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700447 Set<Long> rmvPWs = prevPws.stream()
448 .filter(tunnelId -> !newPws.contains(tunnelId)).collect(Collectors.toSet());
449
450 Set<DefaultL2TunnelDescription> pwToRemove = rmvPWs.stream()
Pier Ventref3cf5b92016-11-09 14:17:26 -0800451 .map(prevConfig::getPwDescription)
452 .collect(Collectors.toSet());
453 tearDown(pwToRemove);
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700454
Pier Ventref3cf5b92016-11-09 14:17:26 -0800455 // The pseudo wires to add.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700456 Set<Long> addedPWs = newPws.stream()
Pier Ventref3cf5b92016-11-09 14:17:26 -0800457 .filter(tunnelId -> !prevPws.contains(tunnelId))
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700458 .collect(Collectors.toSet());
459 Set<DefaultL2TunnelDescription> pwToAdd = addedPWs.stream()
Pier Ventref3cf5b92016-11-09 14:17:26 -0800460 .map(config::getPwDescription)
461 .collect(Collectors.toSet());
462 deploy(pwToAdd);
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700463
464
Pier Ventref3cf5b92016-11-09 14:17:26 -0800465 // The pseudo wires to update.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700466 updPws.forEach(tunnelId -> updatePw(prevConfig.getPwDescription(tunnelId),
467 config.getPwDescription(tunnelId)));
468
469 log.info("Pseudowires removed : {}, Pseudowires updated : {}, Pseudowires added : {}", rmvPWs,
470 updPws, addedPWs);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800471 }
472
473 /**
474 * Helper function to update a pw.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700475 * <p>
476 * Called upon configuration changes that update existing pseudowires and
477 * when links fail. Checking of mastership for CP1 is mandatory because it is
478 * called in multiple instances for both cases.
479 * <p>
480 * Meant to call asynchronously for various events, thus this call can not block and need
481 * to perform asynchronous operations.
482 * <p>
483 * For this reason error checking is omitted.
Pier Ventref3cf5b92016-11-09 14:17:26 -0800484 *
485 * @param oldPw the pseudo wire to remove
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700486 * @param newPw the pseudo wire to add
Pier Ventref3cf5b92016-11-09 14:17:26 -0800487 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700488 public void updatePw(DefaultL2TunnelDescription oldPw, DefaultL2TunnelDescription newPw) {
Pier Ventref3cf5b92016-11-09 14:17:26 -0800489 long tunnelId = oldPw.l2Tunnel().tunnelId();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700490
491 // only the master of CP1 will update this pseudowire
492 if (!srManager.isMasterOf(oldPw.l2TunnelPolicy().cP1())) {
493 return;
494 }
495
496 log.info("Updating pseudowire {}", oldPw.l2Tunnel().tunnelId());
497
Pier Ventref3cf5b92016-11-09 14:17:26 -0800498 // The async tasks to orchestrate the next and
499 // forwarding update.
Pier Ventref3cf5b92016-11-09 14:17:26 -0800500 CompletableFuture<ObjectiveError> fwdInitNextFuture = new CompletableFuture<>();
501 CompletableFuture<ObjectiveError> revInitNextFuture = new CompletableFuture<>();
Pier Ventreac3e1d92016-11-17 22:26:29 -0800502 CompletableFuture<ObjectiveError> fwdTermNextFuture = new CompletableFuture<>();
503 CompletableFuture<ObjectiveError> revTermNextFuture = new CompletableFuture<>();
504 CompletableFuture<ObjectiveError> fwdPwFuture = new CompletableFuture<>();
505 CompletableFuture<ObjectiveError> revPwFuture = new CompletableFuture<>();
Pier Ventref3cf5b92016-11-09 14:17:26 -0800506
Pier Ventref3cf5b92016-11-09 14:17:26 -0800507 // First we remove both policy.
Pier Ventref3cf5b92016-11-09 14:17:26 -0800508 log.debug("Start deleting fwd policy for {}", tunnelId);
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700509
510 // first delete all information from our stores
511 // we can not do it asynchronously
512 l2PolicyStore.remove(Long.toString(tunnelId));
513 l2TunnelStore.remove(Long.toString(tunnelId));
514
515 VlanId egressVlan = determineEgressVlan(oldPw.l2TunnelPolicy().cP1OuterTag(),
516 oldPw.l2TunnelPolicy().cP1InnerTag(),
517 oldPw.l2TunnelPolicy().cP2OuterTag(),
518 oldPw.l2TunnelPolicy().cP2InnerTag());
519 deletePolicy(tunnelId,
520 oldPw.l2TunnelPolicy().cP1(),
521 oldPw.l2TunnelPolicy().cP1InnerTag(),
522 oldPw.l2TunnelPolicy().cP1OuterTag(),
523 egressVlan,
524 fwdInitNextFuture,
525 FWD);
526
527 log.debug("Update process : Start deleting rev policy for {}", tunnelId);
528
529 egressVlan = determineEgressVlan(oldPw.l2TunnelPolicy().cP2OuterTag(),
530 oldPw.l2TunnelPolicy().cP2InnerTag(),
531 oldPw.l2TunnelPolicy().cP1OuterTag(),
532 oldPw.l2TunnelPolicy().cP1InnerTag());
533 deletePolicy(tunnelId,
534 oldPw.l2TunnelPolicy().cP2(),
535 oldPw.l2TunnelPolicy().cP2InnerTag(),
536 oldPw.l2TunnelPolicy().cP2OuterTag(),
537 egressVlan, revInitNextFuture,
538 REV);
539
Pier Ventref3cf5b92016-11-09 14:17:26 -0800540 // Finally we remove both the tunnels.
541 fwdInitNextFuture.thenAcceptAsync(status -> {
542 if (status == null) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700543 log.debug("Update process : Fwd policy removed. " +
544 "Now remove fwd {} for {}", INITIATION, tunnelId);
545 tearDownPseudoWireInit(tunnelId,
546 oldPw.l2TunnelPolicy().cP1(),
547 fwdTermNextFuture,
548 FWD);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800549 }
550 });
551 revInitNextFuture.thenAcceptAsync(status -> {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700552 if (status == null) {
553 log.debug("Update process : Rev policy removed. " +
554 "Now remove rev {} for {}", INITIATION, tunnelId);
555 tearDownPseudoWireInit(tunnelId,
556 oldPw.l2TunnelPolicy().cP2(),
557 revTermNextFuture,
558 REV);
559 }
Pier Ventref3cf5b92016-11-09 14:17:26 -0800560 });
Pier Ventreac3e1d92016-11-17 22:26:29 -0800561 fwdTermNextFuture.thenAcceptAsync(status -> {
562 if (status == null) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700563 log.debug("Update process : Fwd {} removed. " +
564 "Now remove fwd {} for {}", INITIATION, TERMINATION, tunnelId);
565 tearDownPseudoWireTerm(oldPw.l2Tunnel(),
566 oldPw.l2TunnelPolicy().cP2(),
567 fwdPwFuture,
568 FWD);
Pier Ventreac3e1d92016-11-17 22:26:29 -0800569 }
570 });
571 revTermNextFuture.thenAcceptAsync(status -> {
572 if (status == null) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700573 log.debug("Update process : Rev {} removed. " +
574 "Now remove rev {} for {}", INITIATION, TERMINATION, tunnelId);
575 tearDownPseudoWireTerm(oldPw.l2Tunnel(),
576 oldPw.l2TunnelPolicy().cP1(),
577 revPwFuture,
578 REV);
Pier Ventreac3e1d92016-11-17 22:26:29 -0800579 }
580 });
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700581
582 // get path here, need to use the same for fwd and rev direction
583 List<Link> path = getPath(newPw.l2TunnelPolicy().cP1(),
584 newPw.l2TunnelPolicy().cP2());
585 if (path == null) {
586 log.info("Deploying process : " +
587 "No path between the connection points for pseudowire {}", newPw.l2Tunnel().tunnelId());
588 return;
589 }
590
591 newPw.l2Tunnel().setPath(path);
592 // next hops for next objectives
593 Link fwdNextHop = path.get(0);
594 Link revNextHop = reverseLink(path.get(1));
595
596 // At the end we install the updated PW.
Pier Ventreac3e1d92016-11-17 22:26:29 -0800597 fwdPwFuture.thenAcceptAsync(status -> {
Pier Ventref3cf5b92016-11-09 14:17:26 -0800598 if (status == null) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700599
600 // Upgrade stores and book keeping information, need to move this here
601 // cause this call is asynchronous.
602 l2PolicyStore.put(Long.toString(tunnelId), newPw.l2TunnelPolicy());
603 l2TunnelStore.put(Long.toString(tunnelId), newPw.l2Tunnel());
604
605 log.debug("Update process : Deploying new fwd pw for {}", tunnelId);
606 Result lamdaResult = deployPseudoWireInit(newPw.l2Tunnel(),
607 newPw.l2TunnelPolicy().cP1(),
608 newPw.l2TunnelPolicy().cP2(),
609 FWD,
610 fwdNextHop);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800611 if (lamdaResult != SUCCESS) {
612 return;
613 }
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700614
615 VlanId egressVlanId = determineEgressVlan(newPw.l2TunnelPolicy().cP1OuterTag(),
616 newPw.l2TunnelPolicy().cP1InnerTag(),
617 newPw.l2TunnelPolicy().cP2OuterTag(),
618 newPw.l2TunnelPolicy().cP2InnerTag());
619
620 lamdaResult = deployPolicy(tunnelId,
621 newPw.l2TunnelPolicy().cP1(),
622 newPw.l2TunnelPolicy().cP1InnerTag(),
623 newPw.l2TunnelPolicy().cP1OuterTag(),
624 egressVlanId,
625 lamdaResult.nextId);
Pier Ventreac3e1d92016-11-17 22:26:29 -0800626 if (lamdaResult != SUCCESS) {
627 return;
628 }
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700629 deployPseudoWireTerm(newPw.l2Tunnel(),
630 newPw.l2TunnelPolicy().cP2(),
631 newPw.l2TunnelPolicy().cP2OuterTag(),
632 FWD);
Pier Ventreac3e1d92016-11-17 22:26:29 -0800633
634 }
635 });
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700636
Pier Ventreac3e1d92016-11-17 22:26:29 -0800637 revPwFuture.thenAcceptAsync(status -> {
638 if (status == null) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700639 log.debug("Update process : Deploying new rev pw for {}", tunnelId);
640 Result lamdaResult = deployPseudoWireInit(newPw.l2Tunnel(),
641 newPw.l2TunnelPolicy().cP2(),
642 newPw.l2TunnelPolicy().cP1(),
643 REV,
644 revNextHop);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800645 if (lamdaResult != SUCCESS) {
646 return;
647 }
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700648
649 VlanId egressVlanId = determineEgressVlan(newPw.l2TunnelPolicy().cP2OuterTag(),
650 newPw.l2TunnelPolicy().cP2InnerTag(),
651 newPw.l2TunnelPolicy().cP1OuterTag(),
652 newPw.l2TunnelPolicy().cP1InnerTag());
653 lamdaResult = deployPolicy(tunnelId,
654 newPw.l2TunnelPolicy().cP2(),
655 newPw.l2TunnelPolicy().cP2InnerTag(),
656 newPw.l2TunnelPolicy().cP2OuterTag(),
657 egressVlanId,
658 lamdaResult.nextId);
Pier Ventreac3e1d92016-11-17 22:26:29 -0800659 if (lamdaResult != SUCCESS) {
660 return;
661 }
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700662 deployPseudoWireTerm(newPw.l2Tunnel(),
663 newPw.l2TunnelPolicy().cP1(),
664 newPw.l2TunnelPolicy().cP1OuterTag(),
665 REV);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800666 }
Pier Ventre6b19e482016-11-07 16:21:04 -0800667 });
668 }
669
670 /**
671 * Processes Pwaas Config removed event.
672 *
673 * @param event network config removed event
674 */
675 public void processPwaasConfigRemoved(NetworkConfigEvent event) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700676
677 log.info("Network event : Pseudowire configuration removed!");
Pier Ventref3cf5b92016-11-09 14:17:26 -0800678 PwaasConfig config = (PwaasConfig) event.prevConfig().get();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700679
680 Set<DefaultL2TunnelDescription> pwToRemove = config
681 .getPwIds()
Pier Ventref3cf5b92016-11-09 14:17:26 -0800682 .stream()
683 .map(config::getPwDescription)
684 .collect(Collectors.toSet());
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700685
Pier Ventref3cf5b92016-11-09 14:17:26 -0800686 // We teardown all the pseudo wire deployed
687 tearDown(pwToRemove);
Pier Ventre6b19e482016-11-07 16:21:04 -0800688 }
Pier Ventref3cf5b92016-11-09 14:17:26 -0800689
690 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700691 * Helper function for removing a single pseudowire.
692 * <p>
693 * No mastership of CP1 is checked, because it can be called from
694 * the CLI for removal of pseudowires.
Pier Ventref3cf5b92016-11-09 14:17:26 -0800695 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700696 * @param l2TunnelId the id of the pseudowire to tear down
697 * @return Returns SUCCESS if no error is obeserved or an appropriate
698 * error on a failure
Pier Ventref3cf5b92016-11-09 14:17:26 -0800699 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700700 public Result tearDownPseudowire(long l2TunnelId) {
701
702 CompletableFuture<ObjectiveError> fwdInitNextFuture = new CompletableFuture<>();
703 CompletableFuture<ObjectiveError> fwdTermNextFuture = new CompletableFuture<>();
704
705 CompletableFuture<ObjectiveError> revInitNextFuture = new CompletableFuture<>();
706 CompletableFuture<ObjectiveError> revTermNextFuture = new CompletableFuture<>();
707
708 if (l2TunnelId == 0) {
709 log.warn("Removal process : Tunnel id cannot be 0");
710 return Result.WRONG_PARAMETERS;
Pier Ventref3cf5b92016-11-09 14:17:26 -0800711 }
712
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700713 // check existence of tunnels/policy in the store, if one is missing abort!
714 Versioned<DefaultL2Tunnel> l2TunnelVersioned = l2TunnelStore.get(Long.toString(l2TunnelId));
715 Versioned<DefaultL2TunnelPolicy> l2TunnelPolicyVersioned = l2PolicyStore.get(Long.toString(l2TunnelId));
716 if ((l2TunnelVersioned == null) || (l2TunnelPolicyVersioned == null)) {
717 log.warn("Removal process : Policy and/or tunnel missing for tunnel id {}", l2TunnelId);
718 return Result.REMOVAL_ERROR;
719 }
720
721 DefaultL2TunnelDescription pwToRemove = new DefaultL2TunnelDescription(l2TunnelVersioned.value(),
722 l2TunnelPolicyVersioned.value());
723
724 // remove the tunnels and the policies from the store
725 l2PolicyStore.remove(Long.toString(l2TunnelId));
726 l2TunnelStore.remove(Long.toString(l2TunnelId));
727
728 log.info("Removal process : Tearing down forward direction of pseudowire {}", l2TunnelId);
729
730 VlanId egressVlan = determineEgressVlan(pwToRemove.l2TunnelPolicy().cP1OuterTag(),
731 pwToRemove.l2TunnelPolicy().cP1InnerTag(),
732 pwToRemove.l2TunnelPolicy().cP2OuterTag(),
733 pwToRemove.l2TunnelPolicy().cP2InnerTag());
734 deletePolicy(l2TunnelId,
735 pwToRemove.l2TunnelPolicy().cP1(),
736 pwToRemove.l2TunnelPolicy().cP1InnerTag(),
737 pwToRemove.l2TunnelPolicy().cP1OuterTag(),
738 egressVlan,
739 fwdInitNextFuture,
740 FWD);
741
742 fwdInitNextFuture.thenAcceptAsync(status -> {
743 if (status == null) {
744 // Finally we will tear down the pseudo wire.
745 tearDownPseudoWireInit(l2TunnelId,
746 pwToRemove.l2TunnelPolicy().cP1(),
747 fwdTermNextFuture,
748 FWD);
749 }
750 });
751
752 fwdTermNextFuture.thenAcceptAsync(status -> {
753 if (status == null) {
754 tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
755 pwToRemove.l2TunnelPolicy().cP2(),
756 null,
757 FWD);
758 }
759 });
760
761 log.info("Removal process : Tearing down reverse direction of pseudowire {}", l2TunnelId);
762
763 egressVlan = determineEgressVlan(pwToRemove.l2TunnelPolicy().cP2OuterTag(),
764 pwToRemove.l2TunnelPolicy().cP2InnerTag(),
765 pwToRemove.l2TunnelPolicy().cP1OuterTag(),
766 pwToRemove.l2TunnelPolicy().cP1InnerTag());
767
768 // We do the same operations on the reverse side.
769 deletePolicy(l2TunnelId,
770 pwToRemove.l2TunnelPolicy().cP2(),
771 pwToRemove.l2TunnelPolicy().cP2InnerTag(),
772 pwToRemove.l2TunnelPolicy().cP2OuterTag(),
773 egressVlan,
774 revInitNextFuture,
775 REV);
776
777 revInitNextFuture.thenAcceptAsync(status -> {
778 if (status == null) {
779 tearDownPseudoWireInit(l2TunnelId,
780 pwToRemove.l2TunnelPolicy().cP2(),
781 revTermNextFuture,
782 REV);
783 }
784 });
785
786 revTermNextFuture.thenAcceptAsync(status -> {
787 if (status == null) {
788 tearDownPseudoWireTerm(pwToRemove.l2Tunnel(),
789 pwToRemove.l2TunnelPolicy().cP1(),
790 null,
791 REV);
792 }
793 });
794
795 return Result.SUCCESS;
Pier Ventref3cf5b92016-11-09 14:17:26 -0800796 }
797
798 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700799 * Helper function to handle the pw removal.
800 * <p>
801 * This method checks for the mastership of the device because it is
802 * used only from network configuration updates, thus we only want
803 * one instance only to program each pseudowire.
Pier Ventref3cf5b92016-11-09 14:17:26 -0800804 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700805 * @param pwToRemove the pseudo wires to remove
Pier Ventref3cf5b92016-11-09 14:17:26 -0800806 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700807 public void tearDown(Set<DefaultL2TunnelDescription> pwToRemove) {
Pier Ventref3cf5b92016-11-09 14:17:26 -0800808
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700809 Result result;
810
811 // We remove all the pw in the configuration file.
812 for (DefaultL2TunnelDescription currentL2Tunnel : pwToRemove) {
813
814 // only the master of CP1 will program this pseudowire
815 if (!srManager.isMasterOf(currentL2Tunnel.l2TunnelPolicy().cP1())) {
816 continue;
817 }
818
819 log.info("Removing pseudowire {}", currentL2Tunnel.l2Tunnel().tunnelId());
820
821 result = tearDownPseudowire(currentL2Tunnel.l2Tunnel().tunnelId());
822 switch (result) {
823 case WRONG_PARAMETERS:
824 log.warn("Error in supplied parameters for the pseudowire removal with tunnel id {}!",
825 currentL2Tunnel.l2Tunnel().tunnelId());
826 break;
827 case REMOVAL_ERROR:
828 log.warn("Error in pseudowire removal with tunnel id {}!", currentL2Tunnel.l2Tunnel().tunnelId());
829 break;
830 default:
831 log.warn("Pseudowire with tunnel id {} was removed successfully",
832 currentL2Tunnel.l2Tunnel().tunnelId());
833 }
834 }
Pier Ventref3cf5b92016-11-09 14:17:26 -0800835 }
836
837 /**
Pier Ventref3cf5b92016-11-09 14:17:26 -0800838 * Handles the policy establishment which consists in
839 * create the filtering and forwarding objectives related
840 * to the initiation and termination.
841 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700842 * @param tunnelId the tunnel id
843 * @param ingress the ingress point
Pier Ventref3cf5b92016-11-09 14:17:26 -0800844 * @param ingressInner the ingress inner tag
845 * @param ingressOuter the ingress outer tag
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700846 * @param nextId the next objective id
847 * @param egressVlan Vlan-id to set, depends on ingress vlan
848 * combinations. For example, if pw is double tagged
849 * then this is the value of the outer vlan, if single
850 * tagged then it is the new value of the single tag.
851 * Should be None for untagged traffic.
Pier Ventreac3e1d92016-11-17 22:26:29 -0800852 * @return the result of the operation
Pier Ventref3cf5b92016-11-09 14:17:26 -0800853 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700854 private Result deployPolicy(long tunnelId, ConnectPoint ingress, VlanId ingressInner,
855 VlanId ingressOuter, VlanId egressVlan, int nextId) {
856
Pier Ventreac3e1d92016-11-17 22:26:29 -0800857 List<Objective> objectives = Lists.newArrayList();
Pier Ventref3cf5b92016-11-09 14:17:26 -0800858 // We create the forwarding objective for supporting
859 // the l2 tunnel.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700860 ForwardingObjective.Builder fwdBuilder = createInitFwdObjective(tunnelId, ingress.port(), nextId);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800861 // We create and add objective context.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700862 ObjectiveContext context = new DefaultObjectiveContext((objective) ->
863 log.debug("FwdObj for tunnel {} populated", tunnelId),
864 (objective, error) ->
865 log.warn("Failed to populate fwdrObj " +
866 "for tunnel {}", tunnelId, error));
Pier Ventref3cf5b92016-11-09 14:17:26 -0800867 objectives.add(fwdBuilder.add(context));
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700868
Pier Ventref3cf5b92016-11-09 14:17:26 -0800869 // We create the filtering objective to define the
870 // permit traffic in the switch
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700871 FilteringObjective.Builder filtBuilder = createFiltObjective(ingress.port(), ingressInner, ingressOuter);
872
Pier Ventref3cf5b92016-11-09 14:17:26 -0800873 // We add the metadata.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700874 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
875 .builder()
876 .setTunnelId(tunnelId)
877 .setVlanId(egressVlan);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800878 filtBuilder.withMeta(treatment.build());
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700879
Pier Ventref3cf5b92016-11-09 14:17:26 -0800880 // We create and add objective context.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700881 context = new DefaultObjectiveContext((objective) -> log.debug("FilterObj for tunnel {} populated", tunnelId),
882 (objective, error) -> log.warn("Failed to populate filterObj for " +
883 "tunnel {}", tunnelId, error));
Pier Ventref3cf5b92016-11-09 14:17:26 -0800884 objectives.add(filtBuilder.add(context));
885
886 for (Objective objective : objectives) {
887 if (objective instanceof ForwardingObjective) {
888 srManager.flowObjectiveService.forward(ingress.deviceId(), (ForwardingObjective) objective);
Pier Ventreac3e1d92016-11-17 22:26:29 -0800889 log.debug("Creating new FwdObj for initiation NextObj with id={} for tunnel {}", nextId, tunnelId);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800890 } else {
891 srManager.flowObjectiveService.filter(ingress.deviceId(), (FilteringObjective) objective);
892 log.debug("Creating new FiltObj for tunnel {}", tunnelId);
893 }
894 }
895 return SUCCESS;
896 }
897
898 /**
Pier Ventref3cf5b92016-11-09 14:17:26 -0800899 * Handles the tunnel establishment which consists in
Pier Ventreac3e1d92016-11-17 22:26:29 -0800900 * create the next objectives related to the initiation.
Pier Ventref3cf5b92016-11-09 14:17:26 -0800901 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700902 * @param l2Tunnel the tunnel to deploy
903 * @param ingress the ingress connect point
904 * @param egress the egress connect point
Pier Ventref3cf5b92016-11-09 14:17:26 -0800905 * @param direction the direction of the pw
Pier Ventreac3e1d92016-11-17 22:26:29 -0800906 * @return the result of the operation
Pier Ventref3cf5b92016-11-09 14:17:26 -0800907 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700908 private Result deployPseudoWireInit(DefaultL2Tunnel l2Tunnel, ConnectPoint ingress,
909 ConnectPoint egress, Direction direction, Link nextHop) {
910
Pier Ventref3cf5b92016-11-09 14:17:26 -0800911 if (nextHop == null) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700912 log.warn("No path between ingress and egress cps for tunnel {}", l2Tunnel.tunnelId());
Pier Ventref3cf5b92016-11-09 14:17:26 -0800913 return WRONG_PARAMETERS;
914 }
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700915
Pier Ventref3cf5b92016-11-09 14:17:26 -0800916 // We create the next objective without the metadata
917 // context and id. We check if it already exists in the
Pier Ventreac3e1d92016-11-17 22:26:29 -0800918 // store. If not we store as it is in the store.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700919 NextObjective.Builder nextObjectiveBuilder = createNextObjective(INITIATION,
920 nextHop.src(),
921 nextHop.dst(),
922 l2Tunnel,
923 egress.deviceId());
924
Pier Ventref3cf5b92016-11-09 14:17:26 -0800925 if (nextObjectiveBuilder == null) {
926 return INTERNAL_ERROR;
927 }
928 // We set the metadata. We will use this metadata
929 // to inform the driver we are doing a l2 tunnel.
930 TrafficSelector metadata = DefaultTrafficSelector
931 .builder()
932 .matchTunnelId(l2Tunnel.tunnelId())
933 .build();
934 nextObjectiveBuilder.withMeta(metadata);
Pier Ventreac3e1d92016-11-17 22:26:29 -0800935 int nextId = srManager.flowObjectiveService.allocateNextId();
Pier Ventref3cf5b92016-11-09 14:17:26 -0800936 if (nextId < 0) {
937 log.warn("Not able to allocate a next id for initiation");
938 return INTERNAL_ERROR;
939 }
940 nextObjectiveBuilder.withId(nextId);
941 String key = generateKey(l2Tunnel.tunnelId(), direction);
942 l2InitiationNextObjStore.put(key, nextObjectiveBuilder.add());
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700943 ObjectiveContext context = new DefaultObjectiveContext((objective) ->
944 log.debug("Initiation l2 tunnel rule " +
945 "for {} populated",
946 l2Tunnel.tunnelId()),
947 (objective, error) ->
948 log.warn("Failed to populate Initiation " +
949 "l2 tunnel rule for {}: {}",
950 l2Tunnel.tunnelId(), error));
Pier Ventreac3e1d92016-11-17 22:26:29 -0800951 NextObjective nextObjective = nextObjectiveBuilder.add(context);
Pier Ventref3cf5b92016-11-09 14:17:26 -0800952 srManager.flowObjectiveService.next(ingress.deviceId(), nextObjective);
953 log.debug("Initiation next objective for {} not found. Creating new NextObj with id={}",
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700954 l2Tunnel.tunnelId(), nextObjective.id());
Pier Ventreac3e1d92016-11-17 22:26:29 -0800955 Result result = SUCCESS;
Pier Ventref3cf5b92016-11-09 14:17:26 -0800956 result.nextId = nextObjective.id();
957 return result;
958 }
959
960 /**
Pier Ventreac3e1d92016-11-17 22:26:29 -0800961 * Handles the tunnel termination, which consists in the creation
962 * of a forwarding objective and a next objective.
963 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700964 * @param l2Tunnel the tunnel to terminate
965 * @param egress the egress point
Pier Ventreac3e1d92016-11-17 22:26:29 -0800966 * @param egressVlan the expected vlan at egress
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700967 * @param direction the direction
Pier Ventreac3e1d92016-11-17 22:26:29 -0800968 * @return the result of the operation
969 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700970 private Result deployPseudoWireTerm(DefaultL2Tunnel l2Tunnel, ConnectPoint egress,
971 VlanId egressVlan, Direction direction) {
972
Pier Ventreac3e1d92016-11-17 22:26:29 -0800973 // We create the group relative to the termination.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700974 NextObjective.Builder nextObjectiveBuilder = createNextObjective(TERMINATION, egress, null,
975 null, egress.deviceId());
Pier Ventreac3e1d92016-11-17 22:26:29 -0800976 if (nextObjectiveBuilder == null) {
977 return INTERNAL_ERROR;
978 }
979 TrafficSelector metadata = DefaultTrafficSelector
980 .builder()
981 .matchVlanId(egressVlan)
982 .build();
983 nextObjectiveBuilder.withMeta(metadata);
984 int nextId = srManager.flowObjectiveService.allocateNextId();
985 if (nextId < 0) {
986 log.warn("Not able to allocate a next id for initiation");
987 return INTERNAL_ERROR;
988 }
989 nextObjectiveBuilder.withId(nextId);
990 String key = generateKey(l2Tunnel.tunnelId(), direction);
991 l2TerminationNextObjStore.put(key, nextObjectiveBuilder.add());
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -0700992 ObjectiveContext context = new DefaultObjectiveContext((objective) -> log.debug("Termination l2 tunnel rule " +
993 "for {} populated",
994 l2Tunnel.tunnelId()),
995 (objective, error) -> log.warn("Failed to populate " +
996 "termination l2 tunnel " +
997 "rule for {}: {}",
998 l2Tunnel.tunnelId(),
999 error));
Pier Ventreac3e1d92016-11-17 22:26:29 -08001000 NextObjective nextObjective = nextObjectiveBuilder.add(context);
1001 srManager.flowObjectiveService.next(egress.deviceId(), nextObjective);
1002 log.debug("Termination next objective for {} not found. Creating new NextObj with id={}",
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001003 l2Tunnel.tunnelId(), nextObjective.id());
1004
Pier Ventreac3e1d92016-11-17 22:26:29 -08001005 // We create the flow relative to the termination.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001006 ForwardingObjective.Builder fwdBuilder = createTermFwdObjective(l2Tunnel.pwLabel(), l2Tunnel.tunnelId(),
1007 egress.port(), nextObjective.id());
1008 context = new DefaultObjectiveContext((objective) -> log.debug("FwdObj for tunnel termination {} populated",
1009 l2Tunnel.tunnelId()),
1010 (objective, error) -> log.warn("Failed to populate fwdrObj" +
1011 " for tunnel termination {}",
1012 l2Tunnel.tunnelId(), error));
Pier Ventreac3e1d92016-11-17 22:26:29 -08001013 srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.add(context));
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001014 log.debug("Creating new FwdObj for termination NextObj with id={} for tunnel {}",
1015 nextId, l2Tunnel.tunnelId());
Pier Ventreac3e1d92016-11-17 22:26:29 -08001016 return SUCCESS;
1017
1018 }
1019
1020 /**
Pier Ventreac3e1d92016-11-17 22:26:29 -08001021 * Creates the filtering objective according to a given policy.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001022 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001023 * @param inPort the in port
Pier Ventref3cf5b92016-11-09 14:17:26 -08001024 * @param innerTag the inner vlan tag
1025 * @param outerTag the outer vlan tag
1026 * @return the filtering objective
1027 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001028 private FilteringObjective.Builder createFiltObjective(PortNumber inPort, VlanId innerTag, VlanId outerTag) {
1029
1030 log.info("Creating filtering objective for vlans {} / {}", outerTag, innerTag);
1031 return DefaultFilteringObjective
1032 .builder()
Pier Ventref3cf5b92016-11-09 14:17:26 -08001033 .withKey(Criteria.matchInPort(inPort))
1034 .addCondition(Criteria.matchInnerVlanId(innerTag))
1035 .addCondition(Criteria.matchVlanId(outerTag))
1036 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
1037 .permit()
Ray Milkeyb85de082017-04-05 09:42:04 -07001038 .fromApp(srManager.appId());
Pier Ventref3cf5b92016-11-09 14:17:26 -08001039 }
1040
1041 /**
Pier Ventreac3e1d92016-11-17 22:26:29 -08001042 * Creates the forwarding objective for the termination.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001043 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001044 * @param pwLabel the pseudo wire label
1045 * @param tunnelId the tunnel id
Pier Ventreac3e1d92016-11-17 22:26:29 -08001046 * @param egressPort the egress port
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001047 * @param nextId the next step
Pier Ventreac3e1d92016-11-17 22:26:29 -08001048 * @return the forwarding objective to support the termination
Pier Ventref3cf5b92016-11-09 14:17:26 -08001049 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001050 private ForwardingObjective.Builder createTermFwdObjective(MplsLabel pwLabel, long tunnelId,
1051 PortNumber egressPort, int nextId) {
1052
1053 TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();
1054 TrafficTreatment.Builder trafficTreatment = DefaultTrafficTreatment.builder();
Pier Ventreac3e1d92016-11-17 22:26:29 -08001055 // The flow has to match on the pw label and bos
1056 trafficSelector.matchEthType(Ethernet.MPLS_UNICAST);
1057 trafficSelector.matchMplsLabel(pwLabel);
1058 trafficSelector.matchMplsBos(true);
1059 // The flow has to decrement ttl, restore ttl in
1060 // pop mpls, set tunnel id and port.
1061 trafficTreatment.decMplsTtl();
1062 trafficTreatment.copyTtlIn();
1063 trafficTreatment.popMpls();
1064 trafficTreatment.setTunnelId(tunnelId);
1065 trafficTreatment.setOutput(egressPort);
1066
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001067 return DefaultForwardingObjective
1068 .builder()
Ray Milkeyb85de082017-04-05 09:42:04 -07001069 .fromApp(srManager.appId())
Pier Ventreac3e1d92016-11-17 22:26:29 -08001070 .makePermanent()
1071 .nextStep(nextId)
1072 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
1073 .withSelector(trafficSelector.build())
1074 .withTreatment(trafficTreatment.build())
1075 .withFlag(VERSATILE);
1076 }
1077
1078 /**
1079 * Creates the forwarding objective for the initiation.
1080 *
1081 * @param tunnelId the tunnel id
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001082 * @param inPort the input port
1083 * @param nextId the next step
Pier Ventreac3e1d92016-11-17 22:26:29 -08001084 * @return the forwarding objective to support the initiation.
1085 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001086 private ForwardingObjective.Builder createInitFwdObjective(long tunnelId, PortNumber inPort, int nextId) {
1087
1088 TrafficSelector.Builder trafficSelector = DefaultTrafficSelector.builder();
1089
Pier Ventreac3e1d92016-11-17 22:26:29 -08001090 // The flow has to match on the mpls logical
1091 // port and the tunnel id.
1092 trafficSelector.matchTunnelId(tunnelId);
1093 trafficSelector.matchInPort(inPort);
1094
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001095 return DefaultForwardingObjective
1096 .builder()
Ray Milkeyb85de082017-04-05 09:42:04 -07001097 .fromApp(srManager.appId())
Pier Ventreac3e1d92016-11-17 22:26:29 -08001098 .makePermanent()
1099 .nextStep(nextId)
1100 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
1101 .withSelector(trafficSelector.build())
1102 .withFlag(VERSATILE);
Pier Ventref3cf5b92016-11-09 14:17:26 -08001103
1104 }
1105
1106 /**
1107 * Creates the next objective according to a given
1108 * pipeline. We don't set the next id and we don't
1109 * create the final meta to check if we are re-using
1110 * the same next objective for different tunnels.
1111 *
1112 * @param pipeline the pipeline to support
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001113 * @param srcCp the source port
1114 * @param dstCp the destination port
Pier Ventref3cf5b92016-11-09 14:17:26 -08001115 * @param l2Tunnel the tunnel to support
1116 * @param egressId the egress device id
1117 * @return the next objective to support the pipeline
1118 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001119 private NextObjective.Builder createNextObjective(Pipeline pipeline, ConnectPoint srcCp,
1120 ConnectPoint dstCp, DefaultL2Tunnel l2Tunnel,
Pier Ventref3cf5b92016-11-09 14:17:26 -08001121 DeviceId egressId) {
1122 NextObjective.Builder nextObjBuilder;
1123 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
1124 if (pipeline == INITIATION) {
1125 nextObjBuilder = DefaultNextObjective
1126 .builder()
1127 .withType(NextObjective.Type.SIMPLE)
Ray Milkeyb85de082017-04-05 09:42:04 -07001128 .fromApp(srManager.appId());
Pier Ventref3cf5b92016-11-09 14:17:26 -08001129 // The pw label is the bottom of stack. It has to
1130 // be different -1.
1131 if (l2Tunnel.pwLabel().toInt() == MplsLabel.MAX_MPLS) {
1132 log.warn("Pw label not configured");
1133 return null;
1134 }
1135 treatmentBuilder.pushMpls();
1136 treatmentBuilder.setMpls(l2Tunnel.pwLabel());
1137 treatmentBuilder.setMplsBos(true);
1138 treatmentBuilder.copyTtlOut();
1139 // If the inter-co label is present we have to set the label.
1140 if (l2Tunnel.interCoLabel().toInt() != MplsLabel.MAX_MPLS) {
1141 treatmentBuilder.pushMpls();
1142 treatmentBuilder.setMpls(l2Tunnel.interCoLabel());
1143 treatmentBuilder.setMplsBos(false);
1144 treatmentBuilder.copyTtlOut();
1145 }
1146 // We retrieve the sr label from the config
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001147 // specific for pseudowire traffic
Pier Ventref3cf5b92016-11-09 14:17:26 -08001148 // using the egress leaf device id.
1149 MplsLabel srLabel;
1150 try {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001151 srLabel = MplsLabel.mplsLabel(srManager.deviceConfiguration().getPWRoutingLabel(egressId));
1152
Pier Ventref3cf5b92016-11-09 14:17:26 -08001153 } catch (DeviceConfigNotFoundException e) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001154 log.warn("Sr label for pw traffic not configured");
Pier Ventref3cf5b92016-11-09 14:17:26 -08001155 return null;
1156 }
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001157
Pier Ventref3cf5b92016-11-09 14:17:26 -08001158 treatmentBuilder.pushMpls();
1159 treatmentBuilder.setMpls(srLabel);
1160 treatmentBuilder.setMplsBos(false);
1161 treatmentBuilder.copyTtlOut();
1162 // We have to rewrite the src and dst mac address.
1163 MacAddress ingressMac;
1164 try {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001165 ingressMac = srManager.deviceConfiguration().getDeviceMac(srcCp.deviceId());
Pier Ventref3cf5b92016-11-09 14:17:26 -08001166 } catch (DeviceConfigNotFoundException e) {
1167 log.warn("Was not able to find the ingress mac");
1168 return null;
1169 }
1170 treatmentBuilder.setEthSrc(ingressMac);
1171 MacAddress neighborMac;
1172 try {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001173 neighborMac = srManager.deviceConfiguration().getDeviceMac(dstCp.deviceId());
Pier Ventref3cf5b92016-11-09 14:17:26 -08001174 } catch (DeviceConfigNotFoundException e) {
1175 log.warn("Was not able to find the neighbor mac");
1176 return null;
1177 }
1178 treatmentBuilder.setEthDst(neighborMac);
1179 } else {
Pier Ventreac3e1d92016-11-17 22:26:29 -08001180 // We create the next objective which
1181 // will be a simple l2 group.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001182 nextObjBuilder = DefaultNextObjective
1183 .builder()
1184 .withType(NextObjective.Type.SIMPLE)
Ray Milkeyb85de082017-04-05 09:42:04 -07001185 .fromApp(srManager.appId());
Pier Ventref3cf5b92016-11-09 14:17:26 -08001186 }
Pier Ventreac3e1d92016-11-17 22:26:29 -08001187 treatmentBuilder.setOutput(srcCp.port());
Pier Ventref3cf5b92016-11-09 14:17:26 -08001188 nextObjBuilder.addTreatment(treatmentBuilder.build());
1189 return nextObjBuilder;
1190 }
1191
1192 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001193 * Reverses a link.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001194 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001195 * @param link
1196 * @return The reversed link
Pier Ventref3cf5b92016-11-09 14:17:26 -08001197 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001198 private Link reverseLink(Link link) {
1199
1200 DefaultLink.Builder linkBuilder = DefaultLink.builder();
1201
1202 linkBuilder.src(link.dst());
1203 linkBuilder.dst(link.src());
1204 linkBuilder.type(link.type());
1205 linkBuilder.providerId(link.providerId());
1206
1207 return linkBuilder.build();
1208 }
1209
1210 /**
1211 * Returns the path betwwen two connect points.
1212 *
1213 * @param srcCp
1214 * @param dstCp
1215 * @return The path
1216 */
1217 private List<Link> getPath(ConnectPoint srcCp, ConnectPoint dstCp) {
1218
1219 /* We retrieve a set of disjoint paths.
1220 * We perform that in case of a link failure, what happens
1221 * if the PathService gets the link notification AFTER us and
1222 * has not updated the paths?
1223 */
1224 Set<DisjointPath> paths = srManager
1225 .pathService
1226 .getDisjointPaths(srcCp.elementId(), dstCp.elementId());
1227
1228 // We randomly pick a path.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001229 if (paths.isEmpty()) {
1230 return null;
1231 }
1232 int size = paths.size();
1233 int index = RandomUtils.nextInt(0, size);
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001234
1235 return Iterables.get(paths, index).links();
Pier Ventref3cf5b92016-11-09 14:17:26 -08001236 }
1237
1238 /**
Pier Ventref3cf5b92016-11-09 14:17:26 -08001239 * Deletes a given policy using the parameter supplied.
1240 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001241 * @param tunnelId the tunnel id
1242 * @param ingress the ingress point
Pier Ventref3cf5b92016-11-09 14:17:26 -08001243 * @param ingressInner the ingress inner vlan id
1244 * @param ingressOuter the ingress outer vlan id
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001245 * @param future to perform the async operation
1246 * @param direction the direction: forward or reverse
Pier Ventref3cf5b92016-11-09 14:17:26 -08001247 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001248 private void deletePolicy(long tunnelId, ConnectPoint ingress, VlanId ingressInner, VlanId ingressOuter,
1249 VlanId egressVlan, CompletableFuture<ObjectiveError> future, Direction direction) {
1250
Pier Ventreac3e1d92016-11-17 22:26:29 -08001251 String key = generateKey(tunnelId, direction);
1252 if (!l2InitiationNextObjStore.containsKey(key)) {
1253 log.warn("Abort delete of policy for tunnel {}: next does not exist in the store", tunnelId);
1254 if (future != null) {
1255 future.complete(null);
1256 }
1257 return;
1258 }
1259 NextObjective nextObjective = l2InitiationNextObjStore.get(key).value();
1260 int nextId = nextObjective.id();
1261 List<Objective> objectives = Lists.newArrayList();
Pier Ventref3cf5b92016-11-09 14:17:26 -08001262 // We create the forwarding objective.
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001263 ForwardingObjective.Builder fwdBuilder = createInitFwdObjective(tunnelId, ingress.port(), nextId);
Pier Ventref3cf5b92016-11-09 14:17:26 -08001264 ObjectiveContext context = new ObjectiveContext() {
1265 @Override
1266 public void onSuccess(Objective objective) {
Pier Ventreac3e1d92016-11-17 22:26:29 -08001267 log.debug("Previous fwdObj for policy {} removed", tunnelId);
1268 if (future != null) {
1269 future.complete(null);
Pier Ventref3cf5b92016-11-09 14:17:26 -08001270 }
1271 }
1272
1273 @Override
1274 public void onError(Objective objective, ObjectiveError error) {
Pier Ventreac3e1d92016-11-17 22:26:29 -08001275 log.warn("Failed to remove previous fwdObj for policy {}: {}", tunnelId, error);
1276 if (future != null) {
1277 future.complete(error);
Pier Ventref3cf5b92016-11-09 14:17:26 -08001278 }
1279 }
1280 };
1281 objectives.add(fwdBuilder.remove(context));
1282 // We create the filtering objective to define the
1283 // permit traffic in the switch
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001284 FilteringObjective.Builder filtBuilder = createFiltObjective(ingress.port(), ingressInner, ingressOuter);
1285 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
1286 .builder()
1287 .setTunnelId(tunnelId)
1288 .setVlanId(egressVlan);
Pier Ventref3cf5b92016-11-09 14:17:26 -08001289 filtBuilder.withMeta(treatment.build());
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001290 context = new DefaultObjectiveContext((objective) -> log.debug("FilterObj for policy {} revoked", tunnelId),
1291 (objective, error) ->
1292 log.warn("Failed to revoke filterObj for policy {}",
1293 tunnelId, error));
Pier Ventref3cf5b92016-11-09 14:17:26 -08001294 objectives.add(filtBuilder.remove(context));
1295
1296 for (Objective objective : objectives) {
1297 if (objective instanceof ForwardingObjective) {
1298 srManager.flowObjectiveService.forward(ingress.deviceId(), (ForwardingObjective) objective);
1299 } else {
1300 srManager.flowObjectiveService.filter(ingress.deviceId(), (FilteringObjective) objective);
1301 }
1302 }
1303 }
1304
1305 /**
Pier Ventreac3e1d92016-11-17 22:26:29 -08001306 * Deletes the pseudo wire initiation.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001307 *
Pier Ventreac3e1d92016-11-17 22:26:29 -08001308 * @param l2TunnelId the tunnel id
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001309 * @param ingress the ingress connect point
1310 * @param future to perform an async operation
1311 * @param direction the direction: reverse of forward
Pier Ventref3cf5b92016-11-09 14:17:26 -08001312 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001313 private void tearDownPseudoWireInit(long l2TunnelId, ConnectPoint ingress,
1314 CompletableFuture<ObjectiveError> future, Direction direction) {
1315
Pier Ventreac3e1d92016-11-17 22:26:29 -08001316 String key = generateKey(l2TunnelId, direction);
Pier Ventreac3e1d92016-11-17 22:26:29 -08001317 if (!l2InitiationNextObjStore.containsKey(key)) {
1318 log.info("Abort delete of {} for {}: next does not exist in the store", INITIATION, key);
1319 if (future != null) {
1320 future.complete(null);
1321 }
1322 return;
1323 }
1324 NextObjective nextObjective = l2InitiationNextObjStore.get(key).value();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001325 // un-comment in case you want to delete groups used by the pw
1326 // however, this will break the update of pseudowires cause the L2 interface group can
1327 // not be deleted (it is referenced by other groups)
1328 /*
Pier Ventref3cf5b92016-11-09 14:17:26 -08001329 ObjectiveContext context = new ObjectiveContext() {
1330 @Override
1331 public void onSuccess(Objective objective) {
Pier Ventreac3e1d92016-11-17 22:26:29 -08001332 log.debug("Previous {} next for {} removed", INITIATION, key);
1333 if (future != null) {
1334 future.complete(null);
Pier Ventref3cf5b92016-11-09 14:17:26 -08001335 }
1336 }
1337
1338 @Override
1339 public void onError(Objective objective, ObjectiveError error) {
Pier Ventreac3e1d92016-11-17 22:26:29 -08001340 log.warn("Failed to remove previous {} next for {}: {}", INITIATION, key, error);
1341 if (future != null) {
1342 future.complete(error);
Pier Ventref3cf5b92016-11-09 14:17:26 -08001343 }
1344 }
1345 };
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001346 srManager.flowObjectiveService.next(ingress.deviceId(), (NextObjective) nextObjective.copy().remove(context));
1347 */
1348
1349 future.complete(null);
Pier Ventref3cf5b92016-11-09 14:17:26 -08001350 l2InitiationNextObjStore.remove(key);
1351 }
1352
1353 /**
Pier Ventreac3e1d92016-11-17 22:26:29 -08001354 * Deletes the pseudo wire termination.
1355 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001356 * @param l2Tunnel the tunnel
1357 * @param egress the egress connect point
1358 * @param future the async task
Pier Ventreac3e1d92016-11-17 22:26:29 -08001359 * @param direction the direction of the tunnel
1360 */
1361 private void tearDownPseudoWireTerm(DefaultL2Tunnel l2Tunnel,
1362 ConnectPoint egress,
1363 CompletableFuture<ObjectiveError> future,
1364 Direction direction) {
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001365
Pier Ventreac3e1d92016-11-17 22:26:29 -08001366 String key = generateKey(l2Tunnel.tunnelId(), direction);
Pier Ventreac3e1d92016-11-17 22:26:29 -08001367 if (!l2TerminationNextObjStore.containsKey(key)) {
1368 log.info("Abort delete of {} for {}: next does not exist in the store", TERMINATION, key);
1369 if (future != null) {
1370 future.complete(null);
1371 }
1372 return;
1373 }
1374 NextObjective nextObjective = l2TerminationNextObjStore.get(key).value();
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001375 ForwardingObjective.Builder fwdBuilder = createTermFwdObjective(l2Tunnel.pwLabel(),
1376 l2Tunnel.tunnelId(),
1377 egress.port(),
1378 nextObjective.id());
1379 ObjectiveContext context = new DefaultObjectiveContext((objective) -> log.debug("FwdObj for {} {} removed",
1380 TERMINATION,
1381 l2Tunnel.tunnelId()),
1382 (objective, error) ->
1383 log.warn("Failed to remove fwdObj for {} {}",
1384 TERMINATION,
1385 l2Tunnel.tunnelId(),
1386 error));
Pier Ventreac3e1d92016-11-17 22:26:29 -08001387 srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.remove(context));
1388
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001389 // un-comment in case you want to delete groups used by the pw
1390 // however, this will break the update of pseudowires cause the L2 interface group can
1391 // not be deleted (it is referenced by other groups)
1392 /*
Pier Ventreac3e1d92016-11-17 22:26:29 -08001393 context = new ObjectiveContext() {
1394 @Override
1395 public void onSuccess(Objective objective) {
1396 log.debug("Previous {} next for {} removed", TERMINATION, key);
1397 if (future != null) {
1398 future.complete(null);
1399 }
1400 }
1401
1402 @Override
1403 public void onError(Objective objective, ObjectiveError error) {
1404 log.warn("Failed to remove previous {} next for {}: {}", TERMINATION, key, error);
1405 if (future != null) {
1406 future.complete(error);
1407 }
1408 }
1409 };
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001410 srManager.flowObjectiveService.next(egress.deviceId(), (NextObjective) nextObjective.copy().remove(context));
1411 */
1412
1413 future.complete(null);
Pier Ventreac3e1d92016-11-17 22:26:29 -08001414 l2TerminationNextObjStore.remove(key);
1415 }
1416
1417 /**
Pier Ventref3cf5b92016-11-09 14:17:26 -08001418 * Utilities to generate pw key.
1419 *
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001420 * @param tunnelId the tunnel id
Pier Ventref3cf5b92016-11-09 14:17:26 -08001421 * @param direction the direction of the pw
1422 * @return the key of the store
1423 */
Pier Ventreac3e1d92016-11-17 22:26:29 -08001424 private String generateKey(long tunnelId, Direction direction) {
Pier Ventref3cf5b92016-11-09 14:17:26 -08001425 return String.format("%s-%s", tunnelId, direction);
1426 }
1427
1428 /**
Pier Luigi0be3f0f2017-01-30 09:47:36 -08001429 * Pwaas pipelines.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001430 */
1431 protected enum Pipeline {
1432 /**
1433 * The initiation pipeline.
1434 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001435 INITIATION, /**
Pier Ventref3cf5b92016-11-09 14:17:26 -08001436 * The termination pipeline.
1437 */
Pier Ventreac3e1d92016-11-17 22:26:29 -08001438 TERMINATION
Pier Ventref3cf5b92016-11-09 14:17:26 -08001439 }
1440
1441 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001442 * Enum helper to carry results of various operations.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001443 */
1444 public enum Result {
1445 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001446 * Happy ending scenario.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001447 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001448 SUCCESS(0, "No error occurred"),
1449
Pier Ventref3cf5b92016-11-09 14:17:26 -08001450 /**
1451 * We have problems with the supplied parameters.
1452 */
1453 WRONG_PARAMETERS(1, "Wrong parameters"),
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001454
Pier Ventref3cf5b92016-11-09 14:17:26 -08001455 /**
1456 * We have an internal error during the deployment
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001457 * or removal phase.
Pier Ventref3cf5b92016-11-09 14:17:26 -08001458 */
1459 INTERNAL_ERROR(3, "Internal error"),
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001460
Pier Ventref3cf5b92016-11-09 14:17:26 -08001461 /**
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001462 *
Pier Ventref3cf5b92016-11-09 14:17:26 -08001463 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001464 REMOVAL_ERROR(5, "Can not remove pseudowire from network configuration"),
1465
1466 /**
1467 *
1468 */
1469 ADDITION_ERROR(6, "Can not add pseudowire in network configuration"),
1470
1471 /**
1472 *
1473 */
1474 CONFIG_NOT_FOUND(7, "Can not find configuration class for pseudowires");
Pier Ventref3cf5b92016-11-09 14:17:26 -08001475
1476 private final int code;
1477 private final String description;
1478 private int nextId;
1479
Pier Ventreac3e1d92016-11-17 22:26:29 -08001480 Result(int code, String description) {
Pier Ventref3cf5b92016-11-09 14:17:26 -08001481 this.code = code;
1482 this.description = description;
1483 }
1484
1485 public String getDescription() {
1486 return description;
1487 }
1488
Pier Ventref3cf5b92016-11-09 14:17:26 -08001489 @Override
1490 public String toString() {
1491 return code + ": " + description;
1492 }
1493 }
1494
Pier Ventreac3e1d92016-11-17 22:26:29 -08001495 /**
1496 * Enum helper for handling the direction of the pw.
1497 */
1498 public enum Direction {
1499 /**
1500 * The forward direction of the pseudo wire.
1501 */
Andreas Pantelopoulos5e7be3d2017-10-23 12:18:25 -07001502 FWD, /**
Pier Ventreac3e1d92016-11-17 22:26:29 -08001503 * The reverse direction of the pseudo wire.
1504 */
Jon Hall8f867f42017-02-22 13:37:33 -08001505 REV
Pier Ventreac3e1d92016-11-17 22:26:29 -08001506 }
1507
Pier Ventre6b19e482016-11-07 16:21:04 -08001508}