blob: 5dafb3f72daca2c1238d18bbb77fa57ee8cbc1e2 [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.
Charles Chan8d316332018-06-19 20:31:57 -070057 *
58 * @deprecated in ONOS 1.12. Replaced by {@link org.onosproject.segmentrouting.xconnect.impl.XconnectManager}
Charles Chan82f19972016-05-17 13:13:55 -070059 */
Charles Chan8d316332018-06-19 20:31:57 -070060@Deprecated
Charles Chan82f19972016-05-17 13:13:55 -070061public class XConnectHandler {
62 private static final Logger log = LoggerFactory.getLogger(XConnectHandler.class);
Charles Chan44341902016-07-07 12:00:08 -070063 private static final String CONFIG_NOT_FOUND = "XConnect config not found";
Charles Chan82f19972016-05-17 13:13:55 -070064 private static final String NOT_MASTER = "Not master controller";
65 private final SegmentRoutingManager srManager;
Charles Chan82f19972016-05-17 13:13:55 -070066 private final ConsistentMap<XConnectStoreKey, NextObjective> xConnectNextObjStore;
Charles Chan82f19972016-05-17 13:13:55 -070067
Charles Chan868c9572018-06-15 18:54:18 -070068 XConnectHandler(SegmentRoutingManager srManager) {
Charles Chan82f19972016-05-17 13:13:55 -070069 this.srManager = srManager;
Charles Chan868c9572018-06-15 18:54:18 -070070 KryoNamespace.Builder xConnectKryo = new KryoNamespace.Builder()
Charles Chan82f19972016-05-17 13:13:55 -070071 .register(KryoNamespaces.API)
72 .register(XConnectStoreKey.class)
73 .register(NextObjContext.class);
Charles Chan868c9572018-06-15 18:54:18 -070074 xConnectNextObjStore = srManager.storageService
Charles Chan82f19972016-05-17 13:13:55 -070075 .<XConnectStoreKey, NextObjective>consistentMapBuilder()
76 .withName("onos-xconnect-nextobj-store")
77 .withSerializer(Serializer.using(xConnectKryo.build()))
78 .build();
79 }
80
81 /**
82 * Read initial XConnect for given device.
83 *
84 * @param deviceId ID of the device to be initialized
85 */
86 public void init(DeviceId deviceId) {
87 // Try to read XConnect config
88 XConnectConfig config =
89 srManager.cfgService.getConfig(srManager.appId, XConnectConfig.class);
90 if (config == null) {
Charles Chan44341902016-07-07 12:00:08 -070091 log.info("Skip XConnect initialization: {}", CONFIG_NOT_FOUND);
Charles Chan82f19972016-05-17 13:13:55 -070092 return;
93 }
94
Charles Chan868c9572018-06-15 18:54:18 -070095 config.getXconnects(deviceId).forEach(key -> populateXConnect(key, config.getPorts(key)));
Charles Chan82f19972016-05-17 13:13:55 -070096 }
97
98 /**
99 * Processes Segment Routing App Config added event.
100 *
101 * @param event network config added event
102 */
Charles Chan868c9572018-06-15 18:54:18 -0700103 void processXConnectConfigAdded(NetworkConfigEvent event) {
Charles Chan82f19972016-05-17 13:13:55 -0700104 log.info("Processing XConnect CONFIG_ADDED");
105 XConnectConfig config = (XConnectConfig) event.config().get();
Charles Chan868c9572018-06-15 18:54:18 -0700106 config.getXconnects().forEach(key -> populateXConnect(key, config.getPorts(key)));
Charles Chan82f19972016-05-17 13:13:55 -0700107 }
108
109 /**
110 * Processes Segment Routing App Config updated event.
111 *
112 * @param event network config updated event
113 */
Charles Chan868c9572018-06-15 18:54:18 -0700114 void processXConnectConfigUpdated(NetworkConfigEvent event) {
Charles Chan82f19972016-05-17 13:13:55 -0700115 log.info("Processing XConnect CONFIG_UPDATED");
116 XConnectConfig prevConfig = (XConnectConfig) event.prevConfig().get();
117 XConnectConfig config = (XConnectConfig) event.config().get();
118 Set<XConnectStoreKey> prevKeys = prevConfig.getXconnects();
119 Set<XConnectStoreKey> keys = config.getXconnects();
120
121 Set<XConnectStoreKey> pendingRemove = prevKeys.stream()
122 .filter(key -> !keys.contains(key)).collect(Collectors.toSet());
123 Set<XConnectStoreKey> pendingAdd = keys.stream()
124 .filter(key -> !prevKeys.contains(key)).collect(Collectors.toSet());
125 Set<XConnectStoreKey> pendingUpdate = keys.stream()
126 .filter(key -> prevKeys.contains(key) &&
127 !config.getPorts(key).equals(prevConfig.getPorts(key)))
128 .collect(Collectors.toSet());
129
Charles Chan868c9572018-06-15 18:54:18 -0700130 pendingRemove.forEach(key -> revokeXConnect(key, prevConfig.getPorts(key)));
131 pendingAdd.forEach(key -> populateXConnect(key, config.getPorts(key)));
132 pendingUpdate.forEach(key ->
133 updateXConnect(key, prevConfig.getPorts(key), config.getPorts(key)));
Charles Chan82f19972016-05-17 13:13:55 -0700134 }
135
136 /**
137 * Processes Segment Routing App Config removed event.
138 *
139 * @param event network config removed event
140 */
Charles Chan868c9572018-06-15 18:54:18 -0700141 void processXConnectConfigRemoved(NetworkConfigEvent event) {
Charles Chan82f19972016-05-17 13:13:55 -0700142 log.info("Processing XConnect CONFIG_REMOVED");
143 XConnectConfig prevConfig = (XConnectConfig) event.prevConfig().get();
144 prevConfig.getXconnects().forEach(key -> {
145 revokeXConnect(key, prevConfig.getPorts(key));
146 });
147 }
148
149 /**
150 * Checks if there is any XConnect configured on given connect point.
151 *
152 * @param cp connect point
153 * @return true if there is XConnect configured on given connect point.
154 */
155 public boolean hasXConnect(ConnectPoint cp) {
156 // Try to read XConnect config
157 XConnectConfig config =
158 srManager.cfgService.getConfig(srManager.appId, XConnectConfig.class);
159 if (config == null) {
160 log.warn("Failed to read XConnect config: {}", CONFIG_NOT_FOUND);
161 return false;
162 }
163 return config.getXconnects(cp.deviceId()).stream()
164 .anyMatch(key -> config.getPorts(key).contains(cp.port()));
165 }
166
167 /**
168 * Populates XConnect groups and flows for given key.
169 *
170 * @param key XConnect key
171 * @param ports a set of ports to be cross-connected
172 */
173 private void populateXConnect(XConnectStoreKey key, Set<PortNumber> ports) {
174 if (!srManager.mastershipService.isLocalMaster(key.deviceId())) {
175 log.info("Abort populating XConnect {}: {}", key, NOT_MASTER);
176 return;
177 }
Charles Chan868c9572018-06-15 18:54:18 -0700178
179 ports = addPairPort(key.deviceId(), ports);
Charles Chan82f19972016-05-17 13:13:55 -0700180 populateFilter(key, ports);
181 populateFwd(key, populateNext(key, ports));
Charles Chan868c9572018-06-15 18:54:18 -0700182 populateAcl(key);
Charles Chan82f19972016-05-17 13:13:55 -0700183 }
184
185 /**
186 * Populates filtering objectives for given XConnect.
187 *
188 * @param key XConnect store key
189 * @param ports XConnect ports
190 */
191 private void populateFilter(XConnectStoreKey key, Set<PortNumber> ports) {
192 ports.forEach(port -> {
193 FilteringObjective.Builder filtObjBuilder = filterObjBuilder(key, port);
194 ObjectiveContext context = new DefaultObjectiveContext(
195 (objective) -> log.debug("XConnect FilterObj for {} on port {} populated",
196 key, port),
197 (objective, error) ->
198 log.warn("Failed to populate XConnect FilterObj for {} on port {}: {}",
199 key, port, error));
200 srManager.flowObjectiveService.filter(key.deviceId(), filtObjBuilder.add(context));
201 });
202 }
203
204 /**
205 * Populates next objectives for given XConnect.
206 *
207 * @param key XConnect store key
208 * @param ports XConnect ports
209 */
210 private NextObjective populateNext(XConnectStoreKey key, Set<PortNumber> ports) {
Charles Chan868c9572018-06-15 18:54:18 -0700211 NextObjective nextObj;
Charles Chan82f19972016-05-17 13:13:55 -0700212 if (xConnectNextObjStore.containsKey(key)) {
213 nextObj = xConnectNextObjStore.get(key).value();
214 log.debug("NextObj for {} found, id={}", key, nextObj.id());
215 } else {
216 NextObjective.Builder nextObjBuilder = nextObjBuilder(key, ports);
217 ObjectiveContext nextContext = new NextObjContext(Objective.Operation.ADD, key);
218 nextObj = nextObjBuilder.add(nextContext);
219 srManager.flowObjectiveService.next(key.deviceId(), nextObj);
220 xConnectNextObjStore.put(key, nextObj);
221 log.debug("NextObj for {} not found. Creating new NextObj with id={}", key, nextObj.id());
222 }
223 return nextObj;
224 }
225
226 /**
Charles Chan868c9572018-06-15 18:54:18 -0700227 * Populates bridging forwarding objectives for given XConnect.
Charles Chan82f19972016-05-17 13:13:55 -0700228 *
229 * @param key XConnect store key
230 * @param nextObj next objective
231 */
232 private void populateFwd(XConnectStoreKey key, NextObjective nextObj) {
233 ForwardingObjective.Builder fwdObjBuilder = fwdObjBuilder(key, nextObj.id());
234 ObjectiveContext fwdContext = new DefaultObjectiveContext(
235 (objective) -> log.debug("XConnect FwdObj for {} populated", key),
236 (objective, error) ->
237 log.warn("Failed to populate XConnect FwdObj for {}: {}", key, error));
238 srManager.flowObjectiveService.forward(key.deviceId(), fwdObjBuilder.add(fwdContext));
239 }
240
241 /**
Charles Chan868c9572018-06-15 18:54:18 -0700242 * Populates ACL forwarding objectives for given XConnect.
243 *
244 * @param key XConnect store key
245 */
246 private void populateAcl(XConnectStoreKey key) {
247 ForwardingObjective.Builder aclObjBuilder = aclObjBuilder(key.vlanId());
248 ObjectiveContext aclContext = new DefaultObjectiveContext(
249 (objective) -> log.debug("XConnect AclObj for {} populated", key),
250 (objective, error) ->
251 log.warn("Failed to populate XConnect AclObj for {}: {}", key, error));
252 srManager.flowObjectiveService.forward(key.deviceId(), aclObjBuilder.add(aclContext));
253 }
254
255 /**
Charles Chan82f19972016-05-17 13:13:55 -0700256 * Revokes XConnect groups and flows for given key.
257 *
258 * @param key XConnect key
259 * @param ports XConnect ports
260 */
261 private void revokeXConnect(XConnectStoreKey key, Set<PortNumber> ports) {
262 if (!srManager.mastershipService.isLocalMaster(key.deviceId())) {
263 log.info("Abort populating XConnect {}: {}", key, NOT_MASTER);
264 return;
265 }
266
Charles Chan868c9572018-06-15 18:54:18 -0700267 ports = addPairPort(key.deviceId(), ports);
Charles Chan82f19972016-05-17 13:13:55 -0700268 revokeFilter(key, ports);
269 if (xConnectNextObjStore.containsKey(key)) {
270 NextObjective nextObj = xConnectNextObjStore.get(key).value();
271 revokeFwd(key, nextObj, null);
272 revokeNext(key, nextObj, null);
273 } else {
274 log.warn("NextObj for {} does not exist in the store.", key);
275 }
Charles Chan868c9572018-06-15 18:54:18 -0700276 revokeAcl(key);
Charles Chan82f19972016-05-17 13:13:55 -0700277 }
278
279 /**
280 * Revokes filtering objectives for given XConnect.
281 *
282 * @param key XConnect store key
283 * @param ports XConnect ports
284 */
285 private void revokeFilter(XConnectStoreKey key, Set<PortNumber> ports) {
286 ports.forEach(port -> {
287 FilteringObjective.Builder filtObjBuilder = filterObjBuilder(key, port);
288 ObjectiveContext context = new DefaultObjectiveContext(
289 (objective) -> log.debug("XConnect FilterObj for {} on port {} revoked",
290 key, port),
291 (objective, error) ->
292 log.warn("Failed to revoke XConnect FilterObj for {} on port {}: {}",
293 key, port, error));
294 srManager.flowObjectiveService.filter(key.deviceId(), filtObjBuilder.remove(context));
295 });
296 }
297
298 /**
299 * Revokes next objectives for given XConnect.
300 *
301 * @param key XConnect store key
302 * @param nextObj next objective
303 * @param nextFuture completable future for this next objective operation
304 */
305 private void revokeNext(XConnectStoreKey key, NextObjective nextObj,
306 CompletableFuture<ObjectiveError> nextFuture) {
307 ObjectiveContext context = new ObjectiveContext() {
308 @Override
309 public void onSuccess(Objective objective) {
310 log.debug("Previous NextObj for {} removed", key);
311 if (nextFuture != null) {
312 nextFuture.complete(null);
313 }
314 }
315
316 @Override
317 public void onError(Objective objective, ObjectiveError error) {
318 log.warn("Failed to remove previous NextObj for {}: {}", key, error);
319 if (nextFuture != null) {
320 nextFuture.complete(error);
321 }
322 }
323 };
324 srManager.flowObjectiveService.next(key.deviceId(),
325 (NextObjective) nextObj.copy().remove(context));
326 xConnectNextObjStore.remove(key);
327 }
328
329 /**
Charles Chan868c9572018-06-15 18:54:18 -0700330 * Revokes bridging forwarding objectives for given XConnect.
Charles Chan82f19972016-05-17 13:13:55 -0700331 *
332 * @param key XConnect store key
333 * @param nextObj next objective
334 * @param fwdFuture completable future for this forwarding objective operation
335 */
336 private void revokeFwd(XConnectStoreKey key, NextObjective nextObj,
337 CompletableFuture<ObjectiveError> fwdFuture) {
338 ForwardingObjective.Builder fwdObjBuilder = fwdObjBuilder(key, nextObj.id());
339 ObjectiveContext context = new ObjectiveContext() {
340 @Override
341 public void onSuccess(Objective objective) {
342 log.debug("Previous FwdObj for {} removed", key);
343 if (fwdFuture != null) {
344 fwdFuture.complete(null);
345 }
346 }
347
348 @Override
349 public void onError(Objective objective, ObjectiveError error) {
350 log.warn("Failed to remove previous FwdObj for {}: {}", key, error);
351 if (fwdFuture != null) {
352 fwdFuture.complete(error);
353 }
354 }
355 };
356 srManager.flowObjectiveService
357 .forward(key.deviceId(), fwdObjBuilder.remove(context));
358 }
359
360 /**
Charles Chan868c9572018-06-15 18:54:18 -0700361 * Revokes ACL forwarding objectives for given XConnect.
362 *
363 * @param key XConnect store key
364 */
365 private void revokeAcl(XConnectStoreKey key) {
366 ForwardingObjective.Builder aclObjBuilder = aclObjBuilder(key.vlanId());
367 ObjectiveContext aclContext = new DefaultObjectiveContext(
368 (objective) -> log.debug("XConnect AclObj for {} populated", key),
369 (objective, error) ->
370 log.warn("Failed to populate XConnect AclObj for {}: {}", key, error));
371 srManager.flowObjectiveService
372 .forward(key.deviceId(), aclObjBuilder.remove(aclContext));
373 }
374
375 /**
Charles Chan82f19972016-05-17 13:13:55 -0700376 * Updates XConnect groups and flows for given key.
377 *
378 * @param key XConnect key
379 * @param prevPorts previous XConnect ports
380 * @param ports new XConnect ports
381 */
382 private void updateXConnect(XConnectStoreKey key, Set<PortNumber> prevPorts,
383 Set<PortNumber> ports) {
Charles Chan868c9572018-06-15 18:54:18 -0700384 // NOTE: ACL flow doesn't include port information. No need to update it.
385 // Pair port is built-in and thus not going to change. No need to update it.
386
Charles Chan82f19972016-05-17 13:13:55 -0700387 // remove old filter
Charles Chan868c9572018-06-15 18:54:18 -0700388 prevPorts.stream().filter(port -> !ports.contains(port)).forEach(port ->
389 revokeFilter(key, ImmutableSet.of(port)));
Charles Chan82f19972016-05-17 13:13:55 -0700390 // install new filter
Charles Chan868c9572018-06-15 18:54:18 -0700391 ports.stream().filter(port -> !prevPorts.contains(port)).forEach(port ->
392 populateFilter(key, ImmutableSet.of(port)));
Charles Chan82f19972016-05-17 13:13:55 -0700393
394 CompletableFuture<ObjectiveError> fwdFuture = new CompletableFuture<>();
395 CompletableFuture<ObjectiveError> nextFuture = new CompletableFuture<>();
396
397 if (xConnectNextObjStore.containsKey(key)) {
398 NextObjective nextObj = xConnectNextObjStore.get(key).value();
399 revokeFwd(key, nextObj, fwdFuture);
400
401 fwdFuture.thenAcceptAsync(fwdStatus -> {
402 if (fwdStatus == null) {
403 log.debug("Fwd removed. Now remove group {}", key);
404 revokeNext(key, nextObj, nextFuture);
405 }
406 });
407
408 nextFuture.thenAcceptAsync(nextStatus -> {
409 if (nextStatus == null) {
410 log.debug("Installing new group and flow for {}", key);
411 populateFwd(key, populateNext(key, ports));
412 }
413 });
414 } else {
415 log.warn("NextObj for {} does not exist in the store.", key);
416 }
417 }
418
419 /**
420 * Remove all groups on given device.
421 *
422 * @param deviceId device ID
423 */
Charles Chan868c9572018-06-15 18:54:18 -0700424 void removeDevice(DeviceId deviceId) {
Charles Chanfc115892016-06-17 14:28:07 -0700425 xConnectNextObjStore.entrySet().stream()
426 .filter(entry -> entry.getKey().deviceId().equals(deviceId))
Charles Chan868c9572018-06-15 18:54:18 -0700427 .forEach(entry -> xConnectNextObjStore.remove(entry.getKey()));
Charles Chanfc115892016-06-17 14:28:07 -0700428 log.debug("{} is removed from xConnectNextObjStore", deviceId);
Charles Chan82f19972016-05-17 13:13:55 -0700429 }
430
431 /**
432 * Creates a next objective builder for XConnect.
433 *
434 * @param key XConnect key
435 * @param ports set of XConnect ports
436 * @return next objective builder
437 */
438 private NextObjective.Builder nextObjBuilder(XConnectStoreKey key, Set<PortNumber> ports) {
439 int nextId = srManager.flowObjectiveService.allocateNextId();
440 TrafficSelector metadata =
441 DefaultTrafficSelector.builder().matchVlanId(key.vlanId()).build();
442 NextObjective.Builder nextObjBuilder = DefaultNextObjective
443 .builder().withId(nextId)
444 .withType(NextObjective.Type.BROADCAST).fromApp(srManager.appId)
445 .withMeta(metadata);
446 ports.forEach(port -> {
447 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
448 tBuilder.setOutput(port);
449 nextObjBuilder.addTreatment(tBuilder.build());
450 });
451 return nextObjBuilder;
452 }
453
454 /**
Charles Chan868c9572018-06-15 18:54:18 -0700455 * Creates a bridging forwarding objective builder for XConnect.
Charles Chan82f19972016-05-17 13:13:55 -0700456 *
457 * @param key XConnect key
458 * @param nextId next ID of the broadcast group for this XConnect key
Charles Chan868c9572018-06-15 18:54:18 -0700459 * @return forwarding objective builder
Charles Chan82f19972016-05-17 13:13:55 -0700460 */
461 private ForwardingObjective.Builder fwdObjBuilder(XConnectStoreKey key, int nextId) {
462 /*
463 * Driver should treat objectives with MacAddress.NONE and !VlanId.NONE
464 * as the VLAN cross-connect broadcast rules
465 */
466 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
467 sbuilder.matchVlanId(key.vlanId());
468 sbuilder.matchEthDst(MacAddress.NONE);
469
470 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
471 fob.withFlag(ForwardingObjective.Flag.SPECIFIC)
472 .withSelector(sbuilder.build())
473 .nextStep(nextId)
474 .withPriority(SegmentRoutingService.XCONNECT_PRIORITY)
475 .fromApp(srManager.appId)
476 .makePermanent();
477 return fob;
478 }
479
480 /**
Charles Chan868c9572018-06-15 18:54:18 -0700481 * Creates an ACL forwarding objective builder for XConnect.
482 *
483 * @param vlanId cross connect VLAN id
484 * @return forwarding objective builder
485 */
486 private ForwardingObjective.Builder aclObjBuilder(VlanId vlanId) {
487 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
488 sbuilder.matchVlanId(vlanId);
489
490 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
491
492 ForwardingObjective.Builder fob = DefaultForwardingObjective.builder();
493 fob.withFlag(ForwardingObjective.Flag.VERSATILE)
494 .withSelector(sbuilder.build())
495 .withTreatment(tbuilder.build())
496 .withPriority(SegmentRoutingService.XCONNECT_ACL_PRIORITY)
497 .fromApp(srManager.appId)
498 .makePermanent();
499 return fob;
500 }
501
502 /**
Charles Chan82f19972016-05-17 13:13:55 -0700503 * Creates a filtering objective builder for XConnect.
504 *
505 * @param key XConnect key
506 * @param port XConnect ports
507 * @return next objective builder
508 */
509 private FilteringObjective.Builder filterObjBuilder(XConnectStoreKey key, PortNumber port) {
510 FilteringObjective.Builder fob = DefaultFilteringObjective.builder();
511 fob.withKey(Criteria.matchInPort(port))
512 .addCondition(Criteria.matchVlanId(key.vlanId()))
513 .addCondition(Criteria.matchEthDst(MacAddress.NONE))
514 .withPriority(SegmentRoutingService.XCONNECT_PRIORITY);
515 return fob.permit().fromApp(srManager.appId);
516 }
517
Charles Chan868c9572018-06-15 18:54:18 -0700518 /**
519 * Add pair port to the given set of port.
520 *
521 * @param deviceId device Id
522 * @param ports ports specified in the xconnect config
523 * @return port specified in the xconnect config plus the pair port (if configured)
524 */
525 private Set<PortNumber> addPairPort(DeviceId deviceId, Set<PortNumber> ports) {
526 Set<PortNumber> newPorts = Sets.newHashSet(ports);
527 srManager.getPairLocalPort(deviceId).ifPresent(newPorts::add);
528 return newPorts;
529 }
530
Charles Chan82f19972016-05-17 13:13:55 -0700531 // TODO: Lambda closure in DefaultObjectiveContext cannot be serialized properly
532 // with Kryo 3.0.3. It will be fixed in 3.0.4. By then we can use
533 // DefaultObjectiveContext again.
534 private final class NextObjContext implements ObjectiveContext {
535 Objective.Operation op;
536 XConnectStoreKey key;
537
538 private NextObjContext(Objective.Operation op, XConnectStoreKey key) {
539 this.op = op;
540 this.key = key;
541 }
542
543 @Override
544 public void onSuccess(Objective objective) {
545 log.debug("XConnect NextObj for {} {}ED", key, op);
546 }
547
548 @Override
549 public void onError(Objective objective, ObjectiveError error) {
550 log.warn("Failed to {} XConnect NextObj for {}: {}", op, key, error);
551 }
552 }
553}