blob: bb2315dd4376179c1e21290014a69d9b307c3691 [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
217 if (nextObjective.op() == Objective.Operation.REMOVE) {
218 if (nextObjective.next() == null) {
219 removeGroup(nextObjective);
220 } else {
221 removeBucketFromGroup(nextObjective);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700222 }
sangho834e4b02015-05-01 09:38:25 -0700223 } else if (nextObjective.op() == Objective.Operation.ADD) {
224 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
225 if (nextGroup != null) {
226 addBucketToGroup(nextObjective);
227 } else {
228 addGroup(nextObjective);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700229 }
sangho834e4b02015-05-01 09:38:25 -0700230 } else {
231 log.warn("Unsupported operation {}", nextObjective.op());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700232 }
233
234 }
235
sangho834e4b02015-05-01 09:38:25 -0700236 private void removeGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700237 log.debug("removeGroup in {}: for next objective id {}",
238 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700239 final GroupKey key = new DefaultGroupKey(
240 appKryo.serialize(nextObjective.id()));
241 groupService.removeGroup(deviceId, key, appId);
242 }
243
244 private void addGroup(NextObjective nextObjective) {
245 switch (nextObjective.type()) {
246 case SIMPLE:
247 log.debug("processing SIMPLE next objective");
248 Collection<TrafficTreatment> treatments = nextObjective.next();
249 if (treatments.size() == 1) {
250 TrafficTreatment treatment = treatments.iterator().next();
251 GroupBucket bucket = DefaultGroupBucket
252 .createIndirectGroupBucket(treatment);
253 final GroupKey key = new DefaultGroupKey(
254 appKryo.serialize(nextObjective
255 .id()));
256 GroupDescription groupDescription = new DefaultGroupDescription(
257 deviceId,
258 GroupDescription.Type.INDIRECT,
259 new GroupBuckets(
260 Collections.singletonList(bucket)),
261 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700262 null,
sangho834e4b02015-05-01 09:38:25 -0700263 nextObjective.appId());
264 groupService.addGroup(groupDescription);
265 pendingGroups.put(key, nextObjective);
266 }
267 break;
268 case HASHED:
269 log.debug("processing HASHED next objective");
270 List<GroupBucket> buckets = nextObjective
271 .next()
272 .stream()
273 .map((treatment) -> DefaultGroupBucket
274 .createSelectGroupBucket(treatment))
275 .collect(Collectors.toList());
276 if (!buckets.isEmpty()) {
277 final GroupKey key = new DefaultGroupKey(
278 appKryo.serialize(nextObjective
279 .id()));
280 GroupDescription groupDescription = new DefaultGroupDescription(
281 deviceId,
282 GroupDescription.Type.SELECT,
283 new GroupBuckets(buckets),
284 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700285 null,
sangho834e4b02015-05-01 09:38:25 -0700286 nextObjective.appId());
287 groupService.addGroup(groupDescription);
288 pendingGroups.put(key, nextObjective);
289 }
290 break;
291 case BROADCAST:
292 case FAILOVER:
293 log.debug("BROADCAST and FAILOVER next objectives not supported");
294 fail(nextObjective, ObjectiveError.UNSUPPORTED);
295 log.warn("Unsupported next objective type {}", nextObjective.type());
296 break;
297 default:
298 fail(nextObjective, ObjectiveError.UNKNOWN);
299 log.warn("Unknown next objective type {}", nextObjective.type());
300 }
301 }
302
303 private void addBucketToGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700304 log.debug("addBucketToGroup in {}: for next objective id {}",
305 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700306 Collection<TrafficTreatment> treatments = nextObjective.next();
307 TrafficTreatment treatment = treatments.iterator().next();
308 final GroupKey key = new DefaultGroupKey(
309 appKryo.serialize(nextObjective
310 .id()));
311 Group group = groupService.getGroup(deviceId, key);
312 if (group == null) {
313 log.warn("Group is not found in {} for {}", deviceId, key);
314 return;
315 }
316 GroupBucket bucket;
317 if (group.type() == GroupDescription.Type.INDIRECT) {
318 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
319 } else if (group.type() == GroupDescription.Type.SELECT) {
320 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
321 } else {
322 log.warn("Unsupported Group type {}", group.type());
323 return;
324 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700325 GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket));
sangho834e4b02015-05-01 09:38:25 -0700326 groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId);
327 }
328
329 private void removeBucketFromGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700330 log.debug("removeBucketFromGroup in {}: for next objective id {}",
331 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700332 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
333 if (nextGroup != null) {
334 Collection<TrafficTreatment> treatments = nextObjective.next();
335 TrafficTreatment treatment = treatments.iterator().next();
336 final GroupKey key = new DefaultGroupKey(
337 appKryo.serialize(nextObjective
338 .id()));
339 Group group = groupService.getGroup(deviceId, key);
340 if (group == null) {
341 log.warn("Group is not found in {} for {}", deviceId, key);
342 return;
343 }
344 GroupBucket bucket;
345 if (group.type() == GroupDescription.Type.INDIRECT) {
346 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
347 } else if (group.type() == GroupDescription.Type.SELECT) {
348 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
349 } else {
350 log.warn("Unsupported Group type {}", group.type());
351 return;
352 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700353 GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
sangho834e4b02015-05-01 09:38:25 -0700354 groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId);
355 }
356 }
357
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700358 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
359 switch (fwd.flag()) {
360 case SPECIFIC:
361 return processSpecific(fwd);
362 case VERSATILE:
363 return processVersatile(fwd);
364 default:
365 fail(fwd, ObjectiveError.UNKNOWN);
366 log.warn("Unknown forwarding flag {}", fwd.flag());
367 }
368 return Collections.emptySet();
369 }
370
371 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
372 fail(fwd, ObjectiveError.UNSUPPORTED);
373 return Collections.emptySet();
374 }
375
376 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
377 log.debug("Processing specific");
378 TrafficSelector selector = fwd.selector();
379 EthTypeCriterion ethType = (EthTypeCriterion) selector
380 .getCriterion(Criterion.Type.ETH_TYPE);
381 if ((ethType == null) ||
382 ((((short) ethType.ethType()) != Ethernet.TYPE_IPV4) &&
383 (((short) ethType.ethType()) != Ethernet.MPLS_UNICAST))) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700384 log.warn("processSpecific: Unsupported "
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700385 + "forwarding objective criteraia");
386 fail(fwd, ObjectiveError.UNSUPPORTED);
387 return Collections.emptySet();
388 }
389
390 TrafficSelector.Builder filteredSelectorBuilder =
391 DefaultTrafficSelector.builder();
392 int forTableId = -1;
393 if (((short) ethType.ethType()) == Ethernet.TYPE_IPV4) {
394 filteredSelectorBuilder = filteredSelectorBuilder
395 .matchEthType(Ethernet.TYPE_IPV4)
396 .matchIPDst(((IPCriterion) selector
397 .getCriterion(Criterion.Type.IPV4_DST))
398 .ip());
399 forTableId = ipv4UnicastTableId;
400 log.debug("processing IPv4 specific forwarding objective");
401 } else {
402 filteredSelectorBuilder = filteredSelectorBuilder
403 .matchEthType(Ethernet.MPLS_UNICAST)
404 .matchMplsLabel(((MplsCriterion)
405 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
406 //TODO: Add Match for BoS
407 //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) {
408 //}
409 forTableId = mplsTableId;
410 log.debug("processing MPLS specific forwarding objective");
411 }
412
413 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
414 .builder();
415 if (fwd.treatment() != null) {
416 for (Instruction i : fwd.treatment().allInstructions()) {
417 treatmentBuilder.add(i);
418 }
419 }
420
421 //TODO: Analyze the forwarding objective here to make
422 //device specific decision such as no ECMP groups in Dell
423 //switches.
424 if (fwd.nextId() != null) {
425 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
426
427 if (next != null) {
428 GroupKey key = appKryo.deserialize(next.data());
429
430 Group group = groupService.getGroup(deviceId, key);
431
432 if (group == null) {
433 log.warn("The group left!");
434 fail(fwd, ObjectiveError.GROUPMISSING);
435 return Collections.emptySet();
436 }
437 treatmentBuilder.group(group.id());
438 log.debug("Adding OUTGROUP action");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700439 } else {
440 log.warn("processSpecific: No associated next objective object");
441 fail(fwd, ObjectiveError.GROUPMISSING);
442 return Collections.emptySet();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700443 }
444 }
445
446 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
447 TrafficTreatment treatment = treatmentBuilder.transition(aclTableId)
448 .build();
449
450 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
451 .fromApp(fwd.appId()).withPriority(fwd.priority())
452 .forDevice(deviceId).withSelector(filteredSelector)
453 .withTreatment(treatment);
454
455 if (fwd.permanent()) {
456 ruleBuilder.makePermanent();
457 } else {
458 ruleBuilder.makeTemporary(fwd.timeout());
459 }
460
461 ruleBuilder.forTable(forTableId);
462 return Collections.singletonList(ruleBuilder.build());
463
464 }
465
466 protected List<FlowRule> processEthDstFilter(Criterion c,
467 FilteringObjective filt,
468 ApplicationId applicationId) {
469 List<FlowRule> rules = new ArrayList<FlowRule>();
470 EthCriterion e = (EthCriterion) c;
471 TrafficSelector.Builder selectorIp = DefaultTrafficSelector
472 .builder();
473 TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
474 .builder();
475 selectorIp.matchEthDst(e.mac());
476 selectorIp.matchEthType(Ethernet.TYPE_IPV4);
477 treatmentIp.transition(ipv4UnicastTableId);
478 FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
479 .withSelector(selectorIp.build())
480 .withTreatment(treatmentIp.build())
481 .withPriority(filt.priority()).fromApp(applicationId)
482 .makePermanent().forTable(tmacTableId).build();
483 log.debug("adding IP ETH rule for MAC: {}", e.mac());
484 rules.add(ruleIp);
485
486 TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
487 .builder();
488 TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
489 .builder();
490 selectorMpls.matchEthDst(e.mac());
491 selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
492 treatmentMpls.transition(mplsTableId);
493 FlowRule ruleMpls = DefaultFlowRule.builder()
494 .forDevice(deviceId).withSelector(selectorMpls.build())
495 .withTreatment(treatmentMpls.build())
496 .withPriority(filt.priority()).fromApp(applicationId)
497 .makePermanent().forTable(tmacTableId).build();
498 log.debug("adding MPLS ETH rule for MAC: {}", e.mac());
499 rules.add(ruleMpls);
500
501 return rules;
502 }
503
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700504 protected List<FlowRule> processVlanIdFilter(Criterion c,
505 FilteringObjective filt,
506 ApplicationId applicationId) {
507 List<FlowRule> rules = new ArrayList<FlowRule>();
508 VlanIdCriterion v = (VlanIdCriterion) c;
509 log.debug("adding rule for VLAN: {}", v.vlanId());
510 TrafficSelector.Builder selector = DefaultTrafficSelector
511 .builder();
512 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
513 .builder();
514 PortCriterion p = (PortCriterion) filt.key();
515 if (v.vlanId() != VlanId.NONE) {
516 selector.matchVlanId(v.vlanId());
517 selector.matchInPort(p.port());
518 treatment.deferred().popVlan();
519 }
520 treatment.transition(tmacTableId);
521 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
522 .withSelector(selector.build())
523 .withTreatment(treatment.build())
524 .withPriority(filt.priority()).fromApp(applicationId)
525 .makePermanent().forTable(vlanTableId).build();
526 rules.add(rule);
527
528 return rules;
529 }
530
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700531 private void processFilter(FilteringObjective filt, boolean install,
532 ApplicationId applicationId) {
533 // This driver only processes filtering criteria defined with switch
534 // ports as the key
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700535 if (filt.key().equals(Criteria.dummy())
536 || filt.key().type() != Criterion.Type.IN_PORT) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700537 log.warn("No key defined in filtering objective from app: {}. Not"
538 + "processing filtering objective", applicationId);
539 fail(filt, ObjectiveError.UNKNOWN);
540 return;
541 }
542 // convert filtering conditions for switch-intfs into flowrules
543 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
544 for (Criterion c : filt.conditions()) {
545 if (c.type() == Criterion.Type.ETH_DST) {
546 for (FlowRule rule : processEthDstFilter(c,
547 filt,
548 applicationId)) {
549 ops = install ? ops.add(rule) : ops.remove(rule);
550 }
551 } else if (c.type() == Criterion.Type.VLAN_VID) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700552 for (FlowRule rule : processVlanIdFilter(c,
553 filt,
554 applicationId)) {
555 ops = install ? ops.add(rule) : ops.remove(rule);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700556 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700557 } else if (c.type() == Criterion.Type.IPV4_DST) {
558 IPCriterion ip = (IPCriterion) c;
559 log.debug("adding rule for IP: {}", ip.ip());
560 TrafficSelector.Builder selector = DefaultTrafficSelector
561 .builder();
562 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
563 .builder();
564 selector.matchEthType(Ethernet.TYPE_IPV4);
565 selector.matchIPDst(ip.ip());
566 treatment.transition(aclTableId);
567 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
568 .withSelector(selector.build())
569 .withTreatment(treatment.build())
570 .withPriority(filt.priority()).fromApp(applicationId)
571 .makePermanent().forTable(ipv4UnicastTableId).build();
572 ops = install ? ops.add(rule) : ops.remove(rule);
573 } else {
574 log.warn("Driver does not currently process filtering condition"
575 + " of type: {}", c.type());
576 fail(filt, ObjectiveError.UNSUPPORTED);
577 }
578 }
579 // apply filtering flow rules
580 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
581 @Override
582 public void onSuccess(FlowRuleOperations ops) {
583 pass(filt);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700584 log.debug("Provisioned tables in {} with fitering "
585 + "rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700586 }
587
588 @Override
589 public void onError(FlowRuleOperations ops) {
590 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700591 log.warn("Failed to provision tables in {} with "
592 + "fitering rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700593 }
594 }));
595 }
596
597 protected void setTableMissEntries() {
598 // set all table-miss-entries
599 populateTableMissEntry(vlanTableId, true, false, false, -1);
600 populateTableMissEntry(tmacTableId, true, false, false, -1);
601 populateTableMissEntry(ipv4UnicastTableId, false, true, true,
602 aclTableId);
603 populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
604 populateTableMissEntry(aclTableId, false, false, false, -1);
605 }
606
607 protected void populateTableMissEntry(int tableToAdd,
608 boolean toControllerNow,
609 boolean toControllerWrite,
610 boolean toTable, int tableToSend) {
611 TrafficSelector selector = DefaultTrafficSelector.builder().build();
612 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
613
614 if (toControllerNow) {
615 tBuilder.setOutput(PortNumber.CONTROLLER);
616 }
617
618 if (toControllerWrite) {
619 tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
620 }
621
622 if (toTable) {
623 tBuilder.transition(tableToSend);
624 }
625
626 FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId)
627 .withSelector(selector).withTreatment(tBuilder.build())
628 .withPriority(0).fromApp(appId).makePermanent()
629 .forTable(tableToAdd).build();
630
631 flowRuleService.applyFlowRules(flow);
632 }
633
634 private void pass(Objective obj) {
635 if (obj.context().isPresent()) {
636 obj.context().get().onSuccess(obj);
637 }
638 }
639
640 protected void fail(Objective obj, ObjectiveError error) {
641 if (obj.context().isPresent()) {
642 obj.context().get().onError(obj, error);
643 }
644 }
645
646 private class InnerGroupListener implements GroupListener {
647 @Override
648 public void event(GroupEvent event) {
649 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700650 log.debug("InnerGroupListener: Group ADDED "
651 + "event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700652 GroupKey key = event.subject().appCookie();
653
654 NextObjective obj = pendingGroups.getIfPresent(key);
655 if (obj != null) {
656 flowObjectiveStore
657 .putNextGroup(obj.id(),
658 new SegmentRoutingGroup(key));
659 pass(obj);
660 pendingGroups.invalidate(key);
661 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700662 } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
663 log.warn("InnerGroupListener: Group ADD "
664 + "failed event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700665 }
666 }
667 }
668
669 private class GroupChecker implements Runnable {
670
671 @Override
672 public void run() {
673 Set<GroupKey> keys = pendingGroups
674 .asMap()
675 .keySet()
676 .stream()
677 .filter(key -> groupService.getGroup(deviceId, key) != null)
678 .collect(Collectors.toSet());
679
680 keys.stream()
681 .forEach(key -> {
682 NextObjective obj = pendingGroups
683 .getIfPresent(key);
684 if (obj == null) {
685 return;
686 }
687 pass(obj);
688 pendingGroups.invalidate(key);
689 flowObjectiveStore.putNextGroup(obj.id(),
690 new SegmentRoutingGroup(
691 key));
692 });
693 }
694 }
695
696 private class SegmentRoutingGroup implements NextGroup {
697
698 private final GroupKey key;
699
700 public SegmentRoutingGroup(GroupKey key) {
701 this.key = key;
702 }
703
704 public GroupKey key() {
705 return key;
706 }
707
708 @Override
709 public byte[] data() {
710 return appKryo.serialize(key);
711 }
712
713 }
714}