blob: b9fa750accba589982d1713ab47109f7fdbb684a [file] [log] [blame]
Michele Santuari9a8d16d2016-03-24 10:37:58 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Michele Santuari9a8d16d2016-03-24 10:37:58 -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.drivers.corsa;
18
19import com.google.common.cache.Cache;
20import com.google.common.cache.CacheBuilder;
21import com.google.common.cache.RemovalCause;
22import com.google.common.cache.RemovalNotification;
Michele Santuarid2c8b152016-03-30 17:57:56 -070023import com.google.common.collect.ImmutableSet;
Michele Santuari9a8d16d2016-03-24 10:37:58 -070024import org.onlab.osgi.ServiceDirectory;
25import org.onlab.packet.Ethernet;
26import org.onlab.util.KryoNamespace;
27import org.onosproject.core.ApplicationId;
28import org.onosproject.core.CoreService;
29import org.onosproject.net.DeviceId;
30import org.onosproject.net.behaviour.NextGroup;
31import org.onosproject.net.behaviour.Pipeliner;
32import org.onosproject.net.behaviour.PipelinerContext;
33import org.onosproject.net.device.DeviceService;
34import org.onosproject.net.driver.AbstractHandlerBehaviour;
35import org.onosproject.net.flow.DefaultFlowRule;
36import org.onosproject.net.flow.DefaultTrafficSelector;
37import org.onosproject.net.flow.DefaultTrafficTreatment;
38import org.onosproject.net.flow.FlowRule;
39import org.onosproject.net.flow.FlowRuleOperations;
40import org.onosproject.net.flow.FlowRuleOperationsContext;
41import org.onosproject.net.flow.FlowRuleService;
42import org.onosproject.net.flow.TrafficSelector;
43import org.onosproject.net.flow.TrafficTreatment;
44import org.onosproject.net.flow.criteria.Criteria;
45import org.onosproject.net.flow.criteria.Criterion;
46import org.onosproject.net.flow.criteria.EthCriterion;
47import org.onosproject.net.flow.criteria.EthTypeCriterion;
48import org.onosproject.net.flow.criteria.IPCriterion;
49import org.onosproject.net.flow.criteria.PortCriterion;
50import org.onosproject.net.flow.criteria.VlanIdCriterion;
Pier Luigif90c6502017-03-16 10:06:21 +010051import org.onosproject.net.flowobjective.DefaultForwardingObjective;
Michele Santuari9a8d16d2016-03-24 10:37:58 -070052import org.onosproject.net.flowobjective.FilteringObjective;
53import org.onosproject.net.flowobjective.FlowObjectiveStore;
54import org.onosproject.net.flowobjective.ForwardingObjective;
55import org.onosproject.net.flowobjective.NextObjective;
56import org.onosproject.net.flowobjective.Objective;
57import org.onosproject.net.flowobjective.ObjectiveError;
58import org.onosproject.net.group.DefaultGroupBucket;
59import org.onosproject.net.group.DefaultGroupDescription;
60import org.onosproject.net.group.DefaultGroupKey;
61import org.onosproject.net.group.Group;
62import org.onosproject.net.group.GroupBucket;
63import org.onosproject.net.group.GroupBuckets;
64import org.onosproject.net.group.GroupDescription;
65import org.onosproject.net.group.GroupEvent;
66import org.onosproject.net.group.GroupKey;
67import org.onosproject.net.group.GroupListener;
68import org.onosproject.net.group.GroupService;
69import org.onosproject.net.meter.MeterService;
70import org.slf4j.Logger;
71
72import java.util.Collection;
73import java.util.Collections;
74import java.util.List;
75import java.util.Objects;
76import java.util.Set;
77import java.util.concurrent.Executors;
78import java.util.concurrent.ScheduledExecutorService;
79import java.util.concurrent.TimeUnit;
80import java.util.stream.Collectors;
81
82import static org.onlab.util.Tools.groupedThreads;
83import static org.onosproject.net.flow.FlowRule.Builder;
Pier Luigif90c6502017-03-16 10:06:21 +010084import static org.onosproject.net.flowobjective.Objective.Operation.ADD;
Michele Santuari9a8d16d2016-03-24 10:37:58 -070085import static org.slf4j.LoggerFactory.getLogger;
86
87/**
88 * Abstraction of the Corsa pipeline handler.
89 */
90public abstract class AbstractCorsaPipeline extends AbstractHandlerBehaviour implements Pipeliner {
91
92
93 private final Logger log = getLogger(getClass());
94
95 private ServiceDirectory serviceDirectory;
96 protected FlowRuleService flowRuleService;
97 private CoreService coreService;
Pier Ventredb673552016-07-20 15:37:19 +020098 protected GroupService groupService;
Michele Santuari9a8d16d2016-03-24 10:37:58 -070099 protected MeterService meterService;
Pier Ventredb673552016-07-20 15:37:19 +0200100 protected FlowObjectiveStore flowObjectiveStore;
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700101 protected DeviceId deviceId;
102 protected ApplicationId appId;
103 protected DeviceService deviceService;
104
Pier Ventredb673552016-07-20 15:37:19 +0200105 protected KryoNamespace appKryo = new KryoNamespace.Builder()
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700106 .register(GroupKey.class)
107 .register(DefaultGroupKey.class)
108 .register(CorsaGroup.class)
109 .register(byte[].class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700110 .build("AbstractCorsaPipeline");
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700111
112 private Cache<GroupKey, NextObjective> pendingGroups;
Pier Ventredb673552016-07-20 15:37:19 +0200113 protected Cache<Integer, NextObjective> pendingNext;
114
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700115
116 private ScheduledExecutorService groupChecker =
117 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner",
Yuta HIGUCHI1624df12016-07-21 16:54:33 -0700118 "ovs-corsa-%d", log));
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700119
120 protected static final int CONTROLLER_PRIORITY = 255;
121 protected static final int DROP_PRIORITY = 0;
122 protected static final int HIGHEST_PRIORITY = 0xffff;
123 protected static final String APPID = "org.onosproject.drivers.corsa.CorsaPipeline";
124
125 @Override
126 public void init(DeviceId deviceId, PipelinerContext context) {
127 this.serviceDirectory = context.directory();
128 this.deviceId = deviceId;
129
130 pendingGroups = CacheBuilder.newBuilder()
131 .expireAfterWrite(20, TimeUnit.SECONDS)
132 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
133 if (notification.getCause() == RemovalCause.EXPIRED) {
134 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
135 }
136 }).build();
137
Pier Ventredb673552016-07-20 15:37:19 +0200138 pendingNext = CacheBuilder.newBuilder()
139 .expireAfterWrite(20, TimeUnit.SECONDS)
140 .removalListener((RemovalNotification<Integer, NextObjective> notification) -> {
141 if (notification.getCause() == RemovalCause.EXPIRED) {
142 notification.getValue().context()
143 .ifPresent(c -> c.onError(notification.getValue(),
144 ObjectiveError.FLOWINSTALLATIONFAILED));
145 }
146 }).build();
147
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700148 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500, TimeUnit.MILLISECONDS);
149
150 coreService = serviceDirectory.get(CoreService.class);
151 flowRuleService = serviceDirectory.get(FlowRuleService.class);
152 groupService = serviceDirectory.get(GroupService.class);
153 meterService = serviceDirectory.get(MeterService.class);
154 deviceService = serviceDirectory.get(DeviceService.class);
155 flowObjectiveStore = context.store();
156
157 groupService.addListener(new InnerGroupListener());
158
159 appId = coreService.registerApplication(APPID);
160
161 initializePipeline();
162 }
163
164 protected abstract void initializePipeline();
165
166 protected void pass(Objective obj) {
167 obj.context().ifPresent(context -> context.onSuccess(obj));
168 }
169
170 protected void fail(Objective obj, ObjectiveError error) {
171 obj.context().ifPresent(context -> context.onError(obj, error));
172 }
173
174 private class GroupChecker implements Runnable {
175
176 @Override
177 public void run() {
178 Set<GroupKey> keys = pendingGroups.asMap().keySet().stream()
179 .filter(key -> groupService.getGroup(deviceId, key) != null)
180 .collect(Collectors.toSet());
181
Sho SHIMIZUa09e1bb2016-08-01 14:25:25 -0700182 keys.forEach(key -> {
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700183 NextObjective obj = pendingGroups.getIfPresent(key);
184 if (obj == null) {
185 return;
186 }
187 pass(obj);
188 pendingGroups.invalidate(key);
189 log.info("Heard back from group service for group {}. "
190 + "Applying pending forwarding objectives", obj.id());
191 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
192 });
193 }
194 }
195
196 private class CorsaGroup implements NextGroup {
197
198 private final GroupKey key;
199
200 public CorsaGroup(GroupKey key) {
201 this.key = key;
202 }
203
204 public GroupKey key() {
205 return key;
206 }
207
208 @Override
209 public byte[] data() {
210 return appKryo.serialize(key);
211 }
212
213 }
214
215 @Override
216 public List<String> getNextMappings(NextGroup nextGroup) {
217 //TODO: to be implemented
218 return Collections.emptyList();
219 }
220
221 private class InnerGroupListener implements GroupListener {
222 @Override
223 public void event(GroupEvent event) {
224 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
225 GroupKey key = event.subject().appCookie();
226
227 NextObjective obj = pendingGroups.getIfPresent(key);
228 if (obj != null) {
229 flowObjectiveStore.putNextGroup(obj.id(), new CorsaGroup(key));
230 pass(obj);
231 pendingGroups.invalidate(key);
232 }
233 }
234 }
235 }
236
237
238 @Override
239 public void filter(FilteringObjective filteringObjective) {
240 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
241 processFilter(filteringObjective,
Pier Luigif90c6502017-03-16 10:06:21 +0100242 filteringObjective.op() == ADD,
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700243 filteringObjective.appId());
244 } else {
245 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
246 }
247 }
248
249 private void processFilter(FilteringObjective filt, boolean install,
250 ApplicationId applicationId) {
251 // This driver only processes filtering criteria defined with switch
252 // ports as the key
253 PortCriterion port;
254 if (!filt.key().equals(Criteria.dummy()) &&
255 filt.key().type() == Criterion.Type.IN_PORT) {
256 port = (PortCriterion) filt.key();
257 } else {
258 log.warn("No key defined in filtering objective from app: {}. Not"
259 + "processing filtering objective", applicationId);
260 fail(filt, ObjectiveError.UNKNOWN);
261 return;
262 }
263 // convert filtering conditions for switch-intfs into flowrules
264 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
265 for (Criterion c : filt.conditions()) {
266 if (c.type() == Criterion.Type.ETH_DST) {
267 EthCriterion eth = (EthCriterion) c;
268 FlowRule.Builder rule = processEthFiler(filt, eth, port);
269 rule.forDevice(deviceId)
270 .fromApp(applicationId);
271 ops = install ? ops.add(rule.build()) : ops.remove(rule.build());
272
273 } else if (c.type() == Criterion.Type.VLAN_VID) {
274 VlanIdCriterion vlan = (VlanIdCriterion) c;
275 FlowRule.Builder rule = processVlanFiler(filt, vlan, port);
276 rule.forDevice(deviceId)
277 .fromApp(applicationId);
278 ops = install ? ops.add(rule.build()) : ops.remove(rule.build());
279
280 } else if (c.type() == Criterion.Type.IPV4_DST) {
281 IPCriterion ip = (IPCriterion) c;
282 FlowRule.Builder rule = processIpFilter(filt, ip, port);
283 rule.forDevice(deviceId)
284 .fromApp(applicationId);
285 ops = install ? ops.add(rule.build()) : ops.remove(rule.build());
286
287 } else {
288 log.warn("Driver does not currently process filtering condition"
289 + " of type: {}", c.type());
290 fail(filt, ObjectiveError.UNSUPPORTED);
291 }
292 }
293 // apply filtering flow rules
294 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
295 @Override
296 public void onSuccess(FlowRuleOperations ops) {
297 pass(filt);
298 log.info("Applied filtering rules");
299 }
300
301 @Override
302 public void onError(FlowRuleOperations ops) {
303 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
304 log.info("Failed to apply filtering rules");
305 }
306 }));
307 }
308
309 protected abstract Builder processEthFiler(FilteringObjective filt,
310 EthCriterion eth, PortCriterion port);
311
312 protected abstract Builder processVlanFiler(FilteringObjective filt,
313 VlanIdCriterion vlan, PortCriterion port);
314
315 protected abstract Builder processIpFilter(FilteringObjective filt,
316 IPCriterion ip, PortCriterion port);
317
318
319 @Override
320 public void forward(ForwardingObjective fwd) {
Pier Ventredb673552016-07-20 15:37:19 +0200321
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700322 Collection<FlowRule> rules;
323 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
324
325 rules = processForward(fwd);
326 switch (fwd.op()) {
327 case ADD:
328 rules.stream()
329 .filter(Objects::nonNull)
330 .forEach(flowBuilder::add);
331 break;
332 case REMOVE:
333 rules.stream()
334 .filter(Objects::nonNull)
335 .forEach(flowBuilder::remove);
336 break;
337 default:
338 fail(fwd, ObjectiveError.UNKNOWN);
339 log.warn("Unknown forwarding type {}", fwd.op());
340 }
341
342 flowRuleService.apply(flowBuilder.build(new FlowRuleOperationsContext() {
343 @Override
344 public void onSuccess(FlowRuleOperations ops) {
345 pass(fwd);
346 }
347
348 @Override
349 public void onError(FlowRuleOperations ops) {
350 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
351 }
352 }));
353
354 }
355
356 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
357 switch (fwd.flag()) {
358 case SPECIFIC:
359 return processSpecific(fwd);
360 case VERSATILE:
Pier Luigif90c6502017-03-16 10:06:21 +0100361 fwd = preProcessVersatile(fwd);
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700362 return processVersatile(fwd);
363 default:
364 fail(fwd, ObjectiveError.UNKNOWN);
365 log.warn("Unknown forwarding flag {}", fwd.flag());
366 }
Michele Santuarid2c8b152016-03-30 17:57:56 -0700367 return ImmutableSet.of();
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700368 }
369
370 private Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
371 log.debug("Processing specific forwarding objective");
372 TrafficSelector selector = fwd.selector();
Pier Ventredb673552016-07-20 15:37:19 +0200373 EthTypeCriterion ethTypeCriterion =
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700374 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
Pier Ventredb673552016-07-20 15:37:19 +0200375 VlanIdCriterion vlanIdCriterion =
376 (VlanIdCriterion) selector.getCriterion(Criterion.Type.VLAN_VID);
377 if (ethTypeCriterion != null) {
378 short et = ethTypeCriterion.ethType().toShort();
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700379 if (et == Ethernet.TYPE_IPV4) {
380 return processSpecificRoute(fwd);
381 } else if (et == Ethernet.TYPE_VLAN) {
382 /* The ForwardingObjective must specify VLAN ethtype in order to use the Transit Circuit */
383 return processSpecificSwitch(fwd);
384 }
Pier Ventredb673552016-07-20 15:37:19 +0200385 } else if (vlanIdCriterion != null) {
386 return processSpecificSwitch(fwd);
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700387 }
388
389 fail(fwd, ObjectiveError.UNSUPPORTED);
Michele Santuarid2c8b152016-03-30 17:57:56 -0700390 return ImmutableSet.of();
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700391 }
392
393 protected Collection<FlowRule> processSpecificSwitch(ForwardingObjective fwd) {
394 /* Not supported by until CorsaPipelineV3 */
395 log.warn("Vlan switching not supported in ovs-corsa driver");
396 fail(fwd, ObjectiveError.UNSUPPORTED);
Michele Santuarid2c8b152016-03-30 17:57:56 -0700397 return ImmutableSet.of();
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700398 }
399
Pier Luigif90c6502017-03-16 10:06:21 +0100400 private ForwardingObjective preProcessVersatile(ForwardingObjective fwd) {
401 // The Corsa devices don't support the clear deferred actions
402 // so for now we have to filter this instruction for the fwd
403 // objectives sent by the Packet Manager before to create the
404 // flow rule
405 if (fwd.treatment().clearedDeferred()) {
406 // First we create a new treatment without the unsupported action
407 TrafficTreatment.Builder noClearTreatment = DefaultTrafficTreatment.builder();
408 fwd.treatment().allInstructions().forEach(noClearTreatment::add);
409 // Then we create a new forwarding objective without the unsupported action
410 ForwardingObjective.Builder noClearFwd = DefaultForwardingObjective.builder(fwd);
411 noClearFwd.withTreatment(noClearTreatment.build());
412 // According to the operation we substitute fwd with the correct objective
413 switch (fwd.op()) {
414 case ADD:
415 fwd = noClearFwd.add(fwd.context().orElse(null));
416 break;
417 case REMOVE:
418 fwd = noClearFwd.remove(fwd.context().orElse(null));
419 break;
420 default:
421 log.warn("Unknown operation {}", fwd.op());
422 }
423 }
424 return fwd;
425 }
426
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700427 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
428 log.debug("Processing vesatile forwarding objective");
429 TrafficSelector selector = fwd.selector();
430
431 EthTypeCriterion ethType =
432 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
433 if (ethType == null) {
434 log.error("Versatile forwarding objective must include ethType");
435 fail(fwd, ObjectiveError.UNKNOWN);
Michele Santuarid2c8b152016-03-30 17:57:56 -0700436 return ImmutableSet.of();
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700437 }
438 Builder rule = DefaultFlowRule.builder()
439 .forDevice(deviceId)
440 .withSelector(fwd.selector())
441 .withTreatment(fwd.treatment())
442 .withPriority(fwd.priority())
443 .fromApp(fwd.appId())
444 .makePermanent();
445 if (ethType.ethType().toShort() == Ethernet.TYPE_ARP) {
446 return processArpTraffic(fwd, rule);
447 } else if (ethType.ethType().toShort() == Ethernet.TYPE_LLDP ||
448 ethType.ethType().toShort() == Ethernet.TYPE_BSN) {
449 return processLinkDiscovery(fwd, rule);
450 } else if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
451 return processIpTraffic(fwd, rule);
452 }
453 log.warn("Driver does not support given versatile forwarding objective");
454 fail(fwd, ObjectiveError.UNSUPPORTED);
Michele Santuarid2c8b152016-03-30 17:57:56 -0700455 return ImmutableSet.of();
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700456 }
457
458 protected abstract Collection<FlowRule> processArpTraffic(ForwardingObjective fwd, Builder rule);
459
460 protected abstract Collection<FlowRule> processLinkDiscovery(ForwardingObjective fwd, Builder rule);
461
462 protected abstract Collection<FlowRule> processIpTraffic(ForwardingObjective fwd, Builder rule);
463
464 private Collection<FlowRule> processSpecificRoute(ForwardingObjective fwd) {
465 TrafficSelector filteredSelector =
466 DefaultTrafficSelector.builder()
467 .matchEthType(Ethernet.TYPE_IPV4)
468 .matchIPDst(
469 ((IPCriterion) fwd.selector().getCriterion(Criterion.Type.IPV4_DST)).ip())
470 .build();
471
472 TrafficTreatment.Builder tb = processSpecificRoutingTreatment();
473
474 if (fwd.nextId() != null) {
475 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
476 GroupKey key = appKryo.deserialize(next.data());
477 Group group = groupService.getGroup(deviceId, key);
478 if (group == null) {
479 log.warn("The group left!");
480 fail(fwd, ObjectiveError.GROUPMISSING);
Michele Santuarid2c8b152016-03-30 17:57:56 -0700481 return ImmutableSet.of();
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700482 }
483 tb.group(group.id());
Michele Santuarid2c8b152016-03-30 17:57:56 -0700484 } else {
485 log.error("Missing NextObjective ID for ForwardingObjective {}", fwd.id());
486 fail(fwd, ObjectiveError.BADPARAMS);
487 return ImmutableSet.of();
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700488 }
489 Builder ruleBuilder = DefaultFlowRule.builder()
490 .fromApp(fwd.appId())
491 .withPriority(fwd.priority())
492 .forDevice(deviceId)
493 .withSelector(filteredSelector)
494 .withTreatment(tb.build());
495
496 ruleBuilder = processSpecificRoutingRule(ruleBuilder);
497
498 if (fwd.permanent()) {
499 ruleBuilder.makePermanent();
500 } else {
501 ruleBuilder.makeTemporary(fwd.timeout());
502 }
503 return Collections.singletonList(ruleBuilder.build());
504 }
505
506 //Hook for modifying Route traffic treatment
507 protected TrafficTreatment.Builder processSpecificRoutingTreatment() {
508 return DefaultTrafficTreatment.builder();
509 }
510
511 //Hook for modifying Route flow rule
512 protected abstract Builder processSpecificRoutingRule(Builder rb);
513
Pier Ventredb673552016-07-20 15:37:19 +0200514 protected enum CorsaTrafficTreatmentType {
515 /**
516 * If the treatment has to be handled as group.
517 */
518 GROUP,
519 /**
520 * If the treatment has to be handled as simple set of actions.
521 */
522 ACTIONS
523 }
524
525 /**
526 * Helper class to encapsulate both traffic treatment and
527 * type of treatment.
528 */
529 protected class CorsaTrafficTreatment {
530
531 private CorsaTrafficTreatmentType type;
532 private TrafficTreatment trafficTreatment;
533
534 public CorsaTrafficTreatment(CorsaTrafficTreatmentType treatmentType, TrafficTreatment trafficTreatment) {
535 this.type = treatmentType;
536 this.trafficTreatment = trafficTreatment;
537 }
538
539 public CorsaTrafficTreatmentType type() {
540 return type;
541 }
542
543 public TrafficTreatment treatment() {
544 return trafficTreatment;
545 }
546
547 }
548
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700549 @Override
550 public void next(NextObjective nextObjective) {
551 switch (nextObjective.type()) {
552 case SIMPLE:
553 Collection<TrafficTreatment> treatments = nextObjective.next();
554 if (treatments.size() == 1) {
555 TrafficTreatment treatment = treatments.iterator().next();
Pier Ventredb673552016-07-20 15:37:19 +0200556 CorsaTrafficTreatment corsaTreatment = processNextTreatment(treatment);
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700557 final GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
Pier Ventredb673552016-07-20 15:37:19 +0200558 if (corsaTreatment.type() == CorsaTrafficTreatmentType.GROUP) {
559 GroupBucket bucket = DefaultGroupBucket.createIndirectGroupBucket(corsaTreatment.treatment());
560 GroupBuckets buckets = new GroupBuckets(Collections.singletonList(bucket));
561 // group id == null, let group service determine group id
562 GroupDescription groupDescription = new DefaultGroupDescription(deviceId,
563 GroupDescription.Type.INDIRECT,
564 buckets,
565 key,
566 null,
567 nextObjective.appId());
568 groupService.addGroup(groupDescription);
569 pendingGroups.put(key, nextObjective);
570 } else if (corsaTreatment.type() == CorsaTrafficTreatmentType.ACTIONS) {
571 pendingNext.put(nextObjective.id(), nextObjective);
572 flowObjectiveStore.putNextGroup(nextObjective.id(), new CorsaGroup(key));
573 nextObjective.context().ifPresent(context -> context.onSuccess(nextObjective));
574 }
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700575 }
576 break;
577 case HASHED:
578 case BROADCAST:
579 case FAILOVER:
580 fail(nextObjective, ObjectiveError.UNSUPPORTED);
581 log.warn("Unsupported next objective type {}", nextObjective.type());
582 break;
583 default:
584 fail(nextObjective, ObjectiveError.UNKNOWN);
585 log.warn("Unknown next objective type {}", nextObjective.type());
586 }
587
588 }
589
590 //Hook for altering the NextObjective treatment
Pier Ventredb673552016-07-20 15:37:19 +0200591 protected CorsaTrafficTreatment processNextTreatment(TrafficTreatment treatment) {
592 return new CorsaTrafficTreatment(CorsaTrafficTreatmentType.GROUP, treatment);
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700593 }
594
595 //Init helper: Table Miss = Drop
596 protected void processTableMissDrop(boolean install, int table, String description) {
597 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
598
599 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
600 treatment.drop();
601
602 FlowRule rule = DefaultFlowRule.builder()
603 .forDevice(deviceId)
604 .withSelector(selector.build())
605 .withTreatment(treatment.build())
606 .withPriority(DROP_PRIORITY)
607 .fromApp(appId)
608 .makePermanent()
609 .forTable(table).build();
610
611 processFlowRule(install, rule, description);
612 }
613
614 //Init helper: Table Miss = GoTo
615 protected void processTableMissGoTo(boolean install, int table, int goTo, String description) {
616 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
617
618 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
619 treatment.transition(goTo);
620
621 FlowRule rule = DefaultFlowRule.builder()
622 .forDevice(deviceId)
623 .withSelector(selector.build())
624 .withTreatment(treatment.build())
625 .withPriority(DROP_PRIORITY)
626 .fromApp(appId)
627 .makePermanent()
628 .forTable(table).build();
629
630 processFlowRule(install, rule, description);
631 }
632
633 //Init helper: Apply flow rule
634 protected void processFlowRule(boolean install, FlowRule rule, String description) {
635 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
636 ops = install ? ops.add(rule) : ops.remove(rule);
637
638 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
639 @Override
640 public void onSuccess(FlowRuleOperations ops) {
641 log.info(description + " success: " + ops.toString() + ", " + rule.toString());
642 }
643
644 @Override
645 public void onError(FlowRuleOperations ops) {
646 log.info(description + " error: " + ops.toString() + ", " + rule.toString());
647 }
648 }));
649 }
Daniele Moro06aac702021-07-19 22:39:22 +0200650
651 @Override
652 public void purgeAll(ApplicationId appId) {
653 flowRuleService.purgeFlowRules(deviceId, appId);
654 groupService.purgeGroupEntries(deviceId, appId);
655 }
Michele Santuari9a8d16d2016-03-24 10:37:58 -0700656}