blob: a8eb37bc8c153cbca4971c1ba2e08c2c75afa93c [file] [log] [blame]
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001/*
2 * Copyright 2015 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.driver.pipeline;
17
18import static org.onlab.util.Tools.groupedThreads;
19import static org.slf4j.LoggerFactory.getLogger;
20
21import com.google.common.cache.Cache;
22import com.google.common.cache.CacheBuilder;
23import com.google.common.cache.RemovalCause;
24import com.google.common.cache.RemovalNotification;
25
26import org.onlab.osgi.ServiceDirectory;
27import org.onlab.packet.Ethernet;
28import org.onlab.packet.VlanId;
29import org.onlab.util.KryoNamespace;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.net.DeviceId;
33import org.onosproject.net.PortNumber;
34import org.onosproject.net.behaviour.NextGroup;
35import org.onosproject.net.behaviour.Pipeliner;
36import org.onosproject.net.behaviour.PipelinerContext;
37import org.onosproject.net.driver.AbstractHandlerBehaviour;
38import org.onosproject.net.flow.DefaultFlowRule;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.DefaultTrafficTreatment;
41import org.onosproject.net.flow.FlowRule;
42import org.onosproject.net.flow.FlowRuleOperations;
43import org.onosproject.net.flow.FlowRuleOperationsContext;
44import org.onosproject.net.flow.FlowRuleService;
45import org.onosproject.net.flow.TrafficSelector;
46import org.onosproject.net.flow.TrafficTreatment;
47import org.onosproject.net.flow.criteria.Criteria;
48import org.onosproject.net.flow.criteria.Criterion;
49import org.onosproject.net.flow.criteria.EthCriterion;
50import org.onosproject.net.flow.criteria.EthTypeCriterion;
51import org.onosproject.net.flow.criteria.IPCriterion;
sangho1e575652015-05-14 00:39:53 -070052import org.onosproject.net.flow.criteria.IPProtocolCriterion;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070053import org.onosproject.net.flow.criteria.MplsCriterion;
54import org.onosproject.net.flow.criteria.PortCriterion;
55import org.onosproject.net.flow.criteria.VlanIdCriterion;
56import org.onosproject.net.flow.instructions.Instruction;
57import org.onosproject.net.flowobjective.FilteringObjective;
58import org.onosproject.net.flowobjective.FlowObjectiveStore;
59import org.onosproject.net.flowobjective.ForwardingObjective;
60import org.onosproject.net.flowobjective.NextObjective;
61import org.onosproject.net.flowobjective.Objective;
62import org.onosproject.net.flowobjective.ObjectiveError;
63import org.onosproject.net.group.DefaultGroupBucket;
64import org.onosproject.net.group.DefaultGroupDescription;
65import org.onosproject.net.group.DefaultGroupKey;
66import org.onosproject.net.group.Group;
67import org.onosproject.net.group.GroupBucket;
68import org.onosproject.net.group.GroupBuckets;
69import org.onosproject.net.group.GroupDescription;
70import org.onosproject.net.group.GroupEvent;
71import org.onosproject.net.group.GroupKey;
72import org.onosproject.net.group.GroupListener;
73import org.onosproject.net.group.GroupService;
74import org.slf4j.Logger;
75
76import java.util.ArrayList;
77import java.util.Collection;
78import java.util.Collections;
79import java.util.List;
80import java.util.Set;
81import java.util.concurrent.Executors;
82import java.util.concurrent.ScheduledExecutorService;
83import java.util.concurrent.TimeUnit;
84import java.util.stream.Collectors;
85
86/**
87 * Driver for SPRING-OPEN pipeline.
88 */
89public class SpringOpenTTP extends AbstractHandlerBehaviour
90 implements Pipeliner {
91
92 // Default table ID - compatible with CpqD switch
93 private static final int TABLE_VLAN = 0;
94 private static final int TABLE_TMAC = 1;
95 private static final int TABLE_IPV4_UNICAST = 2;
96 private static final int TABLE_MPLS = 3;
97 private static final int TABLE_ACL = 5;
98
99 /**
100 * Set the default values. These variables will get overwritten based on the
101 * switch vendor type
102 */
103 protected int vlanTableId = TABLE_VLAN;
104 protected int tmacTableId = TABLE_TMAC;
105 protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST;
106 protected int mplsTableId = TABLE_MPLS;
107 protected int aclTableId = TABLE_ACL;
108
109 protected final Logger log = getLogger(getClass());
110
111 private ServiceDirectory serviceDirectory;
112 private FlowRuleService flowRuleService;
113 private CoreService coreService;
114 protected GroupService groupService;
115 protected FlowObjectiveStore flowObjectiveStore;
116 protected DeviceId deviceId;
117 private ApplicationId appId;
118
119 private Cache<GroupKey, NextObjective> pendingGroups;
120
121 private ScheduledExecutorService groupChecker = Executors
122 .newScheduledThreadPool(2,
123 groupedThreads("onos/pipeliner",
124 "spring-open-%d"));
125 protected KryoNamespace appKryo = new KryoNamespace.Builder()
126 .register(GroupKey.class).register(DefaultGroupKey.class)
127 .register(SegmentRoutingGroup.class).register(byte[].class).build();
128
129 @Override
130 public void init(DeviceId deviceId, PipelinerContext context) {
131 this.serviceDirectory = context.directory();
132 this.deviceId = deviceId;
133
134 pendingGroups = CacheBuilder
135 .newBuilder()
136 .expireAfterWrite(20, TimeUnit.SECONDS)
137 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
138 if (notification.getCause() == RemovalCause.EXPIRED) {
139 fail(notification.getValue(),
140 ObjectiveError.GROUPINSTALLATIONFAILED);
141 }
142 }).build();
143
144 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500,
145 TimeUnit.MILLISECONDS);
146
147 coreService = serviceDirectory.get(CoreService.class);
148 flowRuleService = serviceDirectory.get(FlowRuleService.class);
149 groupService = serviceDirectory.get(GroupService.class);
150 flowObjectiveStore = context.store();
151
152 groupService.addListener(new InnerGroupListener());
153
154 appId = coreService
155 .registerApplication("org.onosproject.driver.SpringOpenTTP");
156
157 setTableMissEntries();
158 log.info("Spring Open TTP driver initialized");
159 }
160
161 @Override
162 public void filter(FilteringObjective filteringObjective) {
163 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
164 log.debug("processing PERMIT filter objective");
165 processFilter(filteringObjective,
166 filteringObjective.op() == Objective.Operation.ADD,
167 filteringObjective.appId());
168 } else {
169 log.debug("filter objective other than PERMIT not supported");
170 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
171 }
172 }
173
174 @Override
175 public void forward(ForwardingObjective fwd) {
176 Collection<FlowRule> rules;
177 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
178
179 rules = processForward(fwd);
180 switch (fwd.op()) {
181 case ADD:
182 rules.stream().filter(rule -> rule != null)
183 .forEach(flowBuilder::add);
184 break;
185 case REMOVE:
186 rules.stream().filter(rule -> rule != null)
187 .forEach(flowBuilder::remove);
188 break;
189 default:
190 fail(fwd, ObjectiveError.UNKNOWN);
191 log.warn("Unknown forwarding type {}", fwd.op());
192 }
193
194 flowRuleService.apply(flowBuilder
195 .build(new FlowRuleOperationsContext() {
196 @Override
197 public void onSuccess(FlowRuleOperations ops) {
198 pass(fwd);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700199 log.debug("Provisioned tables in {} with "
200 + "forwarding rules for segment "
201 + "router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700202 }
203
204 @Override
205 public void onError(FlowRuleOperations ops) {
206 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700207 log.warn("Failed to provision tables in {} with "
208 + "forwarding rules for segment router",
209 deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700210 }
211 }));
212
213 }
214
215 @Override
216 public void next(NextObjective nextObjective) {
sangho834e4b02015-05-01 09:38:25 -0700217
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700218 log.debug("Processing NextObjective id{} op{}", nextObjective.id(),
219 nextObjective.op());
sangho834e4b02015-05-01 09:38:25 -0700220 if (nextObjective.op() == Objective.Operation.REMOVE) {
sangho1e575652015-05-14 00:39:53 -0700221 if (nextObjective.next().isEmpty()) {
sangho834e4b02015-05-01 09:38:25 -0700222 removeGroup(nextObjective);
223 } else {
224 removeBucketFromGroup(nextObjective);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700225 }
sangho834e4b02015-05-01 09:38:25 -0700226 } else if (nextObjective.op() == Objective.Operation.ADD) {
227 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
228 if (nextGroup != null) {
229 addBucketToGroup(nextObjective);
230 } else {
231 addGroup(nextObjective);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700232 }
sangho834e4b02015-05-01 09:38:25 -0700233 } else {
234 log.warn("Unsupported operation {}", nextObjective.op());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700235 }
236
237 }
238
sangho834e4b02015-05-01 09:38:25 -0700239 private void removeGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700240 log.debug("removeGroup in {}: for next objective id {}",
241 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700242 final GroupKey key = new DefaultGroupKey(
243 appKryo.serialize(nextObjective.id()));
244 groupService.removeGroup(deviceId, key, appId);
245 }
246
247 private void addGroup(NextObjective nextObjective) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700248 log.debug("addGroup with type{} for nextObjective id {}",
249 nextObjective.type(), nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700250 switch (nextObjective.type()) {
251 case SIMPLE:
252 log.debug("processing SIMPLE next objective");
253 Collection<TrafficTreatment> treatments = nextObjective.next();
254 if (treatments.size() == 1) {
255 TrafficTreatment treatment = treatments.iterator().next();
256 GroupBucket bucket = DefaultGroupBucket
257 .createIndirectGroupBucket(treatment);
258 final GroupKey key = new DefaultGroupKey(
259 appKryo.serialize(nextObjective
260 .id()));
261 GroupDescription groupDescription = new DefaultGroupDescription(
262 deviceId,
263 GroupDescription.Type.INDIRECT,
264 new GroupBuckets(
265 Collections.singletonList(bucket)),
266 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700267 null,
sangho834e4b02015-05-01 09:38:25 -0700268 nextObjective.appId());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700269 log.debug("Creating SIMPLE group for next objective id {}",
270 nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700271 groupService.addGroup(groupDescription);
272 pendingGroups.put(key, nextObjective);
273 }
274 break;
275 case HASHED:
276 log.debug("processing HASHED next objective");
277 List<GroupBucket> buckets = nextObjective
278 .next()
279 .stream()
280 .map((treatment) -> DefaultGroupBucket
281 .createSelectGroupBucket(treatment))
282 .collect(Collectors.toList());
283 if (!buckets.isEmpty()) {
284 final GroupKey key = new DefaultGroupKey(
285 appKryo.serialize(nextObjective
286 .id()));
287 GroupDescription groupDescription = new DefaultGroupDescription(
288 deviceId,
289 GroupDescription.Type.SELECT,
290 new GroupBuckets(buckets),
291 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700292 null,
sangho834e4b02015-05-01 09:38:25 -0700293 nextObjective.appId());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700294 log.debug("Creating HASHED group for next objective id {}",
295 nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700296 groupService.addGroup(groupDescription);
297 pendingGroups.put(key, nextObjective);
298 }
299 break;
300 case BROADCAST:
301 case FAILOVER:
302 log.debug("BROADCAST and FAILOVER next objectives not supported");
303 fail(nextObjective, ObjectiveError.UNSUPPORTED);
304 log.warn("Unsupported next objective type {}", nextObjective.type());
305 break;
306 default:
307 fail(nextObjective, ObjectiveError.UNKNOWN);
308 log.warn("Unknown next objective type {}", nextObjective.type());
309 }
310 }
311
312 private void addBucketToGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700313 log.debug("addBucketToGroup in {}: for next objective id {}",
314 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700315 Collection<TrafficTreatment> treatments = nextObjective.next();
316 TrafficTreatment treatment = treatments.iterator().next();
317 final GroupKey key = new DefaultGroupKey(
318 appKryo.serialize(nextObjective
319 .id()));
320 Group group = groupService.getGroup(deviceId, key);
321 if (group == null) {
322 log.warn("Group is not found in {} for {}", deviceId, key);
323 return;
324 }
325 GroupBucket bucket;
326 if (group.type() == GroupDescription.Type.INDIRECT) {
327 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
328 } else if (group.type() == GroupDescription.Type.SELECT) {
329 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
330 } else {
331 log.warn("Unsupported Group type {}", group.type());
332 return;
333 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700334 GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket));
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700335 log.debug("Adding buckets to group id {} of next objective id {} in device {}",
336 group.id(), nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700337 groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId);
338 }
339
340 private void removeBucketFromGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700341 log.debug("removeBucketFromGroup in {}: for next objective id {}",
342 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700343 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
344 if (nextGroup != null) {
345 Collection<TrafficTreatment> treatments = nextObjective.next();
346 TrafficTreatment treatment = treatments.iterator().next();
347 final GroupKey key = new DefaultGroupKey(
348 appKryo.serialize(nextObjective
349 .id()));
350 Group group = groupService.getGroup(deviceId, key);
351 if (group == null) {
352 log.warn("Group is not found in {} for {}", deviceId, key);
353 return;
354 }
355 GroupBucket bucket;
356 if (group.type() == GroupDescription.Type.INDIRECT) {
357 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
358 } else if (group.type() == GroupDescription.Type.SELECT) {
359 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
360 } else {
361 log.warn("Unsupported Group type {}", group.type());
362 return;
363 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700364 GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700365 log.debug("Removing buckets from group id {} of next objective id {} in device {}",
366 group.id(), nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700367 groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId);
368 }
369 }
370
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700371 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
372 switch (fwd.flag()) {
373 case SPECIFIC:
374 return processSpecific(fwd);
375 case VERSATILE:
376 return processVersatile(fwd);
377 default:
378 fail(fwd, ObjectiveError.UNKNOWN);
379 log.warn("Unknown forwarding flag {}", fwd.flag());
380 }
381 return Collections.emptySet();
382 }
383
384 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
sangho1e575652015-05-14 00:39:53 -0700385 log.debug("Processing versatile forwarding objective");
386 TrafficSelector selector = fwd.selector();
387
388 EthTypeCriterion ethType =
389 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
390 if (ethType == null) {
391 log.error("Versatile forwarding objective must include ethType");
392 fail(fwd, ObjectiveError.UNKNOWN);
393 return Collections.emptySet();
394 }
395
396 TrafficSelector.Builder filteredSelectorBuilder =
397 DefaultTrafficSelector.builder();
398 if (ethType.ethType() == Ethernet.TYPE_IPV4) {
399 IPCriterion ipSrc = (IPCriterion) selector
400 .getCriterion(Criterion.Type.IPV4_SRC);
401 IPCriterion ipDst = (IPCriterion) selector
402 .getCriterion(Criterion.Type.IPV4_DST);
403 IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
404 .getCriterion(Criterion.Type.IP_PROTO);
405
406 filteredSelectorBuilder
407 .matchEthType(Ethernet.TYPE_IPV4);
408
409 if (ipSrc != null) {
410 filteredSelectorBuilder.matchIPSrc(ipSrc.ip());
411 }
412 if (ipDst != null) {
413 filteredSelectorBuilder.matchIPDst(ipDst.ip());
414 }
415 if (ipProto != null) {
416 filteredSelectorBuilder.matchIPProtocol(
417 Short.valueOf(ipProto.protocol()).byteValue());
418 }
419
420 log.debug("processing IPv4 specific forwarding objective");
421 } else {
422 log.warn("VERSATILE forwarding objective does not support {} yet.",
423 ethType.ethType());
424 return Collections.emptySet();
425 }
426
427 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
428 .builder();
429 treatmentBuilder.wipeDeferred();
430
431 if (fwd.nextId() != null) {
432 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
433
434 if (next != null) {
435 GroupKey key = appKryo.deserialize(next.data());
436
437 Group group = groupService.getGroup(deviceId, key);
438
439 if (group == null) {
440 log.warn("The group left!");
441 fail(fwd, ObjectiveError.GROUPMISSING);
442 return Collections.emptySet();
443 }
444 treatmentBuilder.deferred().group(group.id());
445 log.debug("Adding OUTGROUP action");
446 }
447 } else {
448 log.warn("VERSATILE forwarding objective need next objective ID.");
449 return Collections.emptySet();
450 }
451
452 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
453 TrafficTreatment treatment = treatmentBuilder.build();
454
455 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
456 .fromApp(fwd.appId()).withPriority(fwd.priority())
457 .forDevice(deviceId).withSelector(filteredSelector)
458 .withTreatment(treatment);
459
460 if (fwd.permanent()) {
461 ruleBuilder.makePermanent();
462 } else {
463 ruleBuilder.makeTemporary(fwd.timeout());
464 }
465
466 ruleBuilder.forTable(aclTableId);
467 return Collections.singletonList(ruleBuilder.build());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700468 }
469
470 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
471 log.debug("Processing specific");
472 TrafficSelector selector = fwd.selector();
473 EthTypeCriterion ethType = (EthTypeCriterion) selector
474 .getCriterion(Criterion.Type.ETH_TYPE);
475 if ((ethType == null) ||
476 ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) &&
477 (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700478 log.warn("processSpecific: Unsupported "
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700479 + "forwarding objective criteraia");
480 fail(fwd, ObjectiveError.UNSUPPORTED);
481 return Collections.emptySet();
482 }
483
484 TrafficSelector.Builder filteredSelectorBuilder =
485 DefaultTrafficSelector.builder();
486 int forTableId = -1;
487 if (((short) ethType.ethType()) == Ethernet.TYPE_IPV4) {
488 filteredSelectorBuilder = filteredSelectorBuilder
489 .matchEthType(Ethernet.TYPE_IPV4)
490 .matchIPDst(((IPCriterion) selector
491 .getCriterion(Criterion.Type.IPV4_DST))
492 .ip());
493 forTableId = ipv4UnicastTableId;
494 log.debug("processing IPv4 specific forwarding objective");
495 } else {
496 filteredSelectorBuilder = filteredSelectorBuilder
497 .matchEthType(Ethernet.MPLS_UNICAST)
498 .matchMplsLabel(((MplsCriterion)
499 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
500 //TODO: Add Match for BoS
501 //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) {
502 //}
503 forTableId = mplsTableId;
504 log.debug("processing MPLS specific forwarding objective");
505 }
506
507 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
508 .builder();
509 if (fwd.treatment() != null) {
510 for (Instruction i : fwd.treatment().allInstructions()) {
511 treatmentBuilder.add(i);
512 }
513 }
514
515 //TODO: Analyze the forwarding objective here to make
516 //device specific decision such as no ECMP groups in Dell
517 //switches.
518 if (fwd.nextId() != null) {
519 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
520
521 if (next != null) {
522 GroupKey key = appKryo.deserialize(next.data());
523
524 Group group = groupService.getGroup(deviceId, key);
525
526 if (group == null) {
527 log.warn("The group left!");
528 fail(fwd, ObjectiveError.GROUPMISSING);
529 return Collections.emptySet();
530 }
sangho1e575652015-05-14 00:39:53 -0700531 treatmentBuilder.deferred().group(group.id());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700532 log.debug("Adding OUTGROUP action");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700533 } else {
534 log.warn("processSpecific: No associated next objective object");
535 fail(fwd, ObjectiveError.GROUPMISSING);
536 return Collections.emptySet();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700537 }
538 }
539
540 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
541 TrafficTreatment treatment = treatmentBuilder.transition(aclTableId)
542 .build();
543
544 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
545 .fromApp(fwd.appId()).withPriority(fwd.priority())
546 .forDevice(deviceId).withSelector(filteredSelector)
547 .withTreatment(treatment);
548
549 if (fwd.permanent()) {
550 ruleBuilder.makePermanent();
551 } else {
552 ruleBuilder.makeTemporary(fwd.timeout());
553 }
554
555 ruleBuilder.forTable(forTableId);
556 return Collections.singletonList(ruleBuilder.build());
557
558 }
559
560 protected List<FlowRule> processEthDstFilter(Criterion c,
561 FilteringObjective filt,
562 ApplicationId applicationId) {
563 List<FlowRule> rules = new ArrayList<FlowRule>();
564 EthCriterion e = (EthCriterion) c;
565 TrafficSelector.Builder selectorIp = DefaultTrafficSelector
566 .builder();
567 TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
568 .builder();
569 selectorIp.matchEthDst(e.mac());
570 selectorIp.matchEthType(Ethernet.TYPE_IPV4);
571 treatmentIp.transition(ipv4UnicastTableId);
572 FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
573 .withSelector(selectorIp.build())
574 .withTreatment(treatmentIp.build())
575 .withPriority(filt.priority()).fromApp(applicationId)
576 .makePermanent().forTable(tmacTableId).build();
577 log.debug("adding IP ETH rule for MAC: {}", e.mac());
578 rules.add(ruleIp);
579
580 TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
581 .builder();
582 TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
583 .builder();
584 selectorMpls.matchEthDst(e.mac());
585 selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
586 treatmentMpls.transition(mplsTableId);
587 FlowRule ruleMpls = DefaultFlowRule.builder()
588 .forDevice(deviceId).withSelector(selectorMpls.build())
589 .withTreatment(treatmentMpls.build())
590 .withPriority(filt.priority()).fromApp(applicationId)
591 .makePermanent().forTable(tmacTableId).build();
592 log.debug("adding MPLS ETH rule for MAC: {}", e.mac());
593 rules.add(ruleMpls);
594
595 return rules;
596 }
597
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700598 protected List<FlowRule> processVlanIdFilter(Criterion c,
599 FilteringObjective filt,
600 ApplicationId applicationId) {
601 List<FlowRule> rules = new ArrayList<FlowRule>();
602 VlanIdCriterion v = (VlanIdCriterion) c;
603 log.debug("adding rule for VLAN: {}", v.vlanId());
604 TrafficSelector.Builder selector = DefaultTrafficSelector
605 .builder();
606 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
607 .builder();
608 PortCriterion p = (PortCriterion) filt.key();
609 if (v.vlanId() != VlanId.NONE) {
610 selector.matchVlanId(v.vlanId());
611 selector.matchInPort(p.port());
612 treatment.deferred().popVlan();
613 }
614 treatment.transition(tmacTableId);
615 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
616 .withSelector(selector.build())
617 .withTreatment(treatment.build())
618 .withPriority(filt.priority()).fromApp(applicationId)
619 .makePermanent().forTable(vlanTableId).build();
620 rules.add(rule);
621
622 return rules;
623 }
624
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700625 private void processFilter(FilteringObjective filt, boolean install,
626 ApplicationId applicationId) {
627 // This driver only processes filtering criteria defined with switch
628 // ports as the key
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700629 if (filt.key().equals(Criteria.dummy())
630 || filt.key().type() != Criterion.Type.IN_PORT) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700631 log.warn("No key defined in filtering objective from app: {}. Not"
632 + "processing filtering objective", applicationId);
633 fail(filt, ObjectiveError.UNKNOWN);
634 return;
635 }
636 // convert filtering conditions for switch-intfs into flowrules
637 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
638 for (Criterion c : filt.conditions()) {
639 if (c.type() == Criterion.Type.ETH_DST) {
640 for (FlowRule rule : processEthDstFilter(c,
641 filt,
642 applicationId)) {
643 ops = install ? ops.add(rule) : ops.remove(rule);
644 }
645 } else if (c.type() == Criterion.Type.VLAN_VID) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700646 for (FlowRule rule : processVlanIdFilter(c,
647 filt,
648 applicationId)) {
649 ops = install ? ops.add(rule) : ops.remove(rule);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700650 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700651 } else if (c.type() == Criterion.Type.IPV4_DST) {
652 IPCriterion ip = (IPCriterion) c;
653 log.debug("adding rule for IP: {}", ip.ip());
654 TrafficSelector.Builder selector = DefaultTrafficSelector
655 .builder();
656 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
657 .builder();
658 selector.matchEthType(Ethernet.TYPE_IPV4);
659 selector.matchIPDst(ip.ip());
660 treatment.transition(aclTableId);
661 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
662 .withSelector(selector.build())
663 .withTreatment(treatment.build())
664 .withPriority(filt.priority()).fromApp(applicationId)
665 .makePermanent().forTable(ipv4UnicastTableId).build();
666 ops = install ? ops.add(rule) : ops.remove(rule);
667 } else {
668 log.warn("Driver does not currently process filtering condition"
669 + " of type: {}", c.type());
670 fail(filt, ObjectiveError.UNSUPPORTED);
671 }
672 }
673 // apply filtering flow rules
674 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
675 @Override
676 public void onSuccess(FlowRuleOperations ops) {
677 pass(filt);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700678 log.debug("Provisioned tables in {} with fitering "
679 + "rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700680 }
681
682 @Override
683 public void onError(FlowRuleOperations ops) {
684 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700685 log.warn("Failed to provision tables in {} with "
686 + "fitering rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700687 }
688 }));
689 }
690
691 protected void setTableMissEntries() {
692 // set all table-miss-entries
693 populateTableMissEntry(vlanTableId, true, false, false, -1);
694 populateTableMissEntry(tmacTableId, true, false, false, -1);
695 populateTableMissEntry(ipv4UnicastTableId, false, true, true,
696 aclTableId);
697 populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
698 populateTableMissEntry(aclTableId, false, false, false, -1);
699 }
700
701 protected void populateTableMissEntry(int tableToAdd,
702 boolean toControllerNow,
703 boolean toControllerWrite,
704 boolean toTable, int tableToSend) {
705 TrafficSelector selector = DefaultTrafficSelector.builder().build();
706 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
707
708 if (toControllerNow) {
709 tBuilder.setOutput(PortNumber.CONTROLLER);
710 }
711
712 if (toControllerWrite) {
713 tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
714 }
715
716 if (toTable) {
717 tBuilder.transition(tableToSend);
718 }
719
720 FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId)
721 .withSelector(selector).withTreatment(tBuilder.build())
722 .withPriority(0).fromApp(appId).makePermanent()
723 .forTable(tableToAdd).build();
724
725 flowRuleService.applyFlowRules(flow);
726 }
727
728 private void pass(Objective obj) {
729 if (obj.context().isPresent()) {
730 obj.context().get().onSuccess(obj);
731 }
732 }
733
734 protected void fail(Objective obj, ObjectiveError error) {
735 if (obj.context().isPresent()) {
736 obj.context().get().onError(obj, error);
737 }
738 }
739
740 private class InnerGroupListener implements GroupListener {
741 @Override
742 public void event(GroupEvent event) {
743 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700744 log.debug("InnerGroupListener: Group ADDED "
745 + "event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700746 GroupKey key = event.subject().appCookie();
747
748 NextObjective obj = pendingGroups.getIfPresent(key);
749 if (obj != null) {
750 flowObjectiveStore
751 .putNextGroup(obj.id(),
752 new SegmentRoutingGroup(key));
753 pass(obj);
754 pendingGroups.invalidate(key);
755 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700756 } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
757 log.warn("InnerGroupListener: Group ADD "
758 + "failed event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700759 }
760 }
761 }
762
763 private class GroupChecker implements Runnable {
764
765 @Override
766 public void run() {
767 Set<GroupKey> keys = pendingGroups
768 .asMap()
769 .keySet()
770 .stream()
771 .filter(key -> groupService.getGroup(deviceId, key) != null)
772 .collect(Collectors.toSet());
773
774 keys.stream()
775 .forEach(key -> {
776 NextObjective obj = pendingGroups
777 .getIfPresent(key);
778 if (obj == null) {
779 return;
780 }
781 pass(obj);
782 pendingGroups.invalidate(key);
783 flowObjectiveStore.putNextGroup(obj.id(),
784 new SegmentRoutingGroup(
785 key));
786 });
787 }
788 }
789
790 private class SegmentRoutingGroup implements NextGroup {
791
792 private final GroupKey key;
793
794 public SegmentRoutingGroup(GroupKey key) {
795 this.key = key;
796 }
797
798 public GroupKey key() {
799 return key;
800 }
801
802 @Override
803 public byte[] data() {
804 return appKryo.serialize(key);
805 }
806
807 }
808}