blob: 68db4ce16de0028aa919c40f2919c63ed981af60 [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
218 if (nextObjective.op() == Objective.Operation.REMOVE) {
sangho1e575652015-05-14 00:39:53 -0700219 if (nextObjective.next().isEmpty()) {
sangho834e4b02015-05-01 09:38:25 -0700220 removeGroup(nextObjective);
221 } else {
222 removeBucketFromGroup(nextObjective);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700223 }
sangho834e4b02015-05-01 09:38:25 -0700224 } else if (nextObjective.op() == Objective.Operation.ADD) {
225 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
226 if (nextGroup != null) {
227 addBucketToGroup(nextObjective);
228 } else {
229 addGroup(nextObjective);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700230 }
sangho834e4b02015-05-01 09:38:25 -0700231 } else {
232 log.warn("Unsupported operation {}", nextObjective.op());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700233 }
234
235 }
236
sangho834e4b02015-05-01 09:38:25 -0700237 private void removeGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700238 log.debug("removeGroup in {}: for next objective id {}",
239 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700240 final GroupKey key = new DefaultGroupKey(
241 appKryo.serialize(nextObjective.id()));
242 groupService.removeGroup(deviceId, key, appId);
243 }
244
245 private void addGroup(NextObjective nextObjective) {
246 switch (nextObjective.type()) {
247 case SIMPLE:
248 log.debug("processing SIMPLE next objective");
249 Collection<TrafficTreatment> treatments = nextObjective.next();
250 if (treatments.size() == 1) {
251 TrafficTreatment treatment = treatments.iterator().next();
252 GroupBucket bucket = DefaultGroupBucket
253 .createIndirectGroupBucket(treatment);
254 final GroupKey key = new DefaultGroupKey(
255 appKryo.serialize(nextObjective
256 .id()));
257 GroupDescription groupDescription = new DefaultGroupDescription(
258 deviceId,
259 GroupDescription.Type.INDIRECT,
260 new GroupBuckets(
261 Collections.singletonList(bucket)),
262 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700263 null,
sangho834e4b02015-05-01 09:38:25 -0700264 nextObjective.appId());
265 groupService.addGroup(groupDescription);
266 pendingGroups.put(key, nextObjective);
267 }
268 break;
269 case HASHED:
270 log.debug("processing HASHED next objective");
271 List<GroupBucket> buckets = nextObjective
272 .next()
273 .stream()
274 .map((treatment) -> DefaultGroupBucket
275 .createSelectGroupBucket(treatment))
276 .collect(Collectors.toList());
277 if (!buckets.isEmpty()) {
278 final GroupKey key = new DefaultGroupKey(
279 appKryo.serialize(nextObjective
280 .id()));
281 GroupDescription groupDescription = new DefaultGroupDescription(
282 deviceId,
283 GroupDescription.Type.SELECT,
284 new GroupBuckets(buckets),
285 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700286 null,
sangho834e4b02015-05-01 09:38:25 -0700287 nextObjective.appId());
288 groupService.addGroup(groupDescription);
289 pendingGroups.put(key, nextObjective);
290 }
291 break;
292 case BROADCAST:
293 case FAILOVER:
294 log.debug("BROADCAST and FAILOVER next objectives not supported");
295 fail(nextObjective, ObjectiveError.UNSUPPORTED);
296 log.warn("Unsupported next objective type {}", nextObjective.type());
297 break;
298 default:
299 fail(nextObjective, ObjectiveError.UNKNOWN);
300 log.warn("Unknown next objective type {}", nextObjective.type());
301 }
302 }
303
304 private void addBucketToGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700305 log.debug("addBucketToGroup in {}: for next objective id {}",
306 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700307 Collection<TrafficTreatment> treatments = nextObjective.next();
308 TrafficTreatment treatment = treatments.iterator().next();
309 final GroupKey key = new DefaultGroupKey(
310 appKryo.serialize(nextObjective
311 .id()));
312 Group group = groupService.getGroup(deviceId, key);
313 if (group == null) {
314 log.warn("Group is not found in {} for {}", deviceId, key);
315 return;
316 }
317 GroupBucket bucket;
318 if (group.type() == GroupDescription.Type.INDIRECT) {
319 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
320 } else if (group.type() == GroupDescription.Type.SELECT) {
321 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
322 } else {
323 log.warn("Unsupported Group type {}", group.type());
324 return;
325 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700326 GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket));
sangho834e4b02015-05-01 09:38:25 -0700327 groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId);
328 }
329
330 private void removeBucketFromGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700331 log.debug("removeBucketFromGroup in {}: for next objective id {}",
332 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700333 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
334 if (nextGroup != null) {
335 Collection<TrafficTreatment> treatments = nextObjective.next();
336 TrafficTreatment treatment = treatments.iterator().next();
337 final GroupKey key = new DefaultGroupKey(
338 appKryo.serialize(nextObjective
339 .id()));
340 Group group = groupService.getGroup(deviceId, key);
341 if (group == null) {
342 log.warn("Group is not found in {} for {}", deviceId, key);
343 return;
344 }
345 GroupBucket bucket;
346 if (group.type() == GroupDescription.Type.INDIRECT) {
347 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
348 } else if (group.type() == GroupDescription.Type.SELECT) {
349 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
350 } else {
351 log.warn("Unsupported Group type {}", group.type());
352 return;
353 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700354 GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
sangho834e4b02015-05-01 09:38:25 -0700355 groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId);
356 }
357 }
358
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700359 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
360 switch (fwd.flag()) {
361 case SPECIFIC:
362 return processSpecific(fwd);
363 case VERSATILE:
364 return processVersatile(fwd);
365 default:
366 fail(fwd, ObjectiveError.UNKNOWN);
367 log.warn("Unknown forwarding flag {}", fwd.flag());
368 }
369 return Collections.emptySet();
370 }
371
372 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
sangho1e575652015-05-14 00:39:53 -0700373 log.debug("Processing versatile forwarding objective");
374 TrafficSelector selector = fwd.selector();
375
376 EthTypeCriterion ethType =
377 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
378 if (ethType == null) {
379 log.error("Versatile forwarding objective must include ethType");
380 fail(fwd, ObjectiveError.UNKNOWN);
381 return Collections.emptySet();
382 }
383
384 TrafficSelector.Builder filteredSelectorBuilder =
385 DefaultTrafficSelector.builder();
386 if (ethType.ethType() == Ethernet.TYPE_IPV4) {
387 IPCriterion ipSrc = (IPCriterion) selector
388 .getCriterion(Criterion.Type.IPV4_SRC);
389 IPCriterion ipDst = (IPCriterion) selector
390 .getCriterion(Criterion.Type.IPV4_DST);
391 IPProtocolCriterion ipProto = (IPProtocolCriterion) selector
392 .getCriterion(Criterion.Type.IP_PROTO);
393
394 filteredSelectorBuilder
395 .matchEthType(Ethernet.TYPE_IPV4);
396
397 if (ipSrc != null) {
398 filteredSelectorBuilder.matchIPSrc(ipSrc.ip());
399 }
400 if (ipDst != null) {
401 filteredSelectorBuilder.matchIPDst(ipDst.ip());
402 }
403 if (ipProto != null) {
404 filteredSelectorBuilder.matchIPProtocol(
405 Short.valueOf(ipProto.protocol()).byteValue());
406 }
407
408 log.debug("processing IPv4 specific forwarding objective");
409 } else {
410 log.warn("VERSATILE forwarding objective does not support {} yet.",
411 ethType.ethType());
412 return Collections.emptySet();
413 }
414
415 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
416 .builder();
417 treatmentBuilder.wipeDeferred();
418
419 if (fwd.nextId() != null) {
420 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
421
422 if (next != null) {
423 GroupKey key = appKryo.deserialize(next.data());
424
425 Group group = groupService.getGroup(deviceId, key);
426
427 if (group == null) {
428 log.warn("The group left!");
429 fail(fwd, ObjectiveError.GROUPMISSING);
430 return Collections.emptySet();
431 }
432 treatmentBuilder.deferred().group(group.id());
433 log.debug("Adding OUTGROUP action");
434 }
435 } else {
436 log.warn("VERSATILE forwarding objective need next objective ID.");
437 return Collections.emptySet();
438 }
439
440 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
441 TrafficTreatment treatment = treatmentBuilder.build();
442
443 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
444 .fromApp(fwd.appId()).withPriority(fwd.priority())
445 .forDevice(deviceId).withSelector(filteredSelector)
446 .withTreatment(treatment);
447
448 if (fwd.permanent()) {
449 ruleBuilder.makePermanent();
450 } else {
451 ruleBuilder.makeTemporary(fwd.timeout());
452 }
453
454 ruleBuilder.forTable(aclTableId);
455 return Collections.singletonList(ruleBuilder.build());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700456 }
457
458 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
459 log.debug("Processing specific");
460 TrafficSelector selector = fwd.selector();
461 EthTypeCriterion ethType = (EthTypeCriterion) selector
462 .getCriterion(Criterion.Type.ETH_TYPE);
463 if ((ethType == null) ||
464 ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) &&
465 (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700466 log.warn("processSpecific: Unsupported "
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700467 + "forwarding objective criteraia");
468 fail(fwd, ObjectiveError.UNSUPPORTED);
469 return Collections.emptySet();
470 }
471
472 TrafficSelector.Builder filteredSelectorBuilder =
473 DefaultTrafficSelector.builder();
474 int forTableId = -1;
475 if (((short) ethType.ethType()) == Ethernet.TYPE_IPV4) {
476 filteredSelectorBuilder = filteredSelectorBuilder
477 .matchEthType(Ethernet.TYPE_IPV4)
478 .matchIPDst(((IPCriterion) selector
479 .getCriterion(Criterion.Type.IPV4_DST))
480 .ip());
481 forTableId = ipv4UnicastTableId;
482 log.debug("processing IPv4 specific forwarding objective");
483 } else {
484 filteredSelectorBuilder = filteredSelectorBuilder
485 .matchEthType(Ethernet.MPLS_UNICAST)
486 .matchMplsLabel(((MplsCriterion)
487 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
488 //TODO: Add Match for BoS
489 //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) {
490 //}
491 forTableId = mplsTableId;
492 log.debug("processing MPLS specific forwarding objective");
493 }
494
495 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
496 .builder();
497 if (fwd.treatment() != null) {
498 for (Instruction i : fwd.treatment().allInstructions()) {
499 treatmentBuilder.add(i);
500 }
501 }
502
503 //TODO: Analyze the forwarding objective here to make
504 //device specific decision such as no ECMP groups in Dell
505 //switches.
506 if (fwd.nextId() != null) {
507 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
508
509 if (next != null) {
510 GroupKey key = appKryo.deserialize(next.data());
511
512 Group group = groupService.getGroup(deviceId, key);
513
514 if (group == null) {
515 log.warn("The group left!");
516 fail(fwd, ObjectiveError.GROUPMISSING);
517 return Collections.emptySet();
518 }
sangho1e575652015-05-14 00:39:53 -0700519 treatmentBuilder.deferred().group(group.id());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700520 log.debug("Adding OUTGROUP action");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700521 } else {
522 log.warn("processSpecific: No associated next objective object");
523 fail(fwd, ObjectiveError.GROUPMISSING);
524 return Collections.emptySet();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700525 }
526 }
527
528 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
529 TrafficTreatment treatment = treatmentBuilder.transition(aclTableId)
530 .build();
531
532 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
533 .fromApp(fwd.appId()).withPriority(fwd.priority())
534 .forDevice(deviceId).withSelector(filteredSelector)
535 .withTreatment(treatment);
536
537 if (fwd.permanent()) {
538 ruleBuilder.makePermanent();
539 } else {
540 ruleBuilder.makeTemporary(fwd.timeout());
541 }
542
543 ruleBuilder.forTable(forTableId);
544 return Collections.singletonList(ruleBuilder.build());
545
546 }
547
548 protected List<FlowRule> processEthDstFilter(Criterion c,
549 FilteringObjective filt,
550 ApplicationId applicationId) {
551 List<FlowRule> rules = new ArrayList<FlowRule>();
552 EthCriterion e = (EthCriterion) c;
553 TrafficSelector.Builder selectorIp = DefaultTrafficSelector
554 .builder();
555 TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
556 .builder();
557 selectorIp.matchEthDst(e.mac());
558 selectorIp.matchEthType(Ethernet.TYPE_IPV4);
559 treatmentIp.transition(ipv4UnicastTableId);
560 FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
561 .withSelector(selectorIp.build())
562 .withTreatment(treatmentIp.build())
563 .withPriority(filt.priority()).fromApp(applicationId)
564 .makePermanent().forTable(tmacTableId).build();
565 log.debug("adding IP ETH rule for MAC: {}", e.mac());
566 rules.add(ruleIp);
567
568 TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
569 .builder();
570 TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
571 .builder();
572 selectorMpls.matchEthDst(e.mac());
573 selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
574 treatmentMpls.transition(mplsTableId);
575 FlowRule ruleMpls = DefaultFlowRule.builder()
576 .forDevice(deviceId).withSelector(selectorMpls.build())
577 .withTreatment(treatmentMpls.build())
578 .withPriority(filt.priority()).fromApp(applicationId)
579 .makePermanent().forTable(tmacTableId).build();
580 log.debug("adding MPLS ETH rule for MAC: {}", e.mac());
581 rules.add(ruleMpls);
582
583 return rules;
584 }
585
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700586 protected List<FlowRule> processVlanIdFilter(Criterion c,
587 FilteringObjective filt,
588 ApplicationId applicationId) {
589 List<FlowRule> rules = new ArrayList<FlowRule>();
590 VlanIdCriterion v = (VlanIdCriterion) c;
591 log.debug("adding rule for VLAN: {}", v.vlanId());
592 TrafficSelector.Builder selector = DefaultTrafficSelector
593 .builder();
594 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
595 .builder();
596 PortCriterion p = (PortCriterion) filt.key();
597 if (v.vlanId() != VlanId.NONE) {
598 selector.matchVlanId(v.vlanId());
599 selector.matchInPort(p.port());
600 treatment.deferred().popVlan();
601 }
602 treatment.transition(tmacTableId);
603 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
604 .withSelector(selector.build())
605 .withTreatment(treatment.build())
606 .withPriority(filt.priority()).fromApp(applicationId)
607 .makePermanent().forTable(vlanTableId).build();
608 rules.add(rule);
609
610 return rules;
611 }
612
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700613 private void processFilter(FilteringObjective filt, boolean install,
614 ApplicationId applicationId) {
615 // This driver only processes filtering criteria defined with switch
616 // ports as the key
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700617 if (filt.key().equals(Criteria.dummy())
618 || filt.key().type() != Criterion.Type.IN_PORT) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700619 log.warn("No key defined in filtering objective from app: {}. Not"
620 + "processing filtering objective", applicationId);
621 fail(filt, ObjectiveError.UNKNOWN);
622 return;
623 }
624 // convert filtering conditions for switch-intfs into flowrules
625 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
626 for (Criterion c : filt.conditions()) {
627 if (c.type() == Criterion.Type.ETH_DST) {
628 for (FlowRule rule : processEthDstFilter(c,
629 filt,
630 applicationId)) {
631 ops = install ? ops.add(rule) : ops.remove(rule);
632 }
633 } else if (c.type() == Criterion.Type.VLAN_VID) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700634 for (FlowRule rule : processVlanIdFilter(c,
635 filt,
636 applicationId)) {
637 ops = install ? ops.add(rule) : ops.remove(rule);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700638 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700639 } else if (c.type() == Criterion.Type.IPV4_DST) {
640 IPCriterion ip = (IPCriterion) c;
641 log.debug("adding rule for IP: {}", ip.ip());
642 TrafficSelector.Builder selector = DefaultTrafficSelector
643 .builder();
644 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
645 .builder();
646 selector.matchEthType(Ethernet.TYPE_IPV4);
647 selector.matchIPDst(ip.ip());
648 treatment.transition(aclTableId);
649 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
650 .withSelector(selector.build())
651 .withTreatment(treatment.build())
652 .withPriority(filt.priority()).fromApp(applicationId)
653 .makePermanent().forTable(ipv4UnicastTableId).build();
654 ops = install ? ops.add(rule) : ops.remove(rule);
655 } else {
656 log.warn("Driver does not currently process filtering condition"
657 + " of type: {}", c.type());
658 fail(filt, ObjectiveError.UNSUPPORTED);
659 }
660 }
661 // apply filtering flow rules
662 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
663 @Override
664 public void onSuccess(FlowRuleOperations ops) {
665 pass(filt);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700666 log.debug("Provisioned tables in {} with fitering "
667 + "rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700668 }
669
670 @Override
671 public void onError(FlowRuleOperations ops) {
672 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700673 log.warn("Failed to provision tables in {} with "
674 + "fitering rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700675 }
676 }));
677 }
678
679 protected void setTableMissEntries() {
680 // set all table-miss-entries
681 populateTableMissEntry(vlanTableId, true, false, false, -1);
682 populateTableMissEntry(tmacTableId, true, false, false, -1);
683 populateTableMissEntry(ipv4UnicastTableId, false, true, true,
684 aclTableId);
685 populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
686 populateTableMissEntry(aclTableId, false, false, false, -1);
687 }
688
689 protected void populateTableMissEntry(int tableToAdd,
690 boolean toControllerNow,
691 boolean toControllerWrite,
692 boolean toTable, int tableToSend) {
693 TrafficSelector selector = DefaultTrafficSelector.builder().build();
694 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
695
696 if (toControllerNow) {
697 tBuilder.setOutput(PortNumber.CONTROLLER);
698 }
699
700 if (toControllerWrite) {
701 tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
702 }
703
704 if (toTable) {
705 tBuilder.transition(tableToSend);
706 }
707
708 FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId)
709 .withSelector(selector).withTreatment(tBuilder.build())
710 .withPriority(0).fromApp(appId).makePermanent()
711 .forTable(tableToAdd).build();
712
713 flowRuleService.applyFlowRules(flow);
714 }
715
716 private void pass(Objective obj) {
717 if (obj.context().isPresent()) {
718 obj.context().get().onSuccess(obj);
719 }
720 }
721
722 protected void fail(Objective obj, ObjectiveError error) {
723 if (obj.context().isPresent()) {
724 obj.context().get().onError(obj, error);
725 }
726 }
727
728 private class InnerGroupListener implements GroupListener {
729 @Override
730 public void event(GroupEvent event) {
731 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700732 log.debug("InnerGroupListener: Group ADDED "
733 + "event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700734 GroupKey key = event.subject().appCookie();
735
736 NextObjective obj = pendingGroups.getIfPresent(key);
737 if (obj != null) {
738 flowObjectiveStore
739 .putNextGroup(obj.id(),
740 new SegmentRoutingGroup(key));
741 pass(obj);
742 pendingGroups.invalidate(key);
743 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700744 } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
745 log.warn("InnerGroupListener: Group ADD "
746 + "failed event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700747 }
748 }
749 }
750
751 private class GroupChecker implements Runnable {
752
753 @Override
754 public void run() {
755 Set<GroupKey> keys = pendingGroups
756 .asMap()
757 .keySet()
758 .stream()
759 .filter(key -> groupService.getGroup(deviceId, key) != null)
760 .collect(Collectors.toSet());
761
762 keys.stream()
763 .forEach(key -> {
764 NextObjective obj = pendingGroups
765 .getIfPresent(key);
766 if (obj == null) {
767 return;
768 }
769 pass(obj);
770 pendingGroups.invalidate(key);
771 flowObjectiveStore.putNextGroup(obj.id(),
772 new SegmentRoutingGroup(
773 key));
774 });
775 }
776 }
777
778 private class SegmentRoutingGroup implements NextGroup {
779
780 private final GroupKey key;
781
782 public SegmentRoutingGroup(GroupKey key) {
783 this.key = key;
784 }
785
786 public GroupKey key() {
787 return key;
788 }
789
790 @Override
791 public byte[] data() {
792 return appKryo.serialize(key);
793 }
794
795 }
796}