blob: 0de641a14f49994ed1a1dd0dc7fa81801329a611 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2015-present Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -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 */
Sho SHIMIZU6c28f832015-02-20 16:12:19 -080016package org.onosproject.net.intent.impl.compiler;
Ray Milkeya058c732014-10-08 13:52:34 -070017
Ray Milkeya058c732014-10-08 13:52:34 -070018import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
helenyrwu2a674902016-07-20 09:48:04 -070021import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
Brian O'Connorabafb502014-12-02 22:26:20 -080023import org.onosproject.net.ConnectPoint;
24import org.onosproject.net.DefaultPath;
helenyrwu2a674902016-07-20 09:48:04 -070025import org.onosproject.net.DeviceId;
26import org.onosproject.net.DisjointPath;
27import org.onosproject.net.EdgeLink;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.net.Link;
29import org.onosproject.net.Path;
helenyrwu2a674902016-07-20 09:48:04 -070030import org.onosproject.net.Port;
31import org.onosproject.net.PortNumber;
32import org.onosproject.net.device.DeviceService;
33import org.onosproject.net.flow.DefaultFlowRule;
34import org.onosproject.net.flow.DefaultTrafficSelector;
35import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.FlowRule;
37import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
39import org.onosproject.net.flow.instructions.Instruction;
40import org.onosproject.net.flow.instructions.Instructions;
41import org.onosproject.net.group.DefaultGroupBucket;
42import org.onosproject.net.group.DefaultGroupDescription;
43import org.onosproject.net.group.DefaultGroupKey;
44import org.onosproject.net.group.Group;
45import org.onosproject.net.group.GroupBucket;
46import org.onosproject.net.group.GroupBuckets;
47import org.onosproject.net.group.GroupDescription;
48import org.onosproject.net.group.GroupKey;
49import org.onosproject.net.group.GroupService;
50import org.onosproject.net.intent.FlowRuleIntent;
Brian O'Connorabafb502014-12-02 22:26:20 -080051import org.onosproject.net.intent.Intent;
helenyrwu2a674902016-07-20 09:48:04 -070052import org.onosproject.net.intent.IntentId;
Brian O'Connorabafb502014-12-02 22:26:20 -080053import org.onosproject.net.intent.PathIntent;
54import org.onosproject.net.intent.PointToPointIntent;
helenyrwu2a674902016-07-20 09:48:04 -070055import org.onosproject.net.intent.constraint.ProtectionConstraint;
56import org.onosproject.net.intent.impl.PathNotFoundException;
57import org.onosproject.net.link.LinkService;
Brian O'Connorabafb502014-12-02 22:26:20 -080058import org.onosproject.net.provider.ProviderId;
Thomas Vachuskaedc944c2014-11-04 15:42:25 -080059
helenyrwu2a674902016-07-20 09:48:04 -070060import java.nio.ByteBuffer;
Thomas Vachuskaedc944c2014-11-04 15:42:25 -080061import java.util.ArrayList;
helenyrwu2a674902016-07-20 09:48:04 -070062import java.util.Collections;
63import java.util.Iterator;
Thomas Vachuskaedc944c2014-11-04 15:42:25 -080064import java.util.List;
helenyrwu2a674902016-07-20 09:48:04 -070065import java.util.ListIterator;
Ray Milkeya058c732014-10-08 13:52:34 -070066
Thomas Vachuska425a2d72014-10-29 11:28:28 -070067import static java.util.Arrays.asList;
Brian O'Connorabafb502014-12-02 22:26:20 -080068import static org.onosproject.net.DefaultEdgeLink.createEdgeLink;
Thomas Vachuska425a2d72014-10-29 11:28:28 -070069
Ray Milkeya058c732014-10-08 13:52:34 -070070/**
Brian O'Connorabafb502014-12-02 22:26:20 -080071 * An intent compiler for {@link org.onosproject.net.intent.PointToPointIntent}.
Ray Milkeya058c732014-10-08 13:52:34 -070072 */
73@Component(immediate = true)
74public class PointToPointIntentCompiler
Thomas Vachuskaedc944c2014-11-04 15:42:25 -080075 extends ConnectivityIntentCompiler<PointToPointIntent> {
Ray Milkeya058c732014-10-08 13:52:34 -070076
Thomas Vachuskaedc944c2014-11-04 15:42:25 -080077 // TODO: use off-the-shell core provider ID
78 private static final ProviderId PID =
Brian O'Connorabafb502014-12-02 22:26:20 -080079 new ProviderId("core", "org.onosproject.core", true);
Sho SHIMIZU3908fde2014-11-19 16:30:22 -080080 // TODO: consider whether the default cost is appropriate or not
81 public static final int DEFAULT_COST = 1;
helenyrwu2a674902016-07-20 09:48:04 -070082 protected static final int PRIORITY = Intent.DEFAULT_INTENT_PRIORITY;
83 protected boolean erasePrimary = false;
84 protected boolean eraseBackup = false;
85
86 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 protected GroupService groupService;
88
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected LinkService linkService;
91
92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected DeviceService deviceService;
weibit50eb95b2014-10-25 21:47:54 -070094
Ray Milkeya058c732014-10-08 13:52:34 -070095 @Activate
96 public void activate() {
Ray Milkeya058c732014-10-08 13:52:34 -070097 intentManager.registerCompiler(PointToPointIntent.class, this);
98 }
99
100 @Deactivate
101 public void deactivate() {
102 intentManager.unregisterCompiler(PointToPointIntent.class);
103 }
104
105 @Override
Sho SHIMIZUec07ffd2016-02-22 20:45:21 -0800106 public List<Intent> compile(PointToPointIntent intent, List<Intent> installable) {
Brian O'Connorfa81eae2014-10-30 13:20:05 -0700107
Sho SHIMIZUde8e6b52014-11-13 11:23:17 -0800108 ConnectPoint ingressPoint = intent.ingressPoint();
109 ConnectPoint egressPoint = intent.egressPoint();
110
111 if (ingressPoint.deviceId().equals(egressPoint.deviceId())) {
helenyrwu2a674902016-07-20 09:48:04 -0700112 return createZeroHopIntent(ingressPoint, egressPoint, intent);
Sho SHIMIZUde8e6b52014-11-13 11:23:17 -0800113 }
Ray Milkeya058c732014-10-08 13:52:34 -0700114
helenyrwu2a674902016-07-20 09:48:04 -0700115 // proceed with no protected paths
116 if (!ProtectionConstraint.requireProtectedPath(intent)) {
117 return createUnprotectedIntent(ingressPoint, egressPoint, intent);
118 }
119
120 try {
121 // attempt to compute and implement backup path
122 return createProtectedIntent(ingressPoint, egressPoint, intent, installable);
123 } catch (PathNotFoundException e) {
124 // no disjoint path extant -- maximum one path exists between devices
125 return createSinglePathIntent(ingressPoint, egressPoint, intent, installable);
126 }
127 }
128
129 private List<Intent> createZeroHopIntent(ConnectPoint ingressPoint,
130 ConnectPoint egressPoint,
131 PointToPointIntent intent) {
132 List<Link> links = asList(createEdgeLink(ingressPoint, true), createEdgeLink(egressPoint, false));
133 return asList(createPathIntent(new DefaultPath(PID, links, DEFAULT_COST),
134 intent, PathIntent.ProtectionType.PRIMARY));
135 }
136
137 private List<Intent> createUnprotectedIntent(ConnectPoint ingressPoint,
138 ConnectPoint egressPoint,
139 PointToPointIntent intent) {
Ray Milkeya058c732014-10-08 13:52:34 -0700140 List<Link> links = new ArrayList<>();
Sho SHIMIZUde8e6b52014-11-13 11:23:17 -0800141 Path path = getPath(intent, ingressPoint.deviceId(),
helenyrwu2a674902016-07-20 09:48:04 -0700142 egressPoint.deviceId());
Sho SHIMIZUde8e6b52014-11-13 11:23:17 -0800143
Sho SHIMIZU3908fde2014-11-19 16:30:22 -0800144 links.add(createEdgeLink(ingressPoint, true));
Ray Milkeya058c732014-10-08 13:52:34 -0700145 links.addAll(path.links());
Sho SHIMIZU3908fde2014-11-19 16:30:22 -0800146 links.add(createEdgeLink(egressPoint, false));
Ray Milkeya058c732014-10-08 13:52:34 -0700147
Thomas Vachuskaedc944c2014-11-04 15:42:25 -0800148 return asList(createPathIntent(new DefaultPath(PID, links, path.cost(),
helenyrwu2a674902016-07-20 09:48:04 -0700149 path.annotations()), intent,
150 PathIntent.ProtectionType.PRIMARY));
151 }
152
153 //FIXME: Compatibility with EncapsulationConstraint
154 private List<Intent> createProtectedIntent(ConnectPoint ingressPoint,
155 ConnectPoint egressPoint,
156 PointToPointIntent intent,
157 List<Intent> installable) {
158 DisjointPath path = getDisjointPath(intent, ingressPoint.deviceId(),
159 egressPoint.deviceId());
160
161 List<Intent> reusableIntents = null;
162 if (installable != null) {
163 reusableIntents = filterInvalidSubIntents(installable, intent);
164 if (reusableIntents.size() == installable.size()) {
165 // all old paths are still viable
166 return installable;
167 }
168 }
169
170 List<Intent> intentList = new ArrayList<>();
171
172 // primary path intent
173 List<Link> links = new ArrayList<>();
174 links.addAll(path.links());
175 links.add(createEdgeLink(egressPoint, false));
176
177 // backup path intent
178 List<Link> backupLinks = new ArrayList<>();
179 backupLinks.addAll(path.backup().links());
180 backupLinks.add(createEdgeLink(egressPoint, false));
181
182 /*
183 * One of the old paths is still entirely intact. This old path has
184 * already been made primary, so we must add a backup path intent
185 * and modify the failover group treatment accordingly.
186 */
187 if (reusableIntents != null && reusableIntents.size() > 1) {
188 /*
189 * Ensures that the egress port on source device is different than
190 * that of existing path so that failover group will be useful
191 * (would not be useful if both output ports in group bucket were
192 * the same). Does not necessarily ensure that the new backup path
193 * is entirely disjoint from the old path.
194 */
195 PortNumber primaryPort = getPrimaryPort(intent);
196 if (primaryPort != null && !links.get(0).src().port().equals(primaryPort)) {
197 reusableIntents.add(createPathIntent(new DefaultPath(PID, links,
198 path.cost(), path.annotations()),
199 intent, PathIntent.ProtectionType.BACKUP));
200 updateFailoverGroup(intent, links);
201 return reusableIntents;
202
203 } else {
204 reusableIntents.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().cost(),
205 path.backup().annotations()), intent, PathIntent.ProtectionType.BACKUP));
206 updateFailoverGroup(intent, backupLinks);
207 return reusableIntents;
208 }
209 }
210
211 intentList.add(createPathIntent(new DefaultPath(PID, links, path.cost(), path.annotations()),
212 intent, PathIntent.ProtectionType.PRIMARY));
213 intentList.add(createPathIntent(new DefaultPath(PID, backupLinks, path.backup().cost(),
214 path.backup().annotations()), intent, PathIntent.ProtectionType.BACKUP));
215
216 // Create fast failover flow rule intent or, if it already exists,
217 // add contents appropriately.
218 if (groupService.getGroup(ingressPoint.deviceId(),
219 makeGroupKey(intent.id())) == null) {
220 // manufactured fast failover flow rule intent
221 createFailoverTreatmentGroup(path.links(), path.backup().links(), intent);
222
223 FlowRuleIntent frIntent = new FlowRuleIntent(intent.appId(),
224 createFailoverFlowRules(intent),
225 asList(ingressPoint.deviceId()),
226 PathIntent.ProtectionType.FAILOVER);
227 intentList.add(frIntent);
228 } else {
229 updateFailoverGroup(intent, links);
230 updateFailoverGroup(intent, backupLinks);
231 }
232
233 return intentList;
234 }
235
236 private List<Intent> createSinglePathIntent(ConnectPoint ingressPoint,
237 ConnectPoint egressPoint,
238 PointToPointIntent intent,
239 List<Intent> installable) {
240 List<Link> links = new ArrayList<>();
241 Path onlyPath = getPath(intent, ingressPoint.deviceId(),
242 egressPoint.deviceId());
243
244 List<Intent> reusableIntents = null;
245 if (installable != null) {
246 reusableIntents = filterInvalidSubIntents(installable, intent);
247 if (reusableIntents.size() == installable.size()) {
248 // all old paths are still viable
249 return installable;
250 }
251 }
252
253 // If there exists a full path from old installable intents,
254 // return the intents that comprise it.
255 if (reusableIntents != null && reusableIntents.size() > 1) {
256 return reusableIntents;
257 } else {
258 links.add(createEdgeLink(ingressPoint, true));
259 links.addAll(onlyPath.links());
260 links.add(createEdgeLink(egressPoint, false));
261
262 return asList(createPathIntent(new DefaultPath(PID, links, onlyPath.cost(),
263 onlyPath.annotations()),
264 intent, PathIntent.ProtectionType.PRIMARY));
265 }
Ray Milkeya058c732014-10-08 13:52:34 -0700266 }
267
268 /**
269 * Creates a path intent from the specified path and original
270 * connectivity intent.
271 *
Thomas Vachuskab97cf282014-10-20 23:31:12 -0700272 * @param path path to create an intent for
Ray Milkeya058c732014-10-08 13:52:34 -0700273 * @param intent original intent
helenyrwu2a674902016-07-20 09:48:04 -0700274 * @param type primary or backup
Ray Milkeya058c732014-10-08 13:52:34 -0700275 */
276 private Intent createPathIntent(Path path,
helenyrwu2a674902016-07-20 09:48:04 -0700277 PointToPointIntent intent,
278 PathIntent.ProtectionType type) {
Ray Milkeyebc5d222015-03-18 15:45:36 -0700279 return PathIntent.builder()
280 .appId(intent.appId())
281 .selector(intent.selector())
282 .treatment(intent.treatment())
283 .path(path)
284 .constraints(intent.constraints())
285 .priority(intent.priority())
helenyrwu2a674902016-07-20 09:48:04 -0700286 .setType(type)
Ray Milkeyebc5d222015-03-18 15:45:36 -0700287 .build();
Ray Milkeya058c732014-10-08 13:52:34 -0700288 }
289
helenyrwu2a674902016-07-20 09:48:04 -0700290 /**
291 * Gets primary port number through failover group associated
292 * with this intent.
293 */
294 private PortNumber getPrimaryPort(PointToPointIntent intent) {
295 Group group = groupService.getGroup(intent.ingressPoint().deviceId(),
296 makeGroupKey(intent.id()));
297 PortNumber primaryPort = null;
298 if (group != null) {
299 List<GroupBucket> buckets = group.buckets().buckets();
300 Iterator<GroupBucket> iterator = buckets.iterator();
301 while (primaryPort == null && iterator.hasNext()) {
302 GroupBucket bucket = iterator.next();
303 Instruction individualInstruction = bucket.treatment().allInstructions().get(0);
304 if (individualInstruction instanceof Instructions.OutputInstruction) {
305 Instructions.OutputInstruction outInstruction =
306 (Instructions.OutputInstruction) individualInstruction;
307 PortNumber tempPortNum = outInstruction.port();
308 Port port = deviceService.getPort(intent.ingressPoint().deviceId(),
309 tempPortNum);
310 if (port != null && port.isEnabled()) {
311 primaryPort = tempPortNum;
312 }
313 }
314 }
315 }
316 return primaryPort;
317 }
318
319 /**
320 * Creates group key unique to each intent.
321 */
322 public static GroupKey makeGroupKey(IntentId intentId) {
323 ByteBuffer buffer = ByteBuffer.allocate(Long.BYTES);
324 buffer.putLong(intentId.fingerprint());
325 return new DefaultGroupKey(buffer.array());
326 }
327
328 /**
329 * Creates a new failover group with the initial ports of the links
330 * from the primary and backup path.
331 *
332 * @param links links from the primary path
333 * @param backupLinks links from the backup path
334 * @param intent intent from which this call originates
335 */
336 private void createFailoverTreatmentGroup(List<Link> links,
337 List<Link> backupLinks,
338 PointToPointIntent intent) {
339
340 List<GroupBucket> buckets = new ArrayList<>();
341
342 TrafficTreatment.Builder tBuilderIn = DefaultTrafficTreatment.builder();
343 ConnectPoint src = links.get(0).src();
344 tBuilderIn.setOutput(src.port());
345
346 TrafficTreatment.Builder tBuilderIn2 = DefaultTrafficTreatment.builder();
347 ConnectPoint src2 = backupLinks.get(0).src();
348 tBuilderIn2.setOutput(src2.port());
349
350 buckets.add(DefaultGroupBucket.createFailoverGroupBucket(tBuilderIn.build(), src.port(), null));
351 buckets.add(DefaultGroupBucket.createFailoverGroupBucket(tBuilderIn2.build(), src2.port(), null));
352
353 GroupBuckets groupBuckets = new GroupBuckets(buckets);
354
355 GroupDescription groupDesc = new DefaultGroupDescription(src.deviceId(), Group.Type.FAILOVER,
356 groupBuckets, makeGroupKey(intent.id()), null, intent.appId());
357 groupService.addGroup(groupDesc);
358 }
359
360 /**
361 * Manufactures flow rule with treatment that is defined by failover
362 * group and traffic selector determined by ingress port of the intent.
363 *
364 * @param intent intent which is being compiled (for appId)
365 * @return a list of a singular flow rule with fast failover
366 * outport traffic treatment
367 */
368 private List<FlowRule> createFailoverFlowRules(PointToPointIntent intent) {
369 List<FlowRule> flowRules = new ArrayList<>();
370
371 ConnectPoint ingress = intent.ingressPoint();
372 DeviceId deviceId = ingress.deviceId();
373
374 // flow rule with failover traffic treatment
375 TrafficSelector trafficSelector = DefaultTrafficSelector.builder(intent.selector())
376 .matchInPort(ingress.port()).build();
377
378 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
379 flowRules.add(flowRuleBuilder.withSelector(trafficSelector)
380 .withTreatment(buildFailoverTreatment(deviceId, makeGroupKey(intent.id())))
381 .fromApp(intent.appId())
382 .makePermanent()
383 .forDevice(deviceId)
384 .withPriority(PRIORITY)
385 .build());
386
387 return flowRules;
388 }
389
390 private TrafficTreatment buildFailoverTreatment(DeviceId srcDevice,
391 GroupKey groupKey) {
392 Group group = groupService.getGroup(srcDevice, groupKey);
393 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
394 TrafficTreatment trafficTreatment = tBuilder.group(group.id()).build();
395 return trafficTreatment;
396 }
397
398 /**
399 * Deletes intents from the given list if the ports or links the intent
400 * relies on are no longer viable. The failover flow rule intent is never
401 * deleted -- only its contents are updated.
402 *
403 * @param oldInstallables list of intents to examine
404 * @return list of reusable installable intents
405 */
406 private List<Intent> filterInvalidSubIntents(List<Intent> oldInstallables,
407 PointToPointIntent pointIntent) {
408 List<Intent> intentList = new ArrayList<>();
409 intentList.addAll(oldInstallables);
410 erasePrimary = false;
411 eraseBackup = false;
412 if (intentList != null) {
413 Iterator<Intent> iterator = intentList.iterator();
414 while (iterator.hasNext() && !(erasePrimary && eraseBackup)) {
415 Intent intent = iterator.next();
416 intent.resources().forEach(resource -> {
417 if (resource instanceof Link) {
418 Link link = (Link) resource;
419 if (link.state() == Link.State.INACTIVE) {
420 setPathsToRemove(intent);
421 } else if (link instanceof EdgeLink) {
422 ConnectPoint connectPoint = (link.src().elementId() instanceof DeviceId)
423 ? link.src() : link.dst();
424 Port port = deviceService.getPort(connectPoint.deviceId(), connectPoint.port());
425 if (port == null || !port.isEnabled()) {
426 setPathsToRemove(intent);
427 }
428 } else {
429 Port port1 = deviceService.getPort(link.src().deviceId(), link.src().port());
430 Port port2 = deviceService.getPort(link.dst().deviceId(), link.dst().port());
431 if (port1 == null || !port1.isEnabled() || port2 == null || !port2.isEnabled()) {
432 setPathsToRemove(intent);
433 }
434 }
435 }
436 });
437 }
438 removeAndUpdateIntents(intentList, pointIntent);
439 }
440 return intentList;
441 }
442
443 /**
444 * Sets instance variables erasePrimary and eraseBackup. If erasePrimary,
445 * the primary path is no longer viable and related intents will be deleted.
446 * If eraseBackup, the backup path is no longer viable and related intents
447 * will be deleted.
448 *
449 * @param intent intent whose resources are found to be disabled/inactive:
450 * if intent is part of primary path, primary path set for removal;
451 * if intent is part of backup path, backup path set for removal;
452 * if bad intent is of type failover, the ingress point is down,
453 * and both paths are rendered inactive.
454 * @return true if both primary and backup paths are to be removed
455 */
456 private boolean setPathsToRemove(Intent intent) {
457 if (intent instanceof FlowRuleIntent) {
458 FlowRuleIntent frIntent = (FlowRuleIntent) intent;
459 PathIntent.ProtectionType type = frIntent.type();
460 if (type == PathIntent.ProtectionType.PRIMARY || type == PathIntent.ProtectionType.FAILOVER) {
461 erasePrimary = true;
462 }
463 if (type == PathIntent.ProtectionType.BACKUP || type == PathIntent.ProtectionType.FAILOVER) {
464 eraseBackup = true;
465 }
466 }
467 return erasePrimary && eraseBackup;
468 }
469
470 /**
471 * Removes intents from installables list, depending on the values
472 * of instance variables erasePrimary and eraseBackup. Flow rule intents
473 * that contain the manufactured fast failover flow rules are never deleted.
474 * The contents are simply modified as necessary. If cleanUpIntents size
475 * is greater than 1 (failover intent), then one whole path from previous
476 * installables must be still viable.
477 *
478 * @param cleanUpIntents list of installable intents
479 */
480 private void removeAndUpdateIntents(List<Intent> cleanUpIntents,
481 PointToPointIntent pointIntent) {
482 ListIterator<Intent> iterator = cleanUpIntents.listIterator();
483 while (iterator.hasNext()) {
484 Intent cIntent = iterator.next();
485 if (cIntent instanceof FlowRuleIntent) {
486 FlowRuleIntent fIntent = (FlowRuleIntent) cIntent;
487 if (fIntent.type() == PathIntent.ProtectionType.PRIMARY && erasePrimary) {
488 // remove primary path's flow rule intents
489 iterator.remove();
490 } else if (fIntent.type() == PathIntent.ProtectionType.BACKUP && eraseBackup) {
491 //remove backup path's flow rule intents
492 iterator.remove();
493 } else if (fIntent.type() == PathIntent.ProtectionType.BACKUP && erasePrimary) {
494 // promote backup path's flow rule intents to primary
495 iterator.set(new FlowRuleIntent(fIntent, PathIntent.ProtectionType.PRIMARY));
496 }
497 }
498 }
499 // remove buckets whose watchports are disabled if the failover group exists
500 Group group = groupService.getGroup(pointIntent.ingressPoint().deviceId(),
501 makeGroupKey(pointIntent.id()));
502 if (group != null) {
503 updateFailoverGroup(pointIntent);
504 }
505 }
506
507 // Removes buckets whose treatments rely on disabled ports from the
508 // failover group.
509 private void updateFailoverGroup(PointToPointIntent pointIntent) {
510 DeviceId deviceId = pointIntent.ingressPoint().deviceId();
511 GroupKey groupKey = makeGroupKey(pointIntent.id());
512 Group group = groupService.getGroup(deviceId, groupKey);
513 Iterator<GroupBucket> groupIterator = group.buckets().buckets().iterator();
514 while (groupIterator.hasNext()) {
515 GroupBucket bucket = groupIterator.next();
516 Instruction individualInstruction = bucket.treatment().allInstructions().get(0);
517 if (individualInstruction instanceof Instructions.OutputInstruction) {
518 Instructions.OutputInstruction outInstruction =
519 (Instructions.OutputInstruction) individualInstruction;
520 Port port = deviceService.getPort(deviceId, outInstruction.port());
521 if (port == null || !port.isEnabled()) {
522 GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
523 groupService.removeBucketsFromGroup(deviceId, groupKey,
524 removeBuckets, groupKey,
525 pointIntent.appId());
526 }
527 }
528 }
529 }
530
531 // Adds failover group bucket with treatment outport determined by the
532 // ingress point of the links.
533 private void updateFailoverGroup(PointToPointIntent intent, List<Link> links) {
534 GroupKey groupKey = makeGroupKey(intent.id());
535
536 TrafficTreatment.Builder tBuilderIn = DefaultTrafficTreatment.builder();
537 ConnectPoint src = links.get(0).src();
538 tBuilderIn.setOutput(src.port());
539 GroupBucket bucket = DefaultGroupBucket.createFailoverGroupBucket(tBuilderIn.build(), src.port(), null);
540 GroupBuckets addBuckets = new GroupBuckets(Collections.singletonList(bucket));
541
542 groupService.addBucketsToGroup(src.deviceId(), groupKey, addBuckets, groupKey, intent.appId());
543 }
Ray Milkeya058c732014-10-08 13:52:34 -0700544}