blob: c02ba3caeeb36c3579ae3123f7031b277542901c [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;
52import org.onosproject.net.flow.criteria.MplsCriterion;
53import org.onosproject.net.flow.criteria.PortCriterion;
54import org.onosproject.net.flow.criteria.VlanIdCriterion;
55import org.onosproject.net.flow.instructions.Instruction;
56import org.onosproject.net.flowobjective.FilteringObjective;
57import org.onosproject.net.flowobjective.FlowObjectiveStore;
58import org.onosproject.net.flowobjective.ForwardingObjective;
59import org.onosproject.net.flowobjective.NextObjective;
60import org.onosproject.net.flowobjective.Objective;
61import org.onosproject.net.flowobjective.ObjectiveError;
62import org.onosproject.net.group.DefaultGroupBucket;
63import org.onosproject.net.group.DefaultGroupDescription;
64import org.onosproject.net.group.DefaultGroupKey;
65import org.onosproject.net.group.Group;
66import org.onosproject.net.group.GroupBucket;
67import org.onosproject.net.group.GroupBuckets;
68import org.onosproject.net.group.GroupDescription;
69import org.onosproject.net.group.GroupEvent;
70import org.onosproject.net.group.GroupKey;
71import org.onosproject.net.group.GroupListener;
72import org.onosproject.net.group.GroupService;
73import org.slf4j.Logger;
74
75import java.util.ArrayList;
76import java.util.Collection;
77import java.util.Collections;
78import java.util.List;
79import java.util.Set;
80import java.util.concurrent.Executors;
81import java.util.concurrent.ScheduledExecutorService;
82import java.util.concurrent.TimeUnit;
83import java.util.stream.Collectors;
84
85/**
86 * Driver for SPRING-OPEN pipeline.
87 */
88public class SpringOpenTTP extends AbstractHandlerBehaviour
89 implements Pipeliner {
90
91 // Default table ID - compatible with CpqD switch
92 private static final int TABLE_VLAN = 0;
93 private static final int TABLE_TMAC = 1;
94 private static final int TABLE_IPV4_UNICAST = 2;
95 private static final int TABLE_MPLS = 3;
96 private static final int TABLE_ACL = 5;
97
98 /**
99 * Set the default values. These variables will get overwritten based on the
100 * switch vendor type
101 */
102 protected int vlanTableId = TABLE_VLAN;
103 protected int tmacTableId = TABLE_TMAC;
104 protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST;
105 protected int mplsTableId = TABLE_MPLS;
106 protected int aclTableId = TABLE_ACL;
107
108 protected final Logger log = getLogger(getClass());
109
110 private ServiceDirectory serviceDirectory;
111 private FlowRuleService flowRuleService;
112 private CoreService coreService;
113 protected GroupService groupService;
114 protected FlowObjectiveStore flowObjectiveStore;
115 protected DeviceId deviceId;
116 private ApplicationId appId;
117
118 private Cache<GroupKey, NextObjective> pendingGroups;
119
120 private ScheduledExecutorService groupChecker = Executors
121 .newScheduledThreadPool(2,
122 groupedThreads("onos/pipeliner",
123 "spring-open-%d"));
124 protected KryoNamespace appKryo = new KryoNamespace.Builder()
125 .register(GroupKey.class).register(DefaultGroupKey.class)
126 .register(SegmentRoutingGroup.class).register(byte[].class).build();
127
128 @Override
129 public void init(DeviceId deviceId, PipelinerContext context) {
130 this.serviceDirectory = context.directory();
131 this.deviceId = deviceId;
132
133 pendingGroups = CacheBuilder
134 .newBuilder()
135 .expireAfterWrite(20, TimeUnit.SECONDS)
136 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
137 if (notification.getCause() == RemovalCause.EXPIRED) {
138 fail(notification.getValue(),
139 ObjectiveError.GROUPINSTALLATIONFAILED);
140 }
141 }).build();
142
143 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500,
144 TimeUnit.MILLISECONDS);
145
146 coreService = serviceDirectory.get(CoreService.class);
147 flowRuleService = serviceDirectory.get(FlowRuleService.class);
148 groupService = serviceDirectory.get(GroupService.class);
149 flowObjectiveStore = context.store();
150
151 groupService.addListener(new InnerGroupListener());
152
153 appId = coreService
154 .registerApplication("org.onosproject.driver.SpringOpenTTP");
155
156 setTableMissEntries();
157 log.info("Spring Open TTP driver initialized");
158 }
159
160 @Override
161 public void filter(FilteringObjective filteringObjective) {
162 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
163 log.debug("processing PERMIT filter objective");
164 processFilter(filteringObjective,
165 filteringObjective.op() == Objective.Operation.ADD,
166 filteringObjective.appId());
167 } else {
168 log.debug("filter objective other than PERMIT not supported");
169 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
170 }
171 }
172
173 @Override
174 public void forward(ForwardingObjective fwd) {
175 Collection<FlowRule> rules;
176 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
177
178 rules = processForward(fwd);
179 switch (fwd.op()) {
180 case ADD:
181 rules.stream().filter(rule -> rule != null)
182 .forEach(flowBuilder::add);
183 break;
184 case REMOVE:
185 rules.stream().filter(rule -> rule != null)
186 .forEach(flowBuilder::remove);
187 break;
188 default:
189 fail(fwd, ObjectiveError.UNKNOWN);
190 log.warn("Unknown forwarding type {}", fwd.op());
191 }
192
193 flowRuleService.apply(flowBuilder
194 .build(new FlowRuleOperationsContext() {
195 @Override
196 public void onSuccess(FlowRuleOperations ops) {
197 pass(fwd);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700198 log.debug("Provisioned tables in {} with "
199 + "forwarding rules for segment "
200 + "router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700201 }
202
203 @Override
204 public void onError(FlowRuleOperations ops) {
205 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700206 log.warn("Failed to provision tables in {} with "
207 + "forwarding rules for segment router",
208 deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700209 }
210 }));
211
212 }
213
214 @Override
215 public void next(NextObjective nextObjective) {
sangho834e4b02015-05-01 09:38:25 -0700216
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700217 log.debug("Processing NextObjective id{} op{}", nextObjective.id(),
218 nextObjective.op());
sangho834e4b02015-05-01 09:38:25 -0700219 if (nextObjective.op() == Objective.Operation.REMOVE) {
sangho1e575652015-05-14 00:39:53 -0700220 if (nextObjective.next().isEmpty()) {
sangho834e4b02015-05-01 09:38:25 -0700221 removeGroup(nextObjective);
222 } else {
223 removeBucketFromGroup(nextObjective);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700224 }
sangho834e4b02015-05-01 09:38:25 -0700225 } else if (nextObjective.op() == Objective.Operation.ADD) {
226 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
227 if (nextGroup != null) {
228 addBucketToGroup(nextObjective);
229 } else {
230 addGroup(nextObjective);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700231 }
sangho834e4b02015-05-01 09:38:25 -0700232 } else {
233 log.warn("Unsupported operation {}", nextObjective.op());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700234 }
235
236 }
237
sangho834e4b02015-05-01 09:38:25 -0700238 private void removeGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700239 log.debug("removeGroup in {}: for next objective id {}",
240 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700241 final GroupKey key = new DefaultGroupKey(
242 appKryo.serialize(nextObjective.id()));
243 groupService.removeGroup(deviceId, key, appId);
244 }
245
246 private void addGroup(NextObjective nextObjective) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700247 log.debug("addGroup with type{} for nextObjective id {}",
248 nextObjective.type(), nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700249 switch (nextObjective.type()) {
250 case SIMPLE:
251 log.debug("processing SIMPLE next objective");
252 Collection<TrafficTreatment> treatments = nextObjective.next();
253 if (treatments.size() == 1) {
254 TrafficTreatment treatment = treatments.iterator().next();
255 GroupBucket bucket = DefaultGroupBucket
256 .createIndirectGroupBucket(treatment);
257 final GroupKey key = new DefaultGroupKey(
258 appKryo.serialize(nextObjective
259 .id()));
260 GroupDescription groupDescription = new DefaultGroupDescription(
261 deviceId,
262 GroupDescription.Type.INDIRECT,
263 new GroupBuckets(
264 Collections.singletonList(bucket)),
265 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700266 null,
sangho834e4b02015-05-01 09:38:25 -0700267 nextObjective.appId());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700268 log.debug("Creating SIMPLE group for next objective id {}",
269 nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700270 groupService.addGroup(groupDescription);
271 pendingGroups.put(key, nextObjective);
272 }
273 break;
274 case HASHED:
275 log.debug("processing HASHED next objective");
276 List<GroupBucket> buckets = nextObjective
277 .next()
278 .stream()
279 .map((treatment) -> DefaultGroupBucket
280 .createSelectGroupBucket(treatment))
281 .collect(Collectors.toList());
282 if (!buckets.isEmpty()) {
283 final GroupKey key = new DefaultGroupKey(
284 appKryo.serialize(nextObjective
285 .id()));
286 GroupDescription groupDescription = new DefaultGroupDescription(
287 deviceId,
288 GroupDescription.Type.SELECT,
289 new GroupBuckets(buckets),
290 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700291 null,
sangho834e4b02015-05-01 09:38:25 -0700292 nextObjective.appId());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700293 log.debug("Creating HASHED group for next objective id {}",
294 nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700295 groupService.addGroup(groupDescription);
296 pendingGroups.put(key, nextObjective);
297 }
298 break;
299 case BROADCAST:
300 case FAILOVER:
301 log.debug("BROADCAST and FAILOVER next objectives not supported");
302 fail(nextObjective, ObjectiveError.UNSUPPORTED);
303 log.warn("Unsupported next objective type {}", nextObjective.type());
304 break;
305 default:
306 fail(nextObjective, ObjectiveError.UNKNOWN);
307 log.warn("Unknown next objective type {}", nextObjective.type());
308 }
309 }
310
311 private void addBucketToGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700312 log.debug("addBucketToGroup in {}: for next objective id {}",
313 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700314 Collection<TrafficTreatment> treatments = nextObjective.next();
315 TrafficTreatment treatment = treatments.iterator().next();
316 final GroupKey key = new DefaultGroupKey(
317 appKryo.serialize(nextObjective
318 .id()));
319 Group group = groupService.getGroup(deviceId, key);
320 if (group == null) {
321 log.warn("Group is not found in {} for {}", deviceId, key);
322 return;
323 }
324 GroupBucket bucket;
325 if (group.type() == GroupDescription.Type.INDIRECT) {
326 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
327 } else if (group.type() == GroupDescription.Type.SELECT) {
328 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
329 } else {
330 log.warn("Unsupported Group type {}", group.type());
331 return;
332 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700333 GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket));
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700334 log.debug("Adding buckets to group id {} of next objective id {} in device {}",
335 group.id(), nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700336 groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId);
337 }
338
339 private void removeBucketFromGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700340 log.debug("removeBucketFromGroup in {}: for next objective id {}",
341 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700342 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
343 if (nextGroup != null) {
344 Collection<TrafficTreatment> treatments = nextObjective.next();
345 TrafficTreatment treatment = treatments.iterator().next();
346 final GroupKey key = new DefaultGroupKey(
347 appKryo.serialize(nextObjective
348 .id()));
349 Group group = groupService.getGroup(deviceId, key);
350 if (group == null) {
351 log.warn("Group is not found in {} for {}", deviceId, key);
352 return;
353 }
354 GroupBucket bucket;
355 if (group.type() == GroupDescription.Type.INDIRECT) {
356 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
357 } else if (group.type() == GroupDescription.Type.SELECT) {
358 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
359 } else {
360 log.warn("Unsupported Group type {}", group.type());
361 return;
362 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700363 GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700364 log.debug("Removing buckets from group id {} of next objective id {} in device {}",
365 group.id(), nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700366 groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId);
367 }
368 }
369
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700370 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
371 switch (fwd.flag()) {
372 case SPECIFIC:
373 return processSpecific(fwd);
374 case VERSATILE:
375 return processVersatile(fwd);
376 default:
377 fail(fwd, ObjectiveError.UNKNOWN);
378 log.warn("Unknown forwarding flag {}", fwd.flag());
379 }
380 return Collections.emptySet();
381 }
382
383 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
sangho1e575652015-05-14 00:39:53 -0700384 log.debug("Processing versatile forwarding objective");
385 TrafficSelector selector = fwd.selector();
386
387 EthTypeCriterion ethType =
388 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
389 if (ethType == null) {
390 log.error("Versatile forwarding objective must include ethType");
391 fail(fwd, ObjectiveError.UNKNOWN);
392 return Collections.emptySet();
393 }
394
sangho1e575652015-05-14 00:39:53 -0700395 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
396 .builder();
397 treatmentBuilder.wipeDeferred();
398
399 if (fwd.nextId() != null) {
400 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
401
402 if (next != null) {
403 GroupKey key = appKryo.deserialize(next.data());
404
405 Group group = groupService.getGroup(deviceId, key);
406
407 if (group == null) {
408 log.warn("The group left!");
409 fail(fwd, ObjectiveError.GROUPMISSING);
410 return Collections.emptySet();
411 }
412 treatmentBuilder.deferred().group(group.id());
413 log.debug("Adding OUTGROUP action");
414 }
415 } else {
416 log.warn("VERSATILE forwarding objective need next objective ID.");
417 return Collections.emptySet();
418 }
419
sangho1e575652015-05-14 00:39:53 -0700420 TrafficTreatment treatment = treatmentBuilder.build();
421
422 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
423 .fromApp(fwd.appId()).withPriority(fwd.priority())
sanghof9d0bf12015-05-19 11:57:42 -0700424 .forDevice(deviceId).withSelector(fwd.selector())
sangho1e575652015-05-14 00:39:53 -0700425 .withTreatment(treatment);
426
427 if (fwd.permanent()) {
428 ruleBuilder.makePermanent();
429 } else {
430 ruleBuilder.makeTemporary(fwd.timeout());
431 }
432
433 ruleBuilder.forTable(aclTableId);
434 return Collections.singletonList(ruleBuilder.build());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700435 }
436
437 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
438 log.debug("Processing specific");
439 TrafficSelector selector = fwd.selector();
440 EthTypeCriterion ethType = (EthTypeCriterion) selector
441 .getCriterion(Criterion.Type.ETH_TYPE);
442 if ((ethType == null) ||
alshabibcaf1ca22015-06-25 15:18:16 -0700443 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
444 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700445 log.warn("processSpecific: Unsupported "
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700446 + "forwarding objective criteraia");
447 fail(fwd, ObjectiveError.UNSUPPORTED);
448 return Collections.emptySet();
449 }
450
451 TrafficSelector.Builder filteredSelectorBuilder =
452 DefaultTrafficSelector.builder();
453 int forTableId = -1;
alshabibcaf1ca22015-06-25 15:18:16 -0700454 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700455 filteredSelectorBuilder = filteredSelectorBuilder
456 .matchEthType(Ethernet.TYPE_IPV4)
457 .matchIPDst(((IPCriterion) selector
458 .getCriterion(Criterion.Type.IPV4_DST))
459 .ip());
460 forTableId = ipv4UnicastTableId;
461 log.debug("processing IPv4 specific forwarding objective");
462 } else {
463 filteredSelectorBuilder = filteredSelectorBuilder
464 .matchEthType(Ethernet.MPLS_UNICAST)
465 .matchMplsLabel(((MplsCriterion)
466 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
467 //TODO: Add Match for BoS
468 //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) {
469 //}
470 forTableId = mplsTableId;
471 log.debug("processing MPLS specific forwarding objective");
472 }
473
474 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
475 .builder();
476 if (fwd.treatment() != null) {
477 for (Instruction i : fwd.treatment().allInstructions()) {
478 treatmentBuilder.add(i);
479 }
480 }
481
482 //TODO: Analyze the forwarding objective here to make
483 //device specific decision such as no ECMP groups in Dell
484 //switches.
485 if (fwd.nextId() != null) {
486 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
487
488 if (next != null) {
489 GroupKey key = appKryo.deserialize(next.data());
490
491 Group group = groupService.getGroup(deviceId, key);
492
493 if (group == null) {
494 log.warn("The group left!");
495 fail(fwd, ObjectiveError.GROUPMISSING);
496 return Collections.emptySet();
497 }
sangho1e575652015-05-14 00:39:53 -0700498 treatmentBuilder.deferred().group(group.id());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700499 log.debug("Adding OUTGROUP action");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700500 } else {
501 log.warn("processSpecific: No associated next objective object");
502 fail(fwd, ObjectiveError.GROUPMISSING);
503 return Collections.emptySet();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700504 }
505 }
506
507 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
508 TrafficTreatment treatment = treatmentBuilder.transition(aclTableId)
509 .build();
510
511 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
512 .fromApp(fwd.appId()).withPriority(fwd.priority())
513 .forDevice(deviceId).withSelector(filteredSelector)
514 .withTreatment(treatment);
515
516 if (fwd.permanent()) {
517 ruleBuilder.makePermanent();
518 } else {
519 ruleBuilder.makeTemporary(fwd.timeout());
520 }
521
522 ruleBuilder.forTable(forTableId);
523 return Collections.singletonList(ruleBuilder.build());
524
525 }
526
527 protected List<FlowRule> processEthDstFilter(Criterion c,
528 FilteringObjective filt,
529 ApplicationId applicationId) {
530 List<FlowRule> rules = new ArrayList<FlowRule>();
531 EthCriterion e = (EthCriterion) c;
532 TrafficSelector.Builder selectorIp = DefaultTrafficSelector
533 .builder();
534 TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
535 .builder();
536 selectorIp.matchEthDst(e.mac());
537 selectorIp.matchEthType(Ethernet.TYPE_IPV4);
538 treatmentIp.transition(ipv4UnicastTableId);
539 FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
540 .withSelector(selectorIp.build())
541 .withTreatment(treatmentIp.build())
542 .withPriority(filt.priority()).fromApp(applicationId)
543 .makePermanent().forTable(tmacTableId).build();
544 log.debug("adding IP ETH rule for MAC: {}", e.mac());
545 rules.add(ruleIp);
546
547 TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
548 .builder();
549 TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
550 .builder();
551 selectorMpls.matchEthDst(e.mac());
552 selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
553 treatmentMpls.transition(mplsTableId);
554 FlowRule ruleMpls = DefaultFlowRule.builder()
555 .forDevice(deviceId).withSelector(selectorMpls.build())
556 .withTreatment(treatmentMpls.build())
557 .withPriority(filt.priority()).fromApp(applicationId)
558 .makePermanent().forTable(tmacTableId).build();
559 log.debug("adding MPLS ETH rule for MAC: {}", e.mac());
560 rules.add(ruleMpls);
561
562 return rules;
563 }
564
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700565 protected List<FlowRule> processVlanIdFilter(Criterion c,
566 FilteringObjective filt,
567 ApplicationId applicationId) {
568 List<FlowRule> rules = new ArrayList<FlowRule>();
569 VlanIdCriterion v = (VlanIdCriterion) c;
570 log.debug("adding rule for VLAN: {}", v.vlanId());
571 TrafficSelector.Builder selector = DefaultTrafficSelector
572 .builder();
573 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
574 .builder();
575 PortCriterion p = (PortCriterion) filt.key();
576 if (v.vlanId() != VlanId.NONE) {
577 selector.matchVlanId(v.vlanId());
578 selector.matchInPort(p.port());
579 treatment.deferred().popVlan();
580 }
581 treatment.transition(tmacTableId);
582 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
583 .withSelector(selector.build())
584 .withTreatment(treatment.build())
585 .withPriority(filt.priority()).fromApp(applicationId)
586 .makePermanent().forTable(vlanTableId).build();
587 rules.add(rule);
588
589 return rules;
590 }
591
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700592 private void processFilter(FilteringObjective filt, boolean install,
593 ApplicationId applicationId) {
594 // This driver only processes filtering criteria defined with switch
595 // ports as the key
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700596 if (filt.key().equals(Criteria.dummy())
597 || filt.key().type() != Criterion.Type.IN_PORT) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700598 log.warn("No key defined in filtering objective from app: {}. Not"
599 + "processing filtering objective", applicationId);
600 fail(filt, ObjectiveError.UNKNOWN);
601 return;
602 }
603 // convert filtering conditions for switch-intfs into flowrules
604 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
605 for (Criterion c : filt.conditions()) {
606 if (c.type() == Criterion.Type.ETH_DST) {
607 for (FlowRule rule : processEthDstFilter(c,
608 filt,
609 applicationId)) {
610 ops = install ? ops.add(rule) : ops.remove(rule);
611 }
612 } else if (c.type() == Criterion.Type.VLAN_VID) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700613 for (FlowRule rule : processVlanIdFilter(c,
614 filt,
615 applicationId)) {
616 ops = install ? ops.add(rule) : ops.remove(rule);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700617 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700618 } else if (c.type() == Criterion.Type.IPV4_DST) {
619 IPCriterion ip = (IPCriterion) c;
620 log.debug("adding rule for IP: {}", ip.ip());
621 TrafficSelector.Builder selector = DefaultTrafficSelector
622 .builder();
623 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
624 .builder();
625 selector.matchEthType(Ethernet.TYPE_IPV4);
626 selector.matchIPDst(ip.ip());
627 treatment.transition(aclTableId);
628 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
629 .withSelector(selector.build())
630 .withTreatment(treatment.build())
631 .withPriority(filt.priority()).fromApp(applicationId)
632 .makePermanent().forTable(ipv4UnicastTableId).build();
633 ops = install ? ops.add(rule) : ops.remove(rule);
634 } else {
635 log.warn("Driver does not currently process filtering condition"
636 + " of type: {}", c.type());
637 fail(filt, ObjectiveError.UNSUPPORTED);
638 }
639 }
640 // apply filtering flow rules
641 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
642 @Override
643 public void onSuccess(FlowRuleOperations ops) {
644 pass(filt);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700645 log.debug("Provisioned tables in {} with fitering "
646 + "rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700647 }
648
649 @Override
650 public void onError(FlowRuleOperations ops) {
651 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700652 log.warn("Failed to provision tables in {} with "
653 + "fitering rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700654 }
655 }));
656 }
657
658 protected void setTableMissEntries() {
659 // set all table-miss-entries
660 populateTableMissEntry(vlanTableId, true, false, false, -1);
661 populateTableMissEntry(tmacTableId, true, false, false, -1);
662 populateTableMissEntry(ipv4UnicastTableId, false, true, true,
663 aclTableId);
664 populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
665 populateTableMissEntry(aclTableId, false, false, false, -1);
666 }
667
668 protected void populateTableMissEntry(int tableToAdd,
669 boolean toControllerNow,
670 boolean toControllerWrite,
671 boolean toTable, int tableToSend) {
672 TrafficSelector selector = DefaultTrafficSelector.builder().build();
673 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
674
675 if (toControllerNow) {
676 tBuilder.setOutput(PortNumber.CONTROLLER);
677 }
678
679 if (toControllerWrite) {
680 tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
681 }
682
683 if (toTable) {
684 tBuilder.transition(tableToSend);
685 }
686
687 FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId)
688 .withSelector(selector).withTreatment(tBuilder.build())
689 .withPriority(0).fromApp(appId).makePermanent()
690 .forTable(tableToAdd).build();
691
692 flowRuleService.applyFlowRules(flow);
693 }
694
695 private void pass(Objective obj) {
696 if (obj.context().isPresent()) {
697 obj.context().get().onSuccess(obj);
698 }
699 }
700
701 protected void fail(Objective obj, ObjectiveError error) {
702 if (obj.context().isPresent()) {
703 obj.context().get().onError(obj, error);
704 }
705 }
706
707 private class InnerGroupListener implements GroupListener {
708 @Override
709 public void event(GroupEvent event) {
710 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700711 log.debug("InnerGroupListener: Group ADDED "
712 + "event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700713 GroupKey key = event.subject().appCookie();
714
715 NextObjective obj = pendingGroups.getIfPresent(key);
716 if (obj != null) {
717 flowObjectiveStore
718 .putNextGroup(obj.id(),
719 new SegmentRoutingGroup(key));
720 pass(obj);
721 pendingGroups.invalidate(key);
722 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700723 } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
724 log.warn("InnerGroupListener: Group ADD "
725 + "failed event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700726 }
727 }
728 }
729
730 private class GroupChecker implements Runnable {
731
732 @Override
733 public void run() {
734 Set<GroupKey> keys = pendingGroups
735 .asMap()
736 .keySet()
737 .stream()
738 .filter(key -> groupService.getGroup(deviceId, key) != null)
739 .collect(Collectors.toSet());
740
741 keys.stream()
742 .forEach(key -> {
743 NextObjective obj = pendingGroups
744 .getIfPresent(key);
745 if (obj == null) {
746 return;
747 }
748 pass(obj);
749 pendingGroups.invalidate(key);
750 flowObjectiveStore.putNextGroup(obj.id(),
751 new SegmentRoutingGroup(
752 key));
753 });
754 }
755 }
756
757 private class SegmentRoutingGroup implements NextGroup {
758
759 private final GroupKey key;
760
761 public SegmentRoutingGroup(GroupKey key) {
762 this.key = key;
763 }
764
765 public GroupKey key() {
766 return key;
767 }
768
769 @Override
770 public byte[] data() {
771 return appKryo.serialize(key);
772 }
773
774 }
775}