blob: 82061808ffac86e53f583b2e40f36cc25c104309 [file] [log] [blame]
Pier Ventref34966c2016-11-07 16:21:04 -08001/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
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 Ventre42287df2016-11-09 14:17:26 -080019import com.google.common.collect.Iterables;
20import com.google.common.collect.Lists;
21import org.apache.commons.lang3.RandomUtils;
Pier Ventre70d53ba2016-11-17 22:26:29 -080022import org.onlab.packet.Ethernet;
Pier Ventre42287df2016-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;
28import org.onosproject.net.DeviceId;
29import org.onosproject.net.DisjointPath;
30import org.onosproject.net.Link;
31import org.onosproject.net.PortNumber;
Pier Ventref34966c2016-11-07 16:21:04 -080032import org.onosproject.net.config.NetworkConfigEvent;
Pier Ventre42287df2016-11-09 14:17:26 -080033import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficSelector;
36import org.onosproject.net.flow.TrafficTreatment;
37import org.onosproject.net.flow.criteria.Criteria;
38import org.onosproject.net.flowobjective.DefaultFilteringObjective;
39import org.onosproject.net.flowobjective.DefaultForwardingObjective;
40import org.onosproject.net.flowobjective.DefaultNextObjective;
41import org.onosproject.net.flowobjective.DefaultObjectiveContext;
42import org.onosproject.net.flowobjective.FilteringObjective;
43import org.onosproject.net.flowobjective.ForwardingObjective;
44import org.onosproject.net.flowobjective.NextObjective;
45import org.onosproject.net.flowobjective.Objective;
46import org.onosproject.net.flowobjective.ObjectiveContext;
47import org.onosproject.net.flowobjective.ObjectiveError;
Pier Ventref34966c2016-11-07 16:21:04 -080048import org.onosproject.segmentrouting.SegmentRoutingManager;
Pier Ventre42287df2016-11-09 14:17:26 -080049import org.onosproject.segmentrouting.SegmentRoutingService;
50import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
Pier Ventref34966c2016-11-07 16:21:04 -080051import org.onosproject.segmentrouting.config.PwaasConfig;
Pier Ventre42287df2016-11-09 14:17:26 -080052import org.onosproject.store.serializers.KryoNamespaces;
53import org.onosproject.store.service.ConsistentMap;
54import org.onosproject.store.service.Serializer;
Pier Ventref34966c2016-11-07 16:21:04 -080055import org.slf4j.Logger;
56import org.slf4j.LoggerFactory;
57
Pier Ventre42287df2016-11-09 14:17:26 -080058import java.util.List;
59import java.util.Set;
60import java.util.concurrent.CompletableFuture;
61import java.util.stream.Collectors;
62
63import static com.google.common.base.Preconditions.checkState;
64import static org.onosproject.net.flowobjective.ForwardingObjective.Flag.VERSATILE;
65import static org.onosproject.segmentrouting.pwaas.L2Mode.TAGGED;
66import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.INITIATION;
Pier Ventre70d53ba2016-11-17 22:26:29 -080067import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Pipeline.TERMINATION;
Pier Ventre42287df2016-11-09 14:17:26 -080068import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Result.*;
Pier Ventre70d53ba2016-11-17 22:26:29 -080069import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.FWD;
70import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.REV;
Pier Ventre42287df2016-11-09 14:17:26 -080071
Pier Ventref34966c2016-11-07 16:21:04 -080072/**
73 * Handles pwaas related events.
74 */
75public class L2TunnelHandler {
Pier Ventre42287df2016-11-09 14:17:26 -080076
Pier Ventref34966c2016-11-07 16:21:04 -080077 private static final Logger log = LoggerFactory.getLogger(L2TunnelHandler.class);
Pier Ventre70d53ba2016-11-17 22:26:29 -080078 /**
79 * Error message for invalid paths.
80 */
Pier Ventre42287df2016-11-09 14:17:26 -080081 private static final String WRONG_TOPOLOGY = "Path in leaf-spine topology" +
82 " should always be two hops: ";
83
Pier Ventref34966c2016-11-07 16:21:04 -080084 private final SegmentRoutingManager srManager;
Pier Ventre42287df2016-11-09 14:17:26 -080085 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -080086 * To store the next objectives related to the initiation.
87 */
88 private final ConsistentMap<String, NextObjective> l2InitiationNextObjStore;
89 /**
90 * To store the next objectives related to the termination.
91 */
92 private final ConsistentMap<String, NextObjective> l2TerminationNextObjStore;
93 /**
94 * TODO a proper store is necessary to handle the policies, collisions and recovery.
95 * We should have a proper store for the policies and the tunnels. For several reasons:
96 * 1) We should avoid the overlapping of different policies;
97 * 2) We should avoid the overlapping of different tunnels;
98 * 3) We should have a proper mechanism for the protection;
99 * The most important one is 3). At least for 3.0 EA0 was not possible
100 * to remove the bucket, so we need a mapping between policies and tunnel
101 * in order to proper update the fwd objective for the recovery of a fault.
Pier Ventre42287df2016-11-09 14:17:26 -0800102 */
103 private final KryoNamespace.Builder l2TunnelKryo;
104
105 /**
106 * Create a l2 tunnel handler for the deploy and
107 * for the tear down of pseudo wires.
108 *
109 * @param segmentRoutingManager the segment routing manager
110 */
111 public L2TunnelHandler(SegmentRoutingManager segmentRoutingManager) {
112 srManager = segmentRoutingManager;
113 l2TunnelKryo = new KryoNamespace.Builder()
114 .register(KryoNamespaces.API);
115
116 l2InitiationNextObjStore = srManager.storageService
117 .<String, NextObjective>consistentMapBuilder()
118 .withName("onos-l2initiation-nextobj-store")
119 .withSerializer(Serializer.using(l2TunnelKryo.build()))
120 .build();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800121
122 l2TerminationNextObjStore = srManager.storageService
123 .<String, NextObjective>consistentMapBuilder()
124 .withName("onos-l2termination-nextobj-store")
125 .withSerializer(Serializer.using(l2TunnelKryo.build()))
126 .build();
Pier Ventref34966c2016-11-07 16:21:04 -0800127 }
128
129 /**
130 * Processes Pwaas Config added event.
131 *
Pier Ventre42287df2016-11-09 14:17:26 -0800132 * @param event network config add event
Pier Ventref34966c2016-11-07 16:21:04 -0800133 */
134 public void processPwaasConfigAdded(NetworkConfigEvent event) {
135 log.info("Processing Pwaas CONFIG_ADDED");
136 PwaasConfig config = (PwaasConfig) event.config().get();
Pier Ventre42287df2016-11-09 14:17:26 -0800137 Set<DefaultL2TunnelDescription> pwToAdd = config.getPwIds()
138 .stream()
139 .map(config::getPwDescription)
140 .collect(Collectors.toSet());
141 // We deploy all the pseudo wire deployed
142 deploy(pwToAdd);
143 }
144
Pier Ventre70d53ba2016-11-17 22:26:29 -0800145 /**
146 * To deploy a number of pseudo wires.
147 *
148 * @param pwToAdd the set of pseudo wires to add
149 */
Pier Ventre42287df2016-11-09 14:17:26 -0800150 private void deploy(Set<DefaultL2TunnelDescription> pwToAdd) {
151 Result result;
152 long l2TunnelId;
153 for (DefaultL2TunnelDescription currentL2Tunnel : pwToAdd) {
154 l2TunnelId = currentL2Tunnel.l2Tunnel().tunnelId();
155 // The tunnel id cannot be 0.
156 if (l2TunnelId == 0) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800157 log.warn("Tunnel id id must be > 0");
Pier Ventre42287df2016-11-09 14:17:26 -0800158 continue;
159 }
160 // We do a sanity check of the pseudo wire.
161 result = verifyPseudoWire(currentL2Tunnel);
162 if (result != SUCCESS) {
163 continue;
164 }
165 // We establish the tunnel.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800166 result = deployPseudoWireInit(
Pier Ventre42287df2016-11-09 14:17:26 -0800167 currentL2Tunnel.l2Tunnel(),
168 currentL2Tunnel.l2TunnelPolicy().cP1(),
169 currentL2Tunnel.l2TunnelPolicy().cP2(),
170 FWD
171 );
172 if (result != SUCCESS) {
173 continue;
174 }
175 // We create the policy.
176 result = deployPolicy(
177 l2TunnelId,
178 currentL2Tunnel.l2TunnelPolicy().cP1(),
179 currentL2Tunnel.l2TunnelPolicy().cP1InnerTag(),
180 currentL2Tunnel.l2TunnelPolicy().cP1OuterTag(),
181 result.nextId
182 );
183 if (result != SUCCESS) {
184 continue;
185 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800186 // We terminate the tunnel
187 result = deployPseudoWireTerm(
188 currentL2Tunnel.l2Tunnel(),
189 currentL2Tunnel.l2TunnelPolicy().cP2(),
190 currentL2Tunnel.l2TunnelPolicy().cP2OuterTag(),
191 FWD
192 );
193 if (result != SUCCESS) {
194 continue;
195 }
Pier Ventre42287df2016-11-09 14:17:26 -0800196 // We establish the reverse tunnel.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800197 result = deployPseudoWireInit(
Pier Ventre42287df2016-11-09 14:17:26 -0800198 currentL2Tunnel.l2Tunnel(),
199 currentL2Tunnel.l2TunnelPolicy().cP2(),
200 currentL2Tunnel.l2TunnelPolicy().cP1(),
201 REV
202 );
203 if (result != SUCCESS) {
204 continue;
205 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800206 result = deployPolicy(
Pier Ventre42287df2016-11-09 14:17:26 -0800207 l2TunnelId,
208 currentL2Tunnel.l2TunnelPolicy().cP2(),
209 currentL2Tunnel.l2TunnelPolicy().cP2InnerTag(),
210 currentL2Tunnel.l2TunnelPolicy().cP2OuterTag(),
211 result.nextId
212 );
Pier Ventre70d53ba2016-11-17 22:26:29 -0800213 if (result != SUCCESS) {
214 continue;
215 }
216 deployPseudoWireTerm(
217 currentL2Tunnel.l2Tunnel(),
218 currentL2Tunnel.l2TunnelPolicy().cP1(),
219 currentL2Tunnel.l2TunnelPolicy().cP1OuterTag(),
220 REV
221 );
Pier Ventre42287df2016-11-09 14:17:26 -0800222 }
Pier Ventref34966c2016-11-07 16:21:04 -0800223 }
224
225 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -0800226 * Processes PWaaS Config updated event.
Pier Ventref34966c2016-11-07 16:21:04 -0800227 *
228 * @param event network config updated event
229 */
230 public void processPwaasConfigUpdated(NetworkConfigEvent event) {
231 log.info("Processing Pwaas CONFIG_UPDATED");
Pier Ventre42287df2016-11-09 14:17:26 -0800232 // We retrieve the old pseudo wires.
233 PwaasConfig prevConfig = (PwaasConfig) event.prevConfig().get();
234 Set<Long> prevPws = prevConfig.getPwIds();
235 // We retrieve the new pseudo wires.
Pier Ventref34966c2016-11-07 16:21:04 -0800236 PwaasConfig config = (PwaasConfig) event.config().get();
Pier Ventre42287df2016-11-09 14:17:26 -0800237 Set<Long> newPws = config.getPwIds();
238 // We compute the pseudo wires to update.
239 Set<Long> updPws = newPws.stream()
240 .filter(tunnelId -> prevPws.contains(tunnelId) &&
241 !config.getPwDescription(tunnelId).equals(prevConfig.getPwDescription(tunnelId)))
242 .collect(Collectors.toSet());
243 // The pseudo wires to remove.
244 Set<DefaultL2TunnelDescription> pwToRemove = prevPws.stream()
245 .filter(tunnelId -> !newPws.contains(tunnelId))
246 .map(prevConfig::getPwDescription)
247 .collect(Collectors.toSet());
248 tearDown(pwToRemove);
249 // The pseudo wires to add.
250 Set<DefaultL2TunnelDescription> pwToAdd = newPws.stream()
251 .filter(tunnelId -> !prevPws.contains(tunnelId))
252 .map(config::getPwDescription)
253 .collect(Collectors.toSet());
254 deploy(pwToAdd);
255 // The pseudo wires to update.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800256 updPws.forEach(tunnelId -> updatePw(
257 prevConfig.getPwDescription(tunnelId),
258 config.getPwDescription(tunnelId))
259 );
Pier Ventre42287df2016-11-09 14:17:26 -0800260 }
261
262 /**
263 * Helper function to update a pw.
264 *
265 * @param oldPw the pseudo wire to remove
266 * @param newPw the pseudo wirte to add
267 */
268 private void updatePw(DefaultL2TunnelDescription oldPw,
269 DefaultL2TunnelDescription newPw) {
Pier Ventre42287df2016-11-09 14:17:26 -0800270 long tunnelId = oldPw.l2Tunnel().tunnelId();
Pier Ventre42287df2016-11-09 14:17:26 -0800271 // The async tasks to orchestrate the next and
272 // forwarding update.
Pier Ventre42287df2016-11-09 14:17:26 -0800273 CompletableFuture<ObjectiveError> fwdInitNextFuture = new CompletableFuture<>();
274 CompletableFuture<ObjectiveError> revInitNextFuture = new CompletableFuture<>();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800275 CompletableFuture<ObjectiveError> fwdTermNextFuture = new CompletableFuture<>();
276 CompletableFuture<ObjectiveError> revTermNextFuture = new CompletableFuture<>();
277 CompletableFuture<ObjectiveError> fwdPwFuture = new CompletableFuture<>();
278 CompletableFuture<ObjectiveError> revPwFuture = new CompletableFuture<>();
Pier Ventre42287df2016-11-09 14:17:26 -0800279
Pier Ventre70d53ba2016-11-17 22:26:29 -0800280
281 Result result = verifyPseudoWire(newPw);
Pier Ventre42287df2016-11-09 14:17:26 -0800282 if (result != SUCCESS) {
283 return;
284 }
Pier Ventre42287df2016-11-09 14:17:26 -0800285 // First we remove both policy.
Pier Ventre42287df2016-11-09 14:17:26 -0800286 log.debug("Start deleting fwd policy for {}", tunnelId);
287 deletePolicy(
288 tunnelId,
289 oldPw.l2TunnelPolicy().cP1(),
290 oldPw.l2TunnelPolicy().cP1InnerTag(),
291 oldPw.l2TunnelPolicy().cP1OuterTag(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800292 fwdInitNextFuture,
293 FWD
Pier Ventre42287df2016-11-09 14:17:26 -0800294 );
Pier Ventre70d53ba2016-11-17 22:26:29 -0800295 log.debug("Start deleting rev policy for {}", tunnelId);
296 deletePolicy(
297 tunnelId,
298 oldPw.l2TunnelPolicy().cP2(),
299 oldPw.l2TunnelPolicy().cP2InnerTag(),
300 oldPw.l2TunnelPolicy().cP2OuterTag(),
301 revInitNextFuture,
302 REV
303 );
Pier Ventre42287df2016-11-09 14:17:26 -0800304 // Finally we remove both the tunnels.
305 fwdInitNextFuture.thenAcceptAsync(status -> {
306 if (status == null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800307 log.debug("Fwd policy removed. Now remove fwd {} for {}", INITIATION, tunnelId);
308 tearDownPseudoWireInit(
309 tunnelId,
Pier Ventre42287df2016-11-09 14:17:26 -0800310 oldPw.l2TunnelPolicy().cP1(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800311 fwdTermNextFuture,
312 FWD
Pier Ventre42287df2016-11-09 14:17:26 -0800313 );
314 }
315 });
316 revInitNextFuture.thenAcceptAsync(status -> {
317 if (status == null) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800318 log.debug("Rev policy removed. Now remove rev {} for {}", INITIATION, tunnelId);
319 tearDownPseudoWireInit(
320 tunnelId,
Pier Ventre42287df2016-11-09 14:17:26 -0800321 oldPw.l2TunnelPolicy().cP2(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800322 revTermNextFuture,
323 REV
Pier Ventre42287df2016-11-09 14:17:26 -0800324 );
325
326 }
327 });
Pier Ventre70d53ba2016-11-17 22:26:29 -0800328 fwdTermNextFuture.thenAcceptAsync(status -> {
329 if (status == null) {
330 log.debug("Fwd {} removed. Now remove fwd {} for {}", INITIATION, TERMINATION, tunnelId);
331 tearDownPseudoWireTerm(
332 oldPw.l2Tunnel(),
333 oldPw.l2TunnelPolicy().cP2(),
334 fwdPwFuture,
335 FWD
336 );
337 }
338 });
339 revTermNextFuture.thenAcceptAsync(status -> {
340 if (status == null) {
341 log.debug("Rev {} removed. Now remove rev {} for {}", INITIATION, TERMINATION, tunnelId);
342 tearDownPseudoWireTerm(
343 oldPw.l2Tunnel(),
344 oldPw.l2TunnelPolicy().cP1(),
345 revPwFuture,
346 REV
347 );
348 }
349 });
Pier Ventre42287df2016-11-09 14:17:26 -0800350 // At the end we install the new pw.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800351 fwdPwFuture.thenAcceptAsync(status -> {
Pier Ventre42287df2016-11-09 14:17:26 -0800352 if (status == null) {
353 log.debug("Deploying new fwd pw for {}", tunnelId);
Pier Ventre70d53ba2016-11-17 22:26:29 -0800354 Result lamdaResult = deployPseudoWireInit(
Pier Ventre42287df2016-11-09 14:17:26 -0800355 newPw.l2Tunnel(),
356 newPw.l2TunnelPolicy().cP1(),
357 newPw.l2TunnelPolicy().cP2(),
358 FWD
359 );
360 if (lamdaResult != SUCCESS) {
361 return;
362 }
363 lamdaResult = deployPolicy(
364 tunnelId,
365 newPw.l2TunnelPolicy().cP1(),
366 newPw.l2TunnelPolicy().cP1InnerTag(),
367 newPw.l2TunnelPolicy().cP1OuterTag(),
368 lamdaResult.nextId
369 );
Pier Ventre70d53ba2016-11-17 22:26:29 -0800370 if (lamdaResult != SUCCESS) {
371 return;
372 }
373 deployPseudoWireTerm(
374 newPw.l2Tunnel(),
375 newPw.l2TunnelPolicy().cP2(),
376 newPw.l2TunnelPolicy().cP2OuterTag(),
377 FWD
378 );
379
380 }
381 });
382 revPwFuture.thenAcceptAsync(status -> {
383 if (status == null) {
Pier Ventre42287df2016-11-09 14:17:26 -0800384 log.debug("Deploying new rev pw for {}", tunnelId);
Pier Ventre70d53ba2016-11-17 22:26:29 -0800385 Result lamdaResult = deployPseudoWireInit(
Pier Ventre42287df2016-11-09 14:17:26 -0800386 newPw.l2Tunnel(),
387 newPw.l2TunnelPolicy().cP2(),
388 newPw.l2TunnelPolicy().cP1(),
389 REV
390 );
391 if (lamdaResult != SUCCESS) {
392 return;
393 }
394 lamdaResult = deployPolicy(
395 tunnelId,
396 newPw.l2TunnelPolicy().cP2(),
397 newPw.l2TunnelPolicy().cP2InnerTag(),
398 newPw.l2TunnelPolicy().cP2OuterTag(),
399 lamdaResult.nextId
400 );
Pier Ventre70d53ba2016-11-17 22:26:29 -0800401 if (lamdaResult != SUCCESS) {
402 return;
403 }
404 deployPseudoWireTerm(
405 newPw.l2Tunnel(),
406 newPw.l2TunnelPolicy().cP1(),
407 newPw.l2TunnelPolicy().cP1OuterTag(),
408 REV
409 );
Pier Ventre42287df2016-11-09 14:17:26 -0800410 }
Pier Ventref34966c2016-11-07 16:21:04 -0800411 });
412 }
413
414 /**
415 * Processes Pwaas Config removed event.
416 *
417 * @param event network config removed event
418 */
419 public void processPwaasConfigRemoved(NetworkConfigEvent event) {
420 log.info("Processing Pwaas CONFIG_REMOVED");
Pier Ventre42287df2016-11-09 14:17:26 -0800421 PwaasConfig config = (PwaasConfig) event.prevConfig().get();
422 Set<DefaultL2TunnelDescription> pwToRemove = config.getPwIds()
423 .stream()
424 .map(config::getPwDescription)
425 .collect(Collectors.toSet());
426 // We teardown all the pseudo wire deployed
427 tearDown(pwToRemove);
Pier Ventref34966c2016-11-07 16:21:04 -0800428 }
Pier Ventre42287df2016-11-09 14:17:26 -0800429
430 /**
431 * Helper function to handle the pw removal.
432 *
433 * @param pwToRemove the pseudo wires to remove
434 */
435 private void tearDown(Set<DefaultL2TunnelDescription> pwToRemove) {
436 Result result;
Pier Ventre42287df2016-11-09 14:17:26 -0800437 long l2TunnelId;
Pier Ventre70d53ba2016-11-17 22:26:29 -0800438 // We remove all the pw in the configuration file.
Pier Ventre42287df2016-11-09 14:17:26 -0800439 for (DefaultL2TunnelDescription currentL2Tunnel : pwToRemove) {
440 l2TunnelId = currentL2Tunnel.l2Tunnel().tunnelId();
441 if (l2TunnelId == 0) {
442 log.warn("Tunnel id cannot be 0");
443 continue;
444 }
445 result = verifyPseudoWire(currentL2Tunnel);
446 if (result != SUCCESS) {
447 continue;
448 }
Pier Ventre42287df2016-11-09 14:17:26 -0800449 // First all we have to delete the policy.
450 deletePolicy(
451 l2TunnelId,
452 currentL2Tunnel.l2TunnelPolicy().cP1(),
453 currentL2Tunnel.l2TunnelPolicy().cP1InnerTag(),
454 currentL2Tunnel.l2TunnelPolicy().cP1OuterTag(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800455 null,
456 FWD
Pier Ventre42287df2016-11-09 14:17:26 -0800457 );
458 // Finally we will tear down the pseudo wire.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800459 tearDownPseudoWireInit(
460 l2TunnelId,
Pier Ventre42287df2016-11-09 14:17:26 -0800461 currentL2Tunnel.l2TunnelPolicy().cP1(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800462 null,
463 FWD
464 );
465 tearDownPseudoWireTerm(
466 currentL2Tunnel.l2Tunnel(),
Pier Ventre42287df2016-11-09 14:17:26 -0800467 currentL2Tunnel.l2TunnelPolicy().cP2(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800468 null,
469 FWD
Pier Ventre42287df2016-11-09 14:17:26 -0800470 );
471 // We do the same operations on the reverse side.
Pier Ventre42287df2016-11-09 14:17:26 -0800472 deletePolicy(
473 l2TunnelId,
474 currentL2Tunnel.l2TunnelPolicy().cP2(),
475 currentL2Tunnel.l2TunnelPolicy().cP2InnerTag(),
476 currentL2Tunnel.l2TunnelPolicy().cP2OuterTag(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800477 null,
478 REV
Pier Ventre42287df2016-11-09 14:17:26 -0800479 );
Pier Ventre70d53ba2016-11-17 22:26:29 -0800480 tearDownPseudoWireInit(
481 l2TunnelId,
Pier Ventre42287df2016-11-09 14:17:26 -0800482 currentL2Tunnel.l2TunnelPolicy().cP2(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800483 null,
484 REV
485 );
486 tearDownPseudoWireTerm(
487 currentL2Tunnel.l2Tunnel(),
Pier Ventre42287df2016-11-09 14:17:26 -0800488 currentL2Tunnel.l2TunnelPolicy().cP1(),
Pier Ventre70d53ba2016-11-17 22:26:29 -0800489 null,
490 REV
Pier Ventre42287df2016-11-09 14:17:26 -0800491 );
492 }
493
494 }
495
496 /**
497 * Helper method to verify the integrity of the pseudo wire.
498 *
499 * @param l2TunnelDescription the pseudo wire description
500 * @return the result of the check
501 */
502 private Result verifyPseudoWire(DefaultL2TunnelDescription l2TunnelDescription) {
503 Result result;
504 DefaultL2Tunnel l2Tunnel = l2TunnelDescription.l2Tunnel();
505 DefaultL2TunnelPolicy l2TunnelPolicy = l2TunnelDescription.l2TunnelPolicy();
506 result = verifyTunnel(l2Tunnel);
507 if (result != SUCCESS) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800508 log.warn("Tunnel {}: did not pass the validation", l2Tunnel.tunnelId());
Pier Ventre42287df2016-11-09 14:17:26 -0800509 return result;
510 }
511 result = verifyPolicy(
512 l2TunnelPolicy.isAllVlan(),
513 l2TunnelPolicy.cP1InnerTag(),
514 l2TunnelPolicy.cP1OuterTag(),
515 l2TunnelPolicy.cP2InnerTag(),
516 l2TunnelPolicy.cP2OuterTag()
517 );
518 if (result != SUCCESS) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800519 log.warn("Policy for tunnel {}: did not pass the validation", l2Tunnel.tunnelId());
Pier Ventre42287df2016-11-09 14:17:26 -0800520 return result;
521 }
522
523 return SUCCESS;
524 }
525
526 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800527 * Handles the policy establishment which consists in
528 * create the filtering and forwarding objectives related
529 * to the initiation and termination.
530 *
531 * @param tunnelId the tunnel id
532 * @param ingress the ingress point
533 * @param ingressInner the ingress inner tag
534 * @param ingressOuter the ingress outer tag
535 * @param nextId the next objective id
Pier Ventre70d53ba2016-11-17 22:26:29 -0800536 * @return the result of the operation
Pier Ventre42287df2016-11-09 14:17:26 -0800537 */
538 private Result deployPolicy(long tunnelId,
539 ConnectPoint ingress,
540 VlanId ingressInner,
541 VlanId ingressOuter,
542 int nextId) {
Pier Ventre42287df2016-11-09 14:17:26 -0800543 if (!srManager.mastershipService.isLocalMaster(ingress.deviceId())) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800544 log.info("Abort creation of policy for tunnel {}: I am not the master", tunnelId);
Pier Ventre42287df2016-11-09 14:17:26 -0800545 return SUCCESS;
546 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800547 List<Objective> objectives = Lists.newArrayList();
Pier Ventre42287df2016-11-09 14:17:26 -0800548 // We create the forwarding objective for supporting
549 // the l2 tunnel.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800550 ForwardingObjective.Builder fwdBuilder = createInitFwdObjective(
Pier Ventre42287df2016-11-09 14:17:26 -0800551 tunnelId,
552 ingress.port(),
553 nextId
554 );
555 // We create and add objective context.
556 ObjectiveContext context = new DefaultObjectiveContext(
557 (objective)
558 -> log.debug("FwdObj for tunnel {} populated", tunnelId),
559 (objective, error)
560 -> log.warn("Failed to populate fwdrObj for tunnel {}", tunnelId, error));
561 objectives.add(fwdBuilder.add(context));
562 // We create the filtering objective to define the
563 // permit traffic in the switch
Pier Ventre70d53ba2016-11-17 22:26:29 -0800564 FilteringObjective.Builder filtBuilder = createFiltObjective(
Pier Ventre42287df2016-11-09 14:17:26 -0800565 ingress.port(),
566 ingressInner,
567 ingressOuter
568 );
569 // We add the metadata.
570 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
571 .setTunnelId(tunnelId);
572 filtBuilder.withMeta(treatment.build());
573 // We create and add objective context.
574 context = new DefaultObjectiveContext(
575 (objective)
576 -> log.debug("FilterObj for tunnel {} populated", tunnelId),
577 (objective, error)
578 -> log.warn("Failed to populate filterObj for tunnel {}", tunnelId, error));
579 objectives.add(filtBuilder.add(context));
580
581 for (Objective objective : objectives) {
582 if (objective instanceof ForwardingObjective) {
583 srManager.flowObjectiveService.forward(ingress.deviceId(), (ForwardingObjective) objective);
Pier Ventre70d53ba2016-11-17 22:26:29 -0800584 log.debug("Creating new FwdObj for initiation NextObj with id={} for tunnel {}", nextId, tunnelId);
Pier Ventre42287df2016-11-09 14:17:26 -0800585 } else {
586 srManager.flowObjectiveService.filter(ingress.deviceId(), (FilteringObjective) objective);
587 log.debug("Creating new FiltObj for tunnel {}", tunnelId);
588 }
589 }
590 return SUCCESS;
591 }
592
593 /**
594 * Helper method to verify if the policy is whether or not
595 * supported.
596 *
597 * @param isAllVlan all vlan mode
598 * @param ingressInner the ingress inner tag
599 * @param ingressOuter the ingress outer tag
600 * @param egressInner the egress inner tag
601 * @param egressOuter the egress outer tag
602 * @return the result of verification
603 */
604 private Result verifyPolicy(boolean isAllVlan,
605 VlanId ingressInner,
606 VlanId ingressOuter,
607 VlanId egressInner,
608 VlanId egressOuter) {
609 // AllVlan mode is not supported yet.
610 if (isAllVlan) {
611 log.warn("AllVlan not supported yet");
612 return UNSUPPORTED;
613 }
614 // The vlan tags for cP1 and cP2 have to be different from
615 // vlan none.
616 if (ingressInner.equals(VlanId.NONE) ||
617 ingressOuter.equals(VlanId.NONE) ||
618 egressInner.equals(VlanId.NONE) ||
619 egressOuter.equals(VlanId.NONE)) {
620 log.warn("The vlan tags for the connect point have to be" +
621 "different from vlan none");
622 return WRONG_PARAMETERS;
623 }
624 return SUCCESS;
625 }
626
627 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800628 * Handles the tunnel establishment which consists in
Pier Ventre70d53ba2016-11-17 22:26:29 -0800629 * create the next objectives related to the initiation.
Pier Ventre42287df2016-11-09 14:17:26 -0800630 *
631 * @param l2Tunnel the tunnel to deploy
632 * @param ingress the ingress connect point
633 * @param egress the egress connect point
634 * @param direction the direction of the pw
Pier Ventre70d53ba2016-11-17 22:26:29 -0800635 * @return the result of the operation
Pier Ventre42287df2016-11-09 14:17:26 -0800636 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800637 private Result deployPseudoWireInit(DefaultL2Tunnel l2Tunnel,
638 ConnectPoint ingress,
639 ConnectPoint egress,
640 Direction direction) {
Pier Ventre42287df2016-11-09 14:17:26 -0800641 if (!srManager.mastershipService.isLocalMaster(ingress.deviceId())) {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800642 log.info("Abort initiation of tunnel {}: I am not the master", l2Tunnel.tunnelId());
Pier Ventre42287df2016-11-09 14:17:26 -0800643 return SUCCESS;
644 }
645 // We need at least a path between ingress and egress.
Pier Ventre70d53ba2016-11-17 22:26:29 -0800646 Link nextHop = getNextHop(ingress, egress);
Pier Ventre42287df2016-11-09 14:17:26 -0800647 if (nextHop == null) {
648 log.warn("No path between ingress and egress");
649 return WRONG_PARAMETERS;
650 }
651 // We create the next objective without the metadata
652 // context and id. We check if it already exists in the
Pier Ventre70d53ba2016-11-17 22:26:29 -0800653 // store. If not we store as it is in the store.
654 NextObjective.Builder nextObjectiveBuilder = createNextObjective(
Pier Ventre42287df2016-11-09 14:17:26 -0800655 INITIATION,
Pier Ventre70d53ba2016-11-17 22:26:29 -0800656 nextHop.src(),
657 nextHop.dst(),
Pier Ventre42287df2016-11-09 14:17:26 -0800658 l2Tunnel,
659 egress.deviceId()
660 );
661 if (nextObjectiveBuilder == null) {
662 return INTERNAL_ERROR;
663 }
664 // We set the metadata. We will use this metadata
665 // to inform the driver we are doing a l2 tunnel.
666 TrafficSelector metadata = DefaultTrafficSelector
667 .builder()
668 .matchTunnelId(l2Tunnel.tunnelId())
669 .build();
670 nextObjectiveBuilder.withMeta(metadata);
Pier Ventre70d53ba2016-11-17 22:26:29 -0800671 int nextId = srManager.flowObjectiveService.allocateNextId();
Pier Ventre42287df2016-11-09 14:17:26 -0800672 if (nextId < 0) {
673 log.warn("Not able to allocate a next id for initiation");
674 return INTERNAL_ERROR;
675 }
676 nextObjectiveBuilder.withId(nextId);
677 String key = generateKey(l2Tunnel.tunnelId(), direction);
678 l2InitiationNextObjStore.put(key, nextObjectiveBuilder.add());
679 ObjectiveContext context = new DefaultObjectiveContext(
680 (objective)
681 -> log.debug("Initiation l2 tunnel rule for {} populated",
682 l2Tunnel.tunnelId()),
683 (objective, error)
684 -> log.warn("Failed to populate Initiation l2 tunnel rule for {}: {}",
685 l2Tunnel.tunnelId(), error));
Pier Ventre70d53ba2016-11-17 22:26:29 -0800686 NextObjective nextObjective = nextObjectiveBuilder.add(context);
Pier Ventre42287df2016-11-09 14:17:26 -0800687 srManager.flowObjectiveService.next(ingress.deviceId(), nextObjective);
688 log.debug("Initiation next objective for {} not found. Creating new NextObj with id={}",
689 l2Tunnel.tunnelId(),
690 nextObjective.id()
691 );
Pier Ventre70d53ba2016-11-17 22:26:29 -0800692 Result result = SUCCESS;
Pier Ventre42287df2016-11-09 14:17:26 -0800693 result.nextId = nextObjective.id();
694 return result;
695 }
696
697 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -0800698 * Handles the tunnel termination, which consists in the creation
699 * of a forwarding objective and a next objective.
700 *
701 * @param l2Tunnel the tunnel to terminate
702 * @param egress the egress point
703 * @param egressVlan the expected vlan at egress
704 * @param direction the direction
705 * @return the result of the operation
706 */
707 private Result deployPseudoWireTerm(DefaultL2Tunnel l2Tunnel,
708 ConnectPoint egress,
709 VlanId egressVlan,
710 Direction direction) {
711 // We create the group relative to the termination.
712 // It's fine to abort the termination if we are
713 // not the master.
714 if (!srManager.mastershipService.isLocalMaster(egress.deviceId())) {
715 log.info("Abort termination of tunnel {}: I am not the master", l2Tunnel.tunnelId());
716 return SUCCESS;
717 }
718 NextObjective.Builder nextObjectiveBuilder = createNextObjective(
719 TERMINATION,
720 egress,
721 null,
722 null,
723 egress.deviceId()
724 );
725 if (nextObjectiveBuilder == null) {
726 return INTERNAL_ERROR;
727 }
728 TrafficSelector metadata = DefaultTrafficSelector
729 .builder()
730 .matchVlanId(egressVlan)
731 .build();
732 nextObjectiveBuilder.withMeta(metadata);
733 int nextId = srManager.flowObjectiveService.allocateNextId();
734 if (nextId < 0) {
735 log.warn("Not able to allocate a next id for initiation");
736 return INTERNAL_ERROR;
737 }
738 nextObjectiveBuilder.withId(nextId);
739 String key = generateKey(l2Tunnel.tunnelId(), direction);
740 l2TerminationNextObjStore.put(key, nextObjectiveBuilder.add());
741 ObjectiveContext context = new DefaultObjectiveContext(
742 (objective)
743 -> log.debug("Termination l2 tunnel rule for {} populated",
744 l2Tunnel.tunnelId()),
745 (objective, error)
746 -> log.warn("Failed to populate termination l2 tunnel rule for {}: {}",
747 l2Tunnel.tunnelId(), error));
748 NextObjective nextObjective = nextObjectiveBuilder.add(context);
749 srManager.flowObjectiveService.next(egress.deviceId(), nextObjective);
750 log.debug("Termination next objective for {} not found. Creating new NextObj with id={}",
751 l2Tunnel.tunnelId(),
752 nextObjective.id()
753 );
754 // We create the flow relative to the termination.
755 ForwardingObjective.Builder fwdBuilder = createTermFwdObjective(
756 l2Tunnel.pwLabel(),
757 l2Tunnel.tunnelId(),
758 egress.port(),
759 nextObjective.id()
760 );
761 context = new DefaultObjectiveContext(
762 (objective)
763 -> log.debug("FwdObj for tunnel termination {} populated",
764 l2Tunnel.tunnelId()),
765 (objective, error)
766 -> log.warn("Failed to populate fwdrObj for tunnel termination {}",
767 l2Tunnel.tunnelId(), error));
768 srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.add(context));
769 log.debug("Creating new FwdObj for termination NextObj with id={} for tunnel {}", nextId, l2Tunnel.tunnelId());
770 return SUCCESS;
771
772 }
773
774 /**
Pier Ventre42287df2016-11-09 14:17:26 -0800775 * Helper method to verify if the tunnel is whether or not
776 * supported.
777 *
778 * @param l2Tunnel the tunnel to verify
779 * @return the result of the verification
780 */
781 private Result verifyTunnel(DefaultL2Tunnel l2Tunnel) {
782 // Service delimiting tag not supported yet.
783 if (!l2Tunnel.sdTag().equals(VlanId.NONE)) {
784 log.warn("Service delimiting tag not supported yet");
785 return UNSUPPORTED;
786 }
787 // Tag mode not supported yet.
788 if (l2Tunnel.pwMode() == TAGGED) {
789 log.warn("Tagged mode not supported yet");
790 return UNSUPPORTED;
791 }
792 // Raw mode without service delimiting tag
793 // is the only mode supported for now.
794 return SUCCESS;
795 }
796
797 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -0800798 * Creates the filtering objective according to a given policy.
Pier Ventre42287df2016-11-09 14:17:26 -0800799 *
800 * @param inPort the in port
801 * @param innerTag the inner vlan tag
802 * @param outerTag the outer vlan tag
803 * @return the filtering objective
804 */
805 private FilteringObjective.Builder createFiltObjective(PortNumber inPort,
806 VlanId innerTag,
807 VlanId outerTag) {
808 return DefaultFilteringObjective.builder()
809 .withKey(Criteria.matchInPort(inPort))
810 .addCondition(Criteria.matchInnerVlanId(innerTag))
811 .addCondition(Criteria.matchVlanId(outerTag))
812 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
813 .permit()
814 .fromApp(srManager.appId);
815 }
816
817 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -0800818 * Creates the forwarding objective for the termination.
Pier Ventre42287df2016-11-09 14:17:26 -0800819 *
Pier Ventre70d53ba2016-11-17 22:26:29 -0800820 * @param pwLabel the pseudo wire label
Pier Ventre42287df2016-11-09 14:17:26 -0800821 * @param tunnelId the tunnel id
Pier Ventre70d53ba2016-11-17 22:26:29 -0800822 * @param egressPort the egress port
Pier Ventre42287df2016-11-09 14:17:26 -0800823 * @param nextId the next step
Pier Ventre70d53ba2016-11-17 22:26:29 -0800824 * @return the forwarding objective to support the termination
Pier Ventre42287df2016-11-09 14:17:26 -0800825 */
Pier Ventre70d53ba2016-11-17 22:26:29 -0800826 private ForwardingObjective.Builder createTermFwdObjective(MplsLabel pwLabel,
827 long tunnelId,
828 PortNumber egressPort,
829 int nextId) {
Pier Ventre42287df2016-11-09 14:17:26 -0800830 TrafficSelector.Builder trafficSelector = DefaultTrafficSelector
831 .builder();
Pier Ventre70d53ba2016-11-17 22:26:29 -0800832 TrafficTreatment.Builder trafficTreatment = DefaultTrafficTreatment
833 .builder();
834 // The flow has to match on the pw label and bos
835 trafficSelector.matchEthType(Ethernet.MPLS_UNICAST);
836 trafficSelector.matchMplsLabel(pwLabel);
837 trafficSelector.matchMplsBos(true);
838 // The flow has to decrement ttl, restore ttl in
839 // pop mpls, set tunnel id and port.
840 trafficTreatment.decMplsTtl();
841 trafficTreatment.copyTtlIn();
842 trafficTreatment.popMpls();
843 trafficTreatment.setTunnelId(tunnelId);
844 trafficTreatment.setOutput(egressPort);
845
846 return DefaultForwardingObjective.builder()
847 .fromApp(srManager.appId)
848 .makePermanent()
849 .nextStep(nextId)
850 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
851 .withSelector(trafficSelector.build())
852 .withTreatment(trafficTreatment.build())
853 .withFlag(VERSATILE);
854 }
855
856 /**
857 * Creates the forwarding objective for the initiation.
858 *
859 * @param tunnelId the tunnel id
860 * @param inPort the input port
861 * @param nextId the next step
862 * @return the forwarding objective to support the initiation.
863 */
864 private ForwardingObjective.Builder createInitFwdObjective(long tunnelId,
865 PortNumber inPort,
866 int nextId) {
867 TrafficSelector.Builder trafficSelector = DefaultTrafficSelector
868 .builder();
869 // The flow has to match on the mpls logical
870 // port and the tunnel id.
871 trafficSelector.matchTunnelId(tunnelId);
872 trafficSelector.matchInPort(inPort);
873
874 return DefaultForwardingObjective.builder()
875 .fromApp(srManager.appId)
876 .makePermanent()
877 .nextStep(nextId)
878 .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
879 .withSelector(trafficSelector.build())
880 .withFlag(VERSATILE);
Pier Ventre42287df2016-11-09 14:17:26 -0800881
882 }
883
884 /**
885 * Creates the next objective according to a given
886 * pipeline. We don't set the next id and we don't
887 * create the final meta to check if we are re-using
888 * the same next objective for different tunnels.
889 *
890 * @param pipeline the pipeline to support
Pier Ventre70d53ba2016-11-17 22:26:29 -0800891 * @param srcCp the source port
892 * @param dstCp the destination port
Pier Ventre42287df2016-11-09 14:17:26 -0800893 * @param l2Tunnel the tunnel to support
894 * @param egressId the egress device id
895 * @return the next objective to support the pipeline
896 */
897 private NextObjective.Builder createNextObjective(Pipeline pipeline,
Pier Ventre70d53ba2016-11-17 22:26:29 -0800898 ConnectPoint srcCp,
899 ConnectPoint dstCp,
Pier Ventre42287df2016-11-09 14:17:26 -0800900 DefaultL2Tunnel l2Tunnel,
901 DeviceId egressId) {
902 NextObjective.Builder nextObjBuilder;
903 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
904 if (pipeline == INITIATION) {
905 nextObjBuilder = DefaultNextObjective
906 .builder()
907 .withType(NextObjective.Type.SIMPLE)
908 .fromApp(srManager.appId);
909 // The pw label is the bottom of stack. It has to
910 // be different -1.
911 if (l2Tunnel.pwLabel().toInt() == MplsLabel.MAX_MPLS) {
912 log.warn("Pw label not configured");
913 return null;
914 }
915 treatmentBuilder.pushMpls();
916 treatmentBuilder.setMpls(l2Tunnel.pwLabel());
917 treatmentBuilder.setMplsBos(true);
918 treatmentBuilder.copyTtlOut();
919 // If the inter-co label is present we have to set the label.
920 if (l2Tunnel.interCoLabel().toInt() != MplsLabel.MAX_MPLS) {
921 treatmentBuilder.pushMpls();
922 treatmentBuilder.setMpls(l2Tunnel.interCoLabel());
923 treatmentBuilder.setMplsBos(false);
924 treatmentBuilder.copyTtlOut();
925 }
926 // We retrieve the sr label from the config
927 // using the egress leaf device id.
928 MplsLabel srLabel;
929 try {
930 srLabel = MplsLabel.mplsLabel(
931 srManager.deviceConfiguration.getIPv4SegmentId(egressId)
932 );
933 } catch (DeviceConfigNotFoundException e) {
934 log.warn("Sr label not configured");
935 return null;
936 }
937 treatmentBuilder.pushMpls();
938 treatmentBuilder.setMpls(srLabel);
939 treatmentBuilder.setMplsBos(false);
940 treatmentBuilder.copyTtlOut();
941 // We have to rewrite the src and dst mac address.
942 MacAddress ingressMac;
943 try {
944 ingressMac = srManager
945 .deviceConfiguration
Pier Ventre70d53ba2016-11-17 22:26:29 -0800946 .getDeviceMac(srcCp.deviceId());
Pier Ventre42287df2016-11-09 14:17:26 -0800947 } catch (DeviceConfigNotFoundException e) {
948 log.warn("Was not able to find the ingress mac");
949 return null;
950 }
951 treatmentBuilder.setEthSrc(ingressMac);
952 MacAddress neighborMac;
953 try {
954 neighborMac = srManager
955 .deviceConfiguration
Pier Ventre70d53ba2016-11-17 22:26:29 -0800956 .getDeviceMac(dstCp.deviceId());
Pier Ventre42287df2016-11-09 14:17:26 -0800957 } catch (DeviceConfigNotFoundException e) {
958 log.warn("Was not able to find the neighbor mac");
959 return null;
960 }
961 treatmentBuilder.setEthDst(neighborMac);
962 } else {
Pier Ventre70d53ba2016-11-17 22:26:29 -0800963 // We create the next objective which
964 // will be a simple l2 group.
Pier Ventre42287df2016-11-09 14:17:26 -0800965 nextObjBuilder = DefaultNextObjective
966 .builder()
967 .withType(NextObjective.Type.SIMPLE)
968 .fromApp(srManager.appId);
Pier Ventre42287df2016-11-09 14:17:26 -0800969 }
Pier Ventre70d53ba2016-11-17 22:26:29 -0800970 treatmentBuilder.setOutput(srcCp.port());
Pier Ventre42287df2016-11-09 14:17:26 -0800971 nextObjBuilder.addTreatment(treatmentBuilder.build());
972 return nextObjBuilder;
973 }
974
975 /**
976 * Returns the next hop.
977 *
978 * @param srcCp the ingress connect point
979 * @param dstCp the egress connect point
980 * @return the next hop
981 */
982 private Link getNextHop(ConnectPoint srcCp, ConnectPoint dstCp) {
983 // We retrieve a set of disjoint paths.
984 Set<DisjointPath> paths = srManager.pathService.getDisjointPaths(
985 srcCp.elementId(),
986 dstCp.elementId()
987 );
988 // We randmly pick a path.
989 if (paths.isEmpty()) {
990 return null;
991 }
992 int size = paths.size();
993 int index = RandomUtils.nextInt(0, size);
994 // We verify if the path is ok and there is not
995 // a misconfiguration.
996 List<Link> links = Iterables.get(paths, index).links();
997 checkState(links.size() == 2, WRONG_TOPOLOGY, links);
998 return links.get(0);
999 }
1000
1001 /**
Pier Ventre42287df2016-11-09 14:17:26 -08001002 * Deletes a given policy using the parameter supplied.
1003 *
1004 * @param tunnelId the tunnel id
1005 * @param ingress the ingress point
1006 * @param ingressInner the ingress inner vlan id
1007 * @param ingressOuter the ingress outer vlan id
Pier Ventre70d53ba2016-11-17 22:26:29 -08001008 * @param future to perform the async operation
1009 * @param direction the direction: forward or reverse
Pier Ventre42287df2016-11-09 14:17:26 -08001010 */
1011 private void deletePolicy(long tunnelId,
1012 ConnectPoint ingress,
1013 VlanId ingressInner,
1014 VlanId ingressOuter,
Pier Ventre70d53ba2016-11-17 22:26:29 -08001015 CompletableFuture<ObjectiveError> future,
1016 Direction direction) {
Pier Ventre42287df2016-11-09 14:17:26 -08001017 if (!srManager.mastershipService.isLocalMaster(ingress.deviceId())) {
Pier Ventre70d53ba2016-11-17 22:26:29 -08001018 log.info("Abort delete of policy for tunnel {}: I am not the master", tunnelId);
1019 if (future != null) {
1020 future.complete(null);
1021 }
Pier Ventre42287df2016-11-09 14:17:26 -08001022 return;
1023 }
Pier Ventre70d53ba2016-11-17 22:26:29 -08001024 String key = generateKey(tunnelId, direction);
1025 if (!l2InitiationNextObjStore.containsKey(key)) {
1026 log.warn("Abort delete of policy for tunnel {}: next does not exist in the store", tunnelId);
1027 if (future != null) {
1028 future.complete(null);
1029 }
1030 return;
1031 }
1032 NextObjective nextObjective = l2InitiationNextObjStore.get(key).value();
1033 int nextId = nextObjective.id();
1034 List<Objective> objectives = Lists.newArrayList();
Pier Ventre42287df2016-11-09 14:17:26 -08001035 // We create the forwarding objective.
Pier Ventre70d53ba2016-11-17 22:26:29 -08001036 ForwardingObjective.Builder fwdBuilder = createInitFwdObjective(
Pier Ventre42287df2016-11-09 14:17:26 -08001037 tunnelId,
1038 ingress.port(),
1039 nextId
1040 );
1041 ObjectiveContext context = new ObjectiveContext() {
1042 @Override
1043 public void onSuccess(Objective objective) {
Pier Ventre70d53ba2016-11-17 22:26:29 -08001044 log.debug("Previous fwdObj for policy {} removed", tunnelId);
1045 if (future != null) {
1046 future.complete(null);
Pier Ventre42287df2016-11-09 14:17:26 -08001047 }
1048 }
1049
1050 @Override
1051 public void onError(Objective objective, ObjectiveError error) {
Pier Ventre70d53ba2016-11-17 22:26:29 -08001052 log.warn("Failed to remove previous fwdObj for policy {}: {}", tunnelId, error);
1053 if (future != null) {
1054 future.complete(error);
Pier Ventre42287df2016-11-09 14:17:26 -08001055 }
1056 }
1057 };
1058 objectives.add(fwdBuilder.remove(context));
1059 // We create the filtering objective to define the
1060 // permit traffic in the switch
Pier Ventre70d53ba2016-11-17 22:26:29 -08001061 FilteringObjective.Builder filtBuilder = createFiltObjective(
Pier Ventre42287df2016-11-09 14:17:26 -08001062 ingress.port(),
1063 ingressInner,
1064 ingressOuter
1065 );
1066 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
1067 .setTunnelId(tunnelId);
1068 filtBuilder.withMeta(treatment.build());
1069 context = new DefaultObjectiveContext(
1070 (objective)
1071 -> log.debug("FilterObj for policy {} revoked", tunnelId),
1072 (objective, error)
1073 -> log.warn("Failed to revoke filterObj for policy {}", tunnelId, error));
1074 objectives.add(filtBuilder.remove(context));
1075
1076 for (Objective objective : objectives) {
1077 if (objective instanceof ForwardingObjective) {
1078 srManager.flowObjectiveService.forward(ingress.deviceId(), (ForwardingObjective) objective);
1079 } else {
1080 srManager.flowObjectiveService.filter(ingress.deviceId(), (FilteringObjective) objective);
1081 }
1082 }
1083 }
1084
1085 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -08001086 * Deletes the pseudo wire initiation.
Pier Ventre42287df2016-11-09 14:17:26 -08001087 *
Pier Ventre70d53ba2016-11-17 22:26:29 -08001088 * @param l2TunnelId the tunnel id
Pier Ventre42287df2016-11-09 14:17:26 -08001089 * @param ingress the ingress connect point
Pier Ventre70d53ba2016-11-17 22:26:29 -08001090 * @param future to perform an async operation
1091 * @param direction the direction: reverse of forward
Pier Ventre42287df2016-11-09 14:17:26 -08001092 */
Pier Ventre70d53ba2016-11-17 22:26:29 -08001093 private void tearDownPseudoWireInit(long l2TunnelId,
1094 ConnectPoint ingress,
1095 CompletableFuture<ObjectiveError> future,
1096 Direction direction) {
1097 String key = generateKey(l2TunnelId, direction);
Pier Ventre42287df2016-11-09 14:17:26 -08001098 if (!srManager.mastershipService.isLocalMaster(ingress.deviceId())) {
Pier Ventre70d53ba2016-11-17 22:26:29 -08001099 log.info("Abort delete of {} for {}: I am not the master", INITIATION, key);
1100 if (future != null) {
1101 future.complete(null);
1102 }
Pier Ventre42287df2016-11-09 14:17:26 -08001103 return;
1104 }
Pier Ventre70d53ba2016-11-17 22:26:29 -08001105 if (!l2InitiationNextObjStore.containsKey(key)) {
1106 log.info("Abort delete of {} for {}: next does not exist in the store", INITIATION, key);
1107 if (future != null) {
1108 future.complete(null);
1109 }
1110 return;
1111 }
1112 NextObjective nextObjective = l2InitiationNextObjStore.get(key).value();
Pier Ventre42287df2016-11-09 14:17:26 -08001113 ObjectiveContext context = new ObjectiveContext() {
1114 @Override
1115 public void onSuccess(Objective objective) {
Pier Ventre70d53ba2016-11-17 22:26:29 -08001116 log.debug("Previous {} next for {} removed", INITIATION, key);
1117 if (future != null) {
1118 future.complete(null);
Pier Ventre42287df2016-11-09 14:17:26 -08001119 }
1120 }
1121
1122 @Override
1123 public void onError(Objective objective, ObjectiveError error) {
Pier Ventre70d53ba2016-11-17 22:26:29 -08001124 log.warn("Failed to remove previous {} next for {}: {}", INITIATION, key, error);
1125 if (future != null) {
1126 future.complete(error);
Pier Ventre42287df2016-11-09 14:17:26 -08001127 }
1128 }
1129 };
Pier Ventre70d53ba2016-11-17 22:26:29 -08001130 srManager.flowObjectiveService
1131 .next(ingress.deviceId(), (NextObjective) nextObjective.copy().remove(context));
Pier Ventre42287df2016-11-09 14:17:26 -08001132 l2InitiationNextObjStore.remove(key);
1133 }
1134
1135 /**
Pier Ventre70d53ba2016-11-17 22:26:29 -08001136 * Deletes the pseudo wire termination.
1137 *
1138 * @param l2Tunnel the tunnel
1139 * @param egress the egress connect point
1140 * @param future the async task
1141 * @param direction the direction of the tunnel
1142 */
1143 private void tearDownPseudoWireTerm(DefaultL2Tunnel l2Tunnel,
1144 ConnectPoint egress,
1145 CompletableFuture<ObjectiveError> future,
1146 Direction direction) {
1147 /*
1148 * We verify the mastership for the termination.
1149 */
1150 String key = generateKey(l2Tunnel.tunnelId(), direction);
1151 if (!srManager.mastershipService.isLocalMaster(egress.deviceId())) {
1152 log.info("Abort delete of {} for {}: I am not the master", TERMINATION, key);
1153 if (future != null) {
1154 future.complete(null);
1155 }
1156 return;
1157 }
1158 if (!l2TerminationNextObjStore.containsKey(key)) {
1159 log.info("Abort delete of {} for {}: next does not exist in the store", TERMINATION, key);
1160 if (future != null) {
1161 future.complete(null);
1162 }
1163 return;
1164 }
1165 NextObjective nextObjective = l2TerminationNextObjStore.get(key).value();
1166 ForwardingObjective.Builder fwdBuilder = createTermFwdObjective(
1167 l2Tunnel.pwLabel(),
1168 l2Tunnel.tunnelId(),
1169 egress.port(),
1170 nextObjective.id()
1171 );
1172 ObjectiveContext context = new DefaultObjectiveContext(
1173 (objective)
1174 -> log.debug("FwdObj for {} {} removed", TERMINATION, l2Tunnel.tunnelId()),
1175 (objective, error)
1176 -> log.warn("Failed to remove fwdObj for {} {}", TERMINATION, l2Tunnel.tunnelId(),
1177 error));
1178 srManager.flowObjectiveService.forward(egress.deviceId(), fwdBuilder.remove(context));
1179
1180 context = new ObjectiveContext() {
1181 @Override
1182 public void onSuccess(Objective objective) {
1183 log.debug("Previous {} next for {} removed", TERMINATION, key);
1184 if (future != null) {
1185 future.complete(null);
1186 }
1187 }
1188
1189 @Override
1190 public void onError(Objective objective, ObjectiveError error) {
1191 log.warn("Failed to remove previous {} next for {}: {}", TERMINATION, key, error);
1192 if (future != null) {
1193 future.complete(error);
1194 }
1195 }
1196 };
1197 srManager.flowObjectiveService
1198 .next(egress.deviceId(), (NextObjective) nextObjective.copy().remove(context));
1199 l2TerminationNextObjStore.remove(key);
1200 }
1201
1202 /**
Pier Ventre42287df2016-11-09 14:17:26 -08001203 * Utilities to generate pw key.
1204 *
1205 * @param tunnelId the tunnel id
1206 * @param direction the direction of the pw
1207 * @return the key of the store
1208 */
Pier Ventre70d53ba2016-11-17 22:26:29 -08001209 private String generateKey(long tunnelId, Direction direction) {
Pier Ventre42287df2016-11-09 14:17:26 -08001210 return String.format("%s-%s", tunnelId, direction);
1211 }
1212
1213 /**
1214 * VPWS pipelines.
1215 */
1216 protected enum Pipeline {
1217 /**
1218 * The initiation pipeline.
1219 */
1220 INITIATION,
1221 /**
1222 * The termination pipeline.
1223 */
Pier Ventre70d53ba2016-11-17 22:26:29 -08001224 TERMINATION
Pier Ventre42287df2016-11-09 14:17:26 -08001225 }
1226
1227 /**
1228 * Enum helper to carry the outcomes of an operation.
1229 */
1230 public enum Result {
1231 /**
1232 * Happy ending scenario it has been created.
1233 */
1234 SUCCESS(0, "It has been Created"),
1235 /**
1236 * We have problems with the supplied parameters.
1237 */
1238 WRONG_PARAMETERS(1, "Wrong parameters"),
1239 /**
1240 * It already exists.
1241 */
1242 ID_EXISTS(2, "The id already exists"),
1243 /**
1244 * We have an internal error during the deployment
1245 * phase.
1246 */
1247 INTERNAL_ERROR(3, "Internal error"),
1248 /**
1249 * The operation is not supported.
1250 */
1251 UNSUPPORTED(4, "Unsupported");
1252
1253 private final int code;
1254 private final String description;
1255 private int nextId;
1256
Pier Ventre70d53ba2016-11-17 22:26:29 -08001257 Result(int code, String description) {
Pier Ventre42287df2016-11-09 14:17:26 -08001258 this.code = code;
1259 this.description = description;
1260 }
1261
1262 public String getDescription() {
1263 return description;
1264 }
1265
Pier Ventre42287df2016-11-09 14:17:26 -08001266 @Override
1267 public String toString() {
1268 return code + ": " + description;
1269 }
1270 }
1271
Pier Ventre70d53ba2016-11-17 22:26:29 -08001272 /**
1273 * Enum helper for handling the direction of the pw.
1274 */
1275 public enum Direction {
1276 /**
1277 * The forward direction of the pseudo wire.
1278 */
1279 FWD,
1280 /**
1281 * The reverse direction of the pseudo wire.
1282 */
1283 REV;
1284 }
1285
Pier Ventref34966c2016-11-07 16:21:04 -08001286}