blob: 96c1a38df0f07ae2fc17a512d9b9e40f665d1b16 [file] [log] [blame]
Charles Chan82f19972016-05-17 13:13:55 -07001/*
Brian O'Connor0947d7e2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Charles Chan82f19972016-05-17 13:13:55 -07003 *
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;
18
19import com.google.common.collect.ImmutableSet;
Charles Chan868c9572018-06-15 18:54:18 -070020import com.google.common.collect.Sets;
Charles Chan82f19972016-05-17 13:13:55 -070021import org.onlab.packet.MacAddress;
Charles Chan868c9572018-06-15 18:54:18 -070022import org.onlab.packet.VlanId;
Charles Chan82f19972016-05-17 13:13:55 -070023import org.onlab.util.KryoNamespace;
24import org.onosproject.net.ConnectPoint;
25import org.onosproject.net.DeviceId;
26import org.onosproject.net.PortNumber;
27import org.onosproject.net.config.NetworkConfigEvent;
28import org.onosproject.net.flow.DefaultTrafficSelector;
29import org.onosproject.net.flow.DefaultTrafficTreatment;
30import org.onosproject.net.flow.TrafficSelector;
31import org.onosproject.net.flow.TrafficTreatment;
32import org.onosproject.net.flow.criteria.Criteria;
33import org.onosproject.net.flowobjective.DefaultFilteringObjective;
34import org.onosproject.net.flowobjective.DefaultForwardingObjective;
35import org.onosproject.net.flowobjective.DefaultNextObjective;
36import org.onosproject.net.flowobjective.DefaultObjectiveContext;
37import org.onosproject.net.flowobjective.FilteringObjective;
38import org.onosproject.net.flowobjective.ForwardingObjective;
39import org.onosproject.net.flowobjective.NextObjective;
40import org.onosproject.net.flowobjective.Objective;
41import org.onosproject.net.flowobjective.ObjectiveContext;
42import org.onosproject.net.flowobjective.ObjectiveError;
43import org.onosproject.segmentrouting.config.XConnectConfig;
44import org.onosproject.segmentrouting.storekey.XConnectStoreKey;
45import org.onosproject.store.serializers.KryoNamespaces;
46import org.onosproject.store.service.ConsistentMap;
47import org.onosproject.store.service.Serializer;
Charles Chan82f19972016-05-17 13:13:55 -070048import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
Charles Chan82f19972016-05-17 13:13:55 -070051import java.util.Set;
52import java.util.concurrent.CompletableFuture;
53import java.util.stream.Collectors;
54
55/**
56 * Handles cross connect related events.
57 */
58public class XConnectHandler {
59 private static final Logger log = LoggerFactory.getLogger(XConnectHandler.class);
Charles Chan44341902016-07-07 12:00:08 -070060 private static final String CONFIG_NOT_FOUND = "XConnect config not found";
Charles Chan82f19972016-05-17 13:13:55 -070061 private static final String NOT_MASTER = "Not master controller";
62 private final SegmentRoutingManager srManager;
Charles Chan82f19972016-05-17 13:13:55 -070063 private final ConsistentMap<XConnectStoreKey, NextObjective> xConnectNextObjStore;
Charles Chan82f19972016-05-17 13:13:55 -070064
Charles Chan868c9572018-06-15 18:54:18 -070065 XConnectHandler(SegmentRoutingManager srManager) {
Charles Chan82f19972016-05-17 13:13:55 -070066 this.srManager = srManager;
Charles Chan868c9572018-06-15 18:54:18 -070067 KryoNamespace.Builder xConnectKryo = new KryoNamespace.Builder()
Charles Chan82f19972016-05-17 13:13:55 -070068 .register(KryoNamespaces.API)
69 .register(XConnectStoreKey.class)
70 .register(NextObjContext.class);
Charles Chan868c9572018-06-15 18:54:18 -070071 xConnectNextObjStore = srManager.storageService
Charles Chan82f19972016-05-17 13:13:55 -070072 .<XConnectStoreKey, NextObjective>consistentMapBuilder()
73 .withName("onos-xconnect-nextobj-store")
74 .withSerializer(Serializer.using(xConnectKryo.build()))
75 .build();
76 }
77
78 /**
79 * Read initial XConnect for given device.
80 *
81 * @param deviceId ID of the device to be initialized
82 */
83 public void init(DeviceId deviceId) {
84 // Try to read XConnect config
85 XConnectConfig config =
86 srManager.cfgService.getConfig(srManager.appId, XConnectConfig.class);
87 if (config == null) {
Charles Chan44341902016-07-07 12:00:08 -070088 log.info("Skip XConnect initialization: {}", CONFIG_NOT_FOUND);
Charles Chan82f19972016-05-17 13:13:55 -070089 return;
90 }
91
Charles Chan868c9572018-06-15 18:54:18 -070092 config.getXconnects(deviceId).forEach(key -> populateXConnect(key, config.getPorts(key)));
Charles Chan82f19972016-05-17 13:13:55 -070093 }
94
95 /**
96 * Processes Segment Routing App Config added event.
97 *
98 * @param event network config added event
99 */
Charles Chan868c9572018-06-15 18:54:18 -0700100 void processXConnectConfigAdded(NetworkConfigEvent event) {
Charles Chan82f19972016-05-17 13:13:55 -0700101 log.info("Processing XConnect CONFIG_ADDED");
102 XConnectConfig config = (XConnectConfig) event.config().get();
Charles Chan868c9572018-06-15 18:54:18 -0700103 config.getXconnects().forEach(key -> populateXConnect(key, config.getPorts(key)));
Charles Chan82f19972016-05-17 13:13:55 -0700104 }
105
106 /**
107 * Processes Segment Routing App Config updated event.
108 *
109 * @param event network config updated event
110 */
Charles Chan868c9572018-06-15 18:54:18 -0700111 void processXConnectConfigUpdated(NetworkConfigEvent event) {
Charles Chan82f19972016-05-17 13:13:55 -0700112 log.info("Processing XConnect CONFIG_UPDATED");
113 XConnectConfig prevConfig = (XConnectConfig) event.prevConfig().get();
114 XConnectConfig config = (XConnectConfig) event.config().get();
115 Set<XConnectStoreKey> prevKeys = prevConfig.getXconnects();
116 Set<XConnectStoreKey> keys = config.getXconnects();
117
118 Set<XConnectStoreKey> pendingRemove = prevKeys.stream()
119 .filter(key -> !keys.contains(key)).collect(Collectors.toSet());
120 Set<XConnectStoreKey> pendingAdd = keys.stream()
121 .filter(key -> !prevKeys.contains(key)).collect(Collectors.toSet());
122 Set<XConnectStoreKey> pendingUpdate = keys.stream()
123 .filter(key -> prevKeys.contains(key) &&
124 !config.getPorts(key).equals(prevConfig.getPorts(key)))
125 .collect(Collectors.toSet());
126
Charles Chan868c9572018-06-15 18:54:18 -0700127 pendingRemove.forEach(key -> revokeXConnect(key, prevConfig.getPorts(key)));
128 pendingAdd.forEach(key -> populateXConnect(key, config.getPorts(key)));
129 pendingUpdate.forEach(key ->
130 updateXConnect(key, prevConfig.getPorts(key), config.getPorts(key)));
Charles Chan82f19972016-05-17 13:13:55 -0700131 }
132
133 /**
134 * Processes Segment Routing App Config removed event.
135 *
136 * @param event network config removed event
137 */
Charles Chan868c9572018-06-15 18:54:18 -0700138 void processXConnectConfigRemoved(NetworkConfigEvent event) {
Charles Chan82f19972016-05-17 13:13:55 -0700139 log.info("Processing XConnect CONFIG_REMOVED");
140 XConnectConfig prevConfig = (XConnectConfig) event.prevConfig().get();
141 prevConfig.getXconnects().forEach(key -> {
142 revokeXConnect(key, prevConfig.getPorts(key));
143 });
144 }
145
146 /**
147 * Checks if there is any XConnect configured on given connect point.
148 *
149 * @param cp connect point
150 * @return true if there is XConnect configured on given connect point.
151 */
152 public boolean hasXConnect(ConnectPoint cp) {
153 // Try to read XConnect config
154 XConnectConfig config =
155 srManager.cfgService.getConfig(srManager.appId, XConnectConfig.class);
156 if (config == null) {
157 log.warn("Failed to read XConnect config: {}", CONFIG_NOT_FOUND);
158 return false;
159 }
160 return config.getXconnects(cp.deviceId()).stream()
161 .anyMatch(key -> config.getPorts(key).contains(cp.port()));
162 }
163
164 /**
165 * Populates XConnect groups and flows for given key.
166 *
167 * @param key XConnect key
168 * @param ports a set of ports to be cross-connected
169 */
170 private void populateXConnect(XConnectStoreKey key, Set<PortNumber> ports) {
171 if (!srManager.mastershipService.isLocalMaster(key.deviceId())) {
172 log.info("Abort populating XConnect {}: {}", key, NOT_MASTER);
173 return;
174 }
Charles Chan868c9572018-06-15 18:54:18 -0700175
176 ports = addPairPort(key.deviceId(), ports);
Charles Chan82f19972016-05-17 13:13:55 -0700177 populateFilter(key, ports);
178 populateFwd(key, populateNext(key, ports));
Charles Chan868c9572018-06-15 18:54:18 -0700179 populateAcl(key);
Charles Chan82f19972016-05-17 13:13:55 -0700180 }
181
182 /**
183 * Populates filtering objectives for given XConnect.
184 *
185 * @param key XConnect store key
186 * @param ports XConnect ports
187 */
188 private void populateFilter(XConnectStoreKey key, Set<PortNumber> ports) {
189 ports.forEach(port -> {
190 FilteringObjective.Builder filtObjBuilder = filterObjBuilder(key, port);
191 ObjectiveContext context = new DefaultObjectiveContext(
192 (objective) -> log.debug("XConnect FilterObj for {} on port {} populated",
193 key, port),
194 (objective, error) ->
195 log.warn("Failed to populate XConnect FilterObj for {} on port {}: {}",
196 key, port, error));
197 srManager.flowObjectiveService.filter(key.deviceId(), filtObjBuilder.add(context));
198 });
199 }
200
201 /**
202 * Populates next objectives for given XConnect.
203 *
204 * @param key XConnect store key
205 * @param ports XConnect ports
206 */
207 private NextObjective populateNext(XConnectStoreKey key, Set<PortNumber> ports) {
Charles Chan868c9572018-06-15 18:54:18 -0700208 NextObjective nextObj;
Charles Chan82f19972016-05-17 13:13:55 -0700209 if (xConnectNextObjStore.containsKey(key)) {
210 nextObj = xConnectNextObjStore.get(key).value();
211 log.debug("NextObj for {} found, id={}", key, nextObj.id());
212 } else {
213 NextObjective.Builder nextObjBuilder = nextObjBuilder(key, ports);
214 ObjectiveContext nextContext = new NextObjContext(Objective.Operation.ADD, key);
215 nextObj = nextObjBuilder.add(nextContext);
216 srManager.flowObjectiveService.next(key.deviceId(), nextObj);
217 xConnectNextObjStore.put(key, nextObj);
218 log.debug("NextObj for {} not found. Creating new NextObj with id={}", key, nextObj.id());
219 }
220 return nextObj;
221 }
222
223 /**
Charles Chan868c9572018-06-15 18:54:18 -0700224 * Populates bridging forwarding objectives for given XConnect.
Charles Chan82f19972016-05-17 13:13:55 -0700225 *
226 * @param key XConnect store key
227 * @param nextObj next objective
228 */
229 private void populateFwd(XConnectStoreKey key, NextObjective nextObj) {
230 ForwardingObjective.Builder fwdObjBuilder = fwdObjBuilder(key, nextObj.id());
231 ObjectiveContext fwdContext = new DefaultObjectiveContext(
232 (objective) -> log.debug("XConnect FwdObj for {} populated", key),
233 (objective, error) ->
234 log.warn("Failed to populate XConnect FwdObj for {}: {}", key, error));
235 srManager.flowObjectiveService.forward(key.deviceId(), fwdObjBuilder.add(fwdContext));
236 }
237
238 /**
Charles Chan868c9572018-06-15 18:54:18 -0700239 * Populates ACL forwarding objectives for given XConnect.
240 *
241 * @param key XConnect store key
242 */
243 private void populateAcl(XConnectStoreKey key) {
244 ForwardingObjective.Builder aclObjBuilder = aclObjBuilder(key.vlanId());
245 ObjectiveContext aclContext = new DefaultObjectiveContext(
246 (objective) -> log.debug("XConnect AclObj for {} populated", key),
247 (objective, error) ->
248 log.warn("Failed to populate XConnect AclObj for {}: {}", key, error));
249 srManager.flowObjectiveService.forward(key.deviceId(), aclObjBuilder.add(aclContext));
250 }
251
252 /**
Charles Chan82f19972016-05-17 13:13:55 -0700253 * Revokes XConnect groups and flows for given key.
254 *
255 * @param key XConnect key
256 * @param ports XConnect ports
257 */
258 private void revokeXConnect(XConnectStoreKey key, Set<PortNumber> ports) {
259 if (!srManager.mastershipService.isLocalMaster(key.deviceId())) {
260 log.info("Abort populating XConnect {}: {}", key, NOT_MASTER);
261 return;
262 }
263
Charles Chan868c9572018-06-15 18:54:18 -0700264 ports = addPairPort(key.deviceId(), ports);
Charles Chan82f19972016-05-17 13:13:55 -0700265 revokeFilter(key, ports);
266 if (xConnectNextObjStore.containsKey(key)) {
267 NextObjective nextObj = xConnectNextObjStore.get(key).value();
268 revokeFwd(key, nextObj, null);
269 revokeNext(key, nextObj, null);
270 } else {
271 log.warn("NextObj for {} does not exist in the store.", key);
272 }
Charles Chan868c9572018-06-15 18:54:18 -0700273 revokeAcl(key);
Charles Chan82f19972016-05-17 13:13:55 -0700274 }
275
276 /**
277 * Revokes filtering objectives for given XConnect.
278 *
279 * @param key XConnect store key
280 * @param ports XConnect ports
281 */
282 private void revokeFilter(XConnectStoreKey key, Set<PortNumber> ports) {
283 ports.forEach(port -> {
284 FilteringObjective.Builder filtObjBuilder = filterObjBuilder(key, port);
285 ObjectiveContext context = new DefaultObjectiveContext(
286 (objective) -> log.debug("XConnect FilterObj for {} on port {} revoked",
287 key, port),
288 (objective, error) ->
289 log.warn("Failed to revoke XConnect FilterObj for {} on port {}: {}",
290 key, port, error));
291 srManager.flowObjectiveService.filter(key.deviceId(), filtObjBuilder.remove(context));
292 });
293 }
294
295 /**
296 * Revokes next objectives for given XConnect.
297 *
298 * @param key XConnect store key
299 * @param nextObj next objective
300 * @param nextFuture completable future for this next objective operation
301 */
302 private void revokeNext(XConnectStoreKey key, NextObjective nextObj,
303 CompletableFuture<ObjectiveError> nextFuture) {
304 ObjectiveContext context = new ObjectiveContext() {
305 @Override
306 public void onSuccess(Objective objective) {
307 log.debug("Previous NextObj for {} removed", key);
308 if (nextFuture != null) {
309 nextFuture.complete(null);
310 }
311 }
312
313 @Override
314 public void onError(Objective objective, ObjectiveError error) {
315 log.warn("Failed to remove previous NextObj for {}: {}", key, error);
316 if (nextFuture != null) {
317 nextFuture.complete(error);
318 }
319 }
320 };
321 srManager.flowObjectiveService.next(key.deviceId(),
322 (NextObjective) nextObj.copy().remove(context));
323 xConnectNextObjStore.remove(key);
324 }
325
326 /**
Charles Chan868c9572018-06-15 18:54:18 -0700327 * Revokes bridging forwarding objectives for given XConnect.
Charles Chan82f19972016-05-17 13:13:55 -0700328 *
329 * @param key XConnect store key
330 * @param nextObj next objective
331 * @param fwdFuture completable future for this forwarding objective operation
332 */
333 private void revokeFwd(XConnectStoreKey key, NextObjective nextObj,
334 CompletableFuture<ObjectiveError> fwdFuture) {
335 ForwardingObjective.Builder fwdObjBuilder = fwdObjBuilder(key, nextObj.id());
336 ObjectiveContext context = new ObjectiveContext() {
337 @Override
338 public void onSuccess(Objective objective) {
339 log.debug("Previous FwdObj for {} removed", key);
340 if (fwdFuture != null) {
341 fwdFuture.complete(null);
342 }
343 }
344
345 @Override
346 public void onError(Objective objective, ObjectiveError error) {
347 log.warn("Failed to remove previous FwdObj for {}: {}", key, error);
348 if (fwdFuture != null) {
349 fwdFuture.complete(error);
350 }
351 }
352 };
353 srManager.flowObjectiveService
354 .forward(key.deviceId(), fwdObjBuilder.remove(context));
355 }
356
357 /**
Charles Chan868c9572018-06-15 18:54:18 -0700358 * Revokes ACL forwarding objectives for given XConnect.
359 *
360 * @param key XConnect store key
361 */
362 private void revokeAcl(XConnectStoreKey key) {
363 ForwardingObjective.Builder aclObjBuilder = aclObjBuilder(key.vlanId());
364 ObjectiveContext aclContext = new DefaultObjectiveContext(
365 (objective) -> log.debug("XConnect AclObj for {} populated", key),
366 (objective, error) ->
367 log.warn("Failed to populate XConnect AclObj for {}: {}", key, error));
368 srManager.flowObjectiveService
369 .forward(key.deviceId(), aclObjBuilder.remove(aclContext));
370 }
371
372 /**
Charles Chan82f19972016-05-17 13:13:55 -0700373 * Updates XConnect groups and flows for given key.
374 *
375 * @param key XConnect key
376 * @param prevPorts previous XConnect ports
377 * @param ports new XConnect ports
378 */
379 private void updateXConnect(XConnectStoreKey key, Set<PortNumber> prevPorts,
380 Set<PortNumber> ports) {
Charles Chan868c9572018-06-15 18:54:18 -0700381 // NOTE: ACL flow doesn't include port information. No need to update it.
382 // Pair port is built-in and thus not going to change. No need to update it.
383
Charles Chan82f19972016-05-17 13:13:55 -0700384 // remove old filter
Charles Chan868c9572018-06-15 18:54:18 -0700385 prevPorts.stream().filter(port -> !ports.contains(port)).forEach(port ->
386 revokeFilter(key, ImmutableSet.of(port)));
Charles Chan82f19972016-05-17 13:13:55 -0700387 // install new filter
Charles Chan868c9572018-06-15 18:54:18 -0700388 ports.stream().filter(port -> !prevPorts.contains(port)).forEach(port ->
389 populateFilter(key, ImmutableSet.of(port)));
Charles Chan82f19972016-05-17 13:13:55 -0700390
391 CompletableFuture<ObjectiveError> fwdFuture = new CompletableFuture<>();
392 CompletableFuture<ObjectiveError> nextFuture = new CompletableFuture<>();
393
394 if (xConnectNextObjStore.containsKey(key)) {
395 NextObjective nextObj = xConnectNextObjStore.get(key).value();
396 revokeFwd(key, nextObj, fwdFuture);
397
398 fwdFuture.thenAcceptAsync(fwdStatus -> {
399 if (fwdStatus == null) {
400 log.debug("Fwd removed. Now remove group {}", key);
401 revokeNext(key, nextObj, nextFuture);
402 }
403 });
404
405 nextFuture.thenAcceptAsync(nextStatus -> {
406 if (nextStatus == null) {
407 log.debug("Installing new group and flow for {}", key);
408 populateFwd(key, populateNext(key, ports));
409 }
410 });
411 } else {
412 log.warn("NextObj for {} does not exist in the store.", key);
413 }
414 }
415
416 /**
417 * Remove all groups on given device.
418 *
419 * @param deviceId device ID
420 */
Charles Chan868c9572018-06-15 18:54:18 -0700421 void removeDevice(DeviceId deviceId) {
Charles Chanfc115892016-06-17 14:28:07 -0700422 xConnectNextObjStore.entrySet().stream()
423 .filter(entry -> entry.getKey().deviceId().equals(deviceId))
Charles Chan868c9572018-06-15 18:54:18 -0700424 .forEach(entry -> xConnectNextObjStore.remove(entry.getKey()));
Charles Chanfc115892016-06-17 14:28:07 -0700425 log.debug("{} is removed from xConnectNextObjStore", deviceId);
Charles Chan82f19972016-05-17 13:13:55 -0700426 }
427
428 /**
429 * Creates a next objective builder for XConnect.
430 *
431 * @param key XConnect key
432 * @param ports set of XConnect ports
433 * @return next objective builder
434 */
435 private NextObjective.Builder nextObjBuilder(XConnectStoreKey key, Set<PortNumber> ports) {
436 int nextId = srManager.flowObjectiveService.allocateNextId();
437 TrafficSelector metadata =
438 DefaultTrafficSelector.builder().matchVlanId(key.vlanId()).build();
439 NextObjective.Builder nextObjBuilder = DefaultNextObjective
440 .builder().withId(nextId)
441 .withType(NextObjective.Type.BROADCAST).fromApp(srManager.appId)
442 .withMeta(metadata);
443 ports.forEach(port -> {
444 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
445 tBuilder.setOutput(port);
446 nextObjBuilder.addTreatment(tBuilder.build());
447 });
448 return nextObjBuilder;
449 }
450
451 /**
Charles Chan868c9572018-06-15 18:54:18 -0700452 * Creates a bridging forwarding objective builder for XConnect.
Charles Chan82f19972016-05-17 13:13:55 -0700453 *
454 * @param key XConnect key
455 * @param nextId next ID of the broadcast group for this XConnect key
Charles Chan868c9572018-06-15 18:54:18 -0700456 * @return forwarding objective builder
Charles Chan82f19972016-05-17 13:13:55 -0700457 */
458 private ForwardingObjective.Builder fwdObjBuilder(XConnectStoreKey key, int nextId) {
459 /*
460 * Driver should treat objectives with MacAddress.NONE and !VlanId.NONE
461 * as the VLAN cross-connect broadcast rules
462 */
463 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
464 sbuilder.matchVlanId(key.vlanId());
465 sbuilder.matchEthDst(MacAddress.NONE);
466
467 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
468 fob.withFlag(ForwardingObjective.Flag.SPECIFIC)
469 .withSelector(sbuilder.build())
470 .nextStep(nextId)
471 .withPriority(SegmentRoutingService.XCONNECT_PRIORITY)
472 .fromApp(srManager.appId)
473 .makePermanent();
474 return fob;
475 }
476
477 /**
Charles Chan868c9572018-06-15 18:54:18 -0700478 * Creates an ACL forwarding objective builder for XConnect.
479 *
480 * @param vlanId cross connect VLAN id
481 * @return forwarding objective builder
482 */
483 private ForwardingObjective.Builder aclObjBuilder(VlanId vlanId) {
484 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
485 sbuilder.matchVlanId(vlanId);
486
487 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
488
489 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
490 fob.withFlag(ForwardingObjective.Flag.VERSATILE)
491 .withSelector(sbuilder.build())
492 .withTreatment(tbuilder.build())
493 .withPriority(SegmentRoutingService.XCONNECT_ACL_PRIORITY)
494 .fromApp(srManager.appId)
495 .makePermanent();
496 return fob;
497 }
498
499 /**
Charles Chan82f19972016-05-17 13:13:55 -0700500 * Creates a filtering objective builder for XConnect.
501 *
502 * @param key XConnect key
503 * @param port XConnect ports
504 * @return next objective builder
505 */
506 private FilteringObjective.Builder filterObjBuilder(XConnectStoreKey key, PortNumber port) {
507 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
508 fob.withKey(Criteria.matchInPort(port))
509 .addCondition(Criteria.matchVlanId(key.vlanId()))
510 .addCondition(Criteria.matchEthDst(MacAddress.NONE))
511 .withPriority(SegmentRoutingService.XCONNECT_PRIORITY);
512 return fob.permit().fromApp(srManager.appId);
513 }
514
Charles Chan868c9572018-06-15 18:54:18 -0700515 /**
516 * Add pair port to the given set of port.
517 *
518 * @param deviceId device Id
519 * @param ports ports specified in the xconnect config
520 * @return port specified in the xconnect config plus the pair port (if configured)
521 */
522 private Set<PortNumber> addPairPort(DeviceId deviceId, Set<PortNumber> ports) {
523 Set<PortNumber> newPorts = Sets.newHashSet(ports);
524 srManager.getPairLocalPort(deviceId).ifPresent(newPorts::add);
525 return newPorts;
526 }
527
Charles Chan82f19972016-05-17 13:13:55 -0700528 // TODO: Lambda closure in DefaultObjectiveContext cannot be serialized properly
529 // with Kryo 3.0.3. It will be fixed in 3.0.4. By then we can use
530 // DefaultObjectiveContext again.
531 private final class NextObjContext implements ObjectiveContext {
532 Objective.Operation op;
533 XConnectStoreKey key;
534
535 private NextObjContext(Objective.Operation op, XConnectStoreKey key) {
536 this.op = op;
537 this.key = key;
538 }
539
540 @Override
541 public void onSuccess(Objective objective) {
542 log.debug("XConnect NextObj for {} {}ED", key, op);
543 }
544
545 @Override
546 public void onError(Objective objective, ObjectiveError error) {
547 log.warn("Failed to {} XConnect NextObj for {}: {}", op, key, error);
548 }
549 }
550}