blob: 31297ff43830931264224854809d9733d217ff71 [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;
Saurav Das822c4e22015-10-23 10:51:11 -070056import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070057import 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());
Charles Chanc42e84e2015-10-20 16:24:19 -0700250 List<GroupBucket> buckets;
sangho834e4b02015-05-01 09:38:25 -0700251 switch (nextObjective.type()) {
252 case SIMPLE:
253 log.debug("processing SIMPLE next objective");
254 Collection<TrafficTreatment> treatments = nextObjective.next();
255 if (treatments.size() == 1) {
256 TrafficTreatment treatment = treatments.iterator().next();
257 GroupBucket bucket = DefaultGroupBucket
258 .createIndirectGroupBucket(treatment);
259 final GroupKey key = new DefaultGroupKey(
260 appKryo.serialize(nextObjective
261 .id()));
262 GroupDescription groupDescription = new DefaultGroupDescription(
263 deviceId,
264 GroupDescription.Type.INDIRECT,
265 new GroupBuckets(
266 Collections.singletonList(bucket)),
267 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700268 null,
sangho834e4b02015-05-01 09:38:25 -0700269 nextObjective.appId());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700270 log.debug("Creating SIMPLE group for next objective id {}",
271 nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700272 groupService.addGroup(groupDescription);
273 pendingGroups.put(key, nextObjective);
274 }
275 break;
276 case HASHED:
277 log.debug("processing HASHED next objective");
Charles Chanc42e84e2015-10-20 16:24:19 -0700278 buckets = nextObjective
sangho834e4b02015-05-01 09:38:25 -0700279 .next()
280 .stream()
281 .map((treatment) -> DefaultGroupBucket
282 .createSelectGroupBucket(treatment))
283 .collect(Collectors.toList());
284 if (!buckets.isEmpty()) {
285 final GroupKey key = new DefaultGroupKey(
286 appKryo.serialize(nextObjective
287 .id()));
288 GroupDescription groupDescription = new DefaultGroupDescription(
289 deviceId,
290 GroupDescription.Type.SELECT,
291 new GroupBuckets(buckets),
292 key,
Saurav Das100e3b82015-04-30 11:12:10 -0700293 null,
sangho834e4b02015-05-01 09:38:25 -0700294 nextObjective.appId());
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700295 log.debug("Creating HASHED group for next objective id {}",
296 nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700297 groupService.addGroup(groupDescription);
298 pendingGroups.put(key, nextObjective);
299 }
300 break;
301 case BROADCAST:
Charles Chanc42e84e2015-10-20 16:24:19 -0700302 log.debug("processing BROADCAST next objective");
303 buckets = nextObjective
304 .next()
305 .stream()
306 .map((treatment) -> DefaultGroupBucket
307 .createAllGroupBucket(treatment))
308 .collect(Collectors.toList());
309 if (!buckets.isEmpty()) {
310 final GroupKey key = new DefaultGroupKey(
311 appKryo.serialize(nextObjective
312 .id()));
313 GroupDescription groupDescription = new DefaultGroupDescription(
314 deviceId,
315 GroupDescription.Type.ALL,
316 new GroupBuckets(buckets),
317 key,
318 null,
319 nextObjective.appId());
320 log.debug("Creating BROADCAST group for next objective id {}",
321 nextObjective.id());
322 groupService.addGroup(groupDescription);
323 pendingGroups.put(key, nextObjective);
324 }
325 break;
sangho834e4b02015-05-01 09:38:25 -0700326 case FAILOVER:
Charles Chanc42e84e2015-10-20 16:24:19 -0700327 log.debug("FAILOVER next objectives not supported");
sangho834e4b02015-05-01 09:38:25 -0700328 fail(nextObjective, ObjectiveError.UNSUPPORTED);
329 log.warn("Unsupported next objective type {}", nextObjective.type());
330 break;
331 default:
332 fail(nextObjective, ObjectiveError.UNKNOWN);
333 log.warn("Unknown next objective type {}", nextObjective.type());
334 }
335 }
336
337 private void addBucketToGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700338 log.debug("addBucketToGroup in {}: for next objective id {}",
339 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700340 Collection<TrafficTreatment> treatments = nextObjective.next();
341 TrafficTreatment treatment = treatments.iterator().next();
342 final GroupKey key = new DefaultGroupKey(
343 appKryo.serialize(nextObjective
344 .id()));
345 Group group = groupService.getGroup(deviceId, key);
346 if (group == null) {
347 log.warn("Group is not found in {} for {}", deviceId, key);
348 return;
349 }
350 GroupBucket bucket;
351 if (group.type() == GroupDescription.Type.INDIRECT) {
352 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
353 } else if (group.type() == GroupDescription.Type.SELECT) {
354 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
Charles Chanc42e84e2015-10-20 16:24:19 -0700355 } else if (group.type() == GroupDescription.Type.ALL) {
356 bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
sangho834e4b02015-05-01 09:38:25 -0700357 } else {
358 log.warn("Unsupported Group type {}", group.type());
359 return;
360 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700361 GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket));
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700362 log.debug("Adding buckets to group id {} of next objective id {} in device {}",
363 group.id(), nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700364 groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId);
365 }
366
367 private void removeBucketFromGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700368 log.debug("removeBucketFromGroup in {}: for next objective id {}",
369 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700370 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
371 if (nextGroup != null) {
372 Collection<TrafficTreatment> treatments = nextObjective.next();
373 TrafficTreatment treatment = treatments.iterator().next();
374 final GroupKey key = new DefaultGroupKey(
375 appKryo.serialize(nextObjective
376 .id()));
377 Group group = groupService.getGroup(deviceId, key);
378 if (group == null) {
379 log.warn("Group is not found in {} for {}", deviceId, key);
380 return;
381 }
382 GroupBucket bucket;
383 if (group.type() == GroupDescription.Type.INDIRECT) {
384 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
385 } else if (group.type() == GroupDescription.Type.SELECT) {
386 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
Charles Chanc42e84e2015-10-20 16:24:19 -0700387 } else if (group.type() == GroupDescription.Type.ALL) {
388 bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
sangho834e4b02015-05-01 09:38:25 -0700389 } else {
390 log.warn("Unsupported Group type {}", group.type());
391 return;
392 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700393 GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700394 log.debug("Removing buckets from group id {} of next objective id {} in device {}",
395 group.id(), nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700396 groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId);
397 }
398 }
399
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700400 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
401 switch (fwd.flag()) {
402 case SPECIFIC:
403 return processSpecific(fwd);
404 case VERSATILE:
405 return processVersatile(fwd);
406 default:
407 fail(fwd, ObjectiveError.UNKNOWN);
408 log.warn("Unknown forwarding flag {}", fwd.flag());
409 }
410 return Collections.emptySet();
411 }
412
413 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
sangho1e575652015-05-14 00:39:53 -0700414 log.debug("Processing versatile forwarding objective");
415 TrafficSelector selector = fwd.selector();
Saurav Das822c4e22015-10-23 10:51:11 -0700416 TrafficTreatment treatment = null;
sangho1e575652015-05-14 00:39:53 -0700417 EthTypeCriterion ethType =
418 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
419 if (ethType == null) {
420 log.error("Versatile forwarding objective must include ethType");
421 fail(fwd, ObjectiveError.UNKNOWN);
422 return Collections.emptySet();
423 }
424
sangho1e575652015-05-14 00:39:53 -0700425 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
426 .builder();
427 treatmentBuilder.wipeDeferred();
428
429 if (fwd.nextId() != null) {
430 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
431
432 if (next != null) {
433 GroupKey key = appKryo.deserialize(next.data());
434
435 Group group = groupService.getGroup(deviceId, key);
436
437 if (group == null) {
438 log.warn("The group left!");
439 fail(fwd, ObjectiveError.GROUPMISSING);
440 return Collections.emptySet();
441 }
442 treatmentBuilder.deferred().group(group.id());
Saurav Das822c4e22015-10-23 10:51:11 -0700443 treatment = treatmentBuilder.build();
sangho1e575652015-05-14 00:39:53 -0700444 log.debug("Adding OUTGROUP action");
445 }
Saurav Das822c4e22015-10-23 10:51:11 -0700446 } else if (fwd.treatment() != null) {
447 if (fwd.treatment().allInstructions().size() == 1 &&
448 fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
449 OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
450 if (o.port() == PortNumber.CONTROLLER) {
451 log.warn("Punts to the controller are handled by misses in"
452 + " the TMAC, IP and MPLS tables.");
453 return Collections.emptySet();
454 }
455 }
456 treatment = fwd.treatment();
sangho1e575652015-05-14 00:39:53 -0700457 } else {
Saurav Das822c4e22015-10-23 10:51:11 -0700458 log.warn("VERSATILE forwarding objective needs next objective ID "
459 + "or treatment.");
sangho1e575652015-05-14 00:39:53 -0700460 return Collections.emptySet();
461 }
462
sangho1e575652015-05-14 00:39:53 -0700463 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
464 .fromApp(fwd.appId()).withPriority(fwd.priority())
sanghof9d0bf12015-05-19 11:57:42 -0700465 .forDevice(deviceId).withSelector(fwd.selector())
sangho1e575652015-05-14 00:39:53 -0700466 .withTreatment(treatment);
467
468 if (fwd.permanent()) {
469 ruleBuilder.makePermanent();
470 } else {
471 ruleBuilder.makeTemporary(fwd.timeout());
472 }
473
474 ruleBuilder.forTable(aclTableId);
475 return Collections.singletonList(ruleBuilder.build());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700476 }
477
478 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
479 log.debug("Processing specific");
480 TrafficSelector selector = fwd.selector();
481 EthTypeCriterion ethType = (EthTypeCriterion) selector
482 .getCriterion(Criterion.Type.ETH_TYPE);
483 if ((ethType == null) ||
alshabibcaf1ca22015-06-25 15:18:16 -0700484 (ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
485 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST)) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700486 log.warn("processSpecific: Unsupported "
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700487 + "forwarding objective criteraia");
488 fail(fwd, ObjectiveError.UNSUPPORTED);
489 return Collections.emptySet();
490 }
491
492 TrafficSelector.Builder filteredSelectorBuilder =
493 DefaultTrafficSelector.builder();
494 int forTableId = -1;
alshabibcaf1ca22015-06-25 15:18:16 -0700495 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700496 filteredSelectorBuilder = filteredSelectorBuilder
497 .matchEthType(Ethernet.TYPE_IPV4)
498 .matchIPDst(((IPCriterion) selector
499 .getCriterion(Criterion.Type.IPV4_DST))
500 .ip());
501 forTableId = ipv4UnicastTableId;
502 log.debug("processing IPv4 specific forwarding objective");
503 } else {
504 filteredSelectorBuilder = filteredSelectorBuilder
505 .matchEthType(Ethernet.MPLS_UNICAST)
506 .matchMplsLabel(((MplsCriterion)
507 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
508 //TODO: Add Match for BoS
509 //if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) {
510 //}
511 forTableId = mplsTableId;
512 log.debug("processing MPLS specific forwarding objective");
513 }
514
515 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
516 .builder();
517 if (fwd.treatment() != null) {
518 for (Instruction i : fwd.treatment().allInstructions()) {
519 treatmentBuilder.add(i);
520 }
521 }
522
523 //TODO: Analyze the forwarding objective here to make
524 //device specific decision such as no ECMP groups in Dell
525 //switches.
526 if (fwd.nextId() != null) {
527 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
528
529 if (next != null) {
530 GroupKey key = appKryo.deserialize(next.data());
531
532 Group group = groupService.getGroup(deviceId, key);
533
534 if (group == null) {
535 log.warn("The group left!");
536 fail(fwd, ObjectiveError.GROUPMISSING);
537 return Collections.emptySet();
538 }
sangho1e575652015-05-14 00:39:53 -0700539 treatmentBuilder.deferred().group(group.id());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700540 log.debug("Adding OUTGROUP action");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700541 } else {
542 log.warn("processSpecific: No associated next objective object");
543 fail(fwd, ObjectiveError.GROUPMISSING);
544 return Collections.emptySet();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700545 }
546 }
547
548 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
549 TrafficTreatment treatment = treatmentBuilder.transition(aclTableId)
550 .build();
551
552 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
553 .fromApp(fwd.appId()).withPriority(fwd.priority())
554 .forDevice(deviceId).withSelector(filteredSelector)
555 .withTreatment(treatment);
556
557 if (fwd.permanent()) {
558 ruleBuilder.makePermanent();
559 } else {
560 ruleBuilder.makeTemporary(fwd.timeout());
561 }
562
563 ruleBuilder.forTable(forTableId);
564 return Collections.singletonList(ruleBuilder.build());
565
566 }
567
568 protected List<FlowRule> processEthDstFilter(Criterion c,
569 FilteringObjective filt,
570 ApplicationId applicationId) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700571 List<FlowRule> rules = new ArrayList<>();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700572 EthCriterion e = (EthCriterion) c;
573 TrafficSelector.Builder selectorIp = DefaultTrafficSelector
574 .builder();
575 TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
576 .builder();
577 selectorIp.matchEthDst(e.mac());
578 selectorIp.matchEthType(Ethernet.TYPE_IPV4);
579 treatmentIp.transition(ipv4UnicastTableId);
580 FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
581 .withSelector(selectorIp.build())
582 .withTreatment(treatmentIp.build())
583 .withPriority(filt.priority()).fromApp(applicationId)
584 .makePermanent().forTable(tmacTableId).build();
585 log.debug("adding IP ETH rule for MAC: {}", e.mac());
586 rules.add(ruleIp);
587
588 TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
589 .builder();
590 TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
591 .builder();
592 selectorMpls.matchEthDst(e.mac());
593 selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
594 treatmentMpls.transition(mplsTableId);
595 FlowRule ruleMpls = DefaultFlowRule.builder()
596 .forDevice(deviceId).withSelector(selectorMpls.build())
597 .withTreatment(treatmentMpls.build())
598 .withPriority(filt.priority()).fromApp(applicationId)
599 .makePermanent().forTable(tmacTableId).build();
600 log.debug("adding MPLS ETH rule for MAC: {}", e.mac());
601 rules.add(ruleMpls);
602
603 return rules;
604 }
605
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700606 protected List<FlowRule> processVlanIdFilter(Criterion c,
607 FilteringObjective filt,
608 ApplicationId applicationId) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700609 List<FlowRule> rules = new ArrayList<>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700610 VlanIdCriterion v = (VlanIdCriterion) c;
611 log.debug("adding rule for VLAN: {}", v.vlanId());
612 TrafficSelector.Builder selector = DefaultTrafficSelector
613 .builder();
614 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
615 .builder();
616 PortCriterion p = (PortCriterion) filt.key();
617 if (v.vlanId() != VlanId.NONE) {
618 selector.matchVlanId(v.vlanId());
619 selector.matchInPort(p.port());
620 treatment.deferred().popVlan();
621 }
622 treatment.transition(tmacTableId);
623 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
624 .withSelector(selector.build())
625 .withTreatment(treatment.build())
626 .withPriority(filt.priority()).fromApp(applicationId)
627 .makePermanent().forTable(vlanTableId).build();
628 rules.add(rule);
629
630 return rules;
631 }
632
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700633 private void processFilter(FilteringObjective filt, boolean install,
634 ApplicationId applicationId) {
635 // This driver only processes filtering criteria defined with switch
636 // ports as the key
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700637 if (filt.key().equals(Criteria.dummy())
638 || filt.key().type() != Criterion.Type.IN_PORT) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700639 log.warn("No key defined in filtering objective from app: {}. Not"
640 + "processing filtering objective", applicationId);
641 fail(filt, ObjectiveError.UNKNOWN);
642 return;
643 }
644 // convert filtering conditions for switch-intfs into flowrules
645 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
646 for (Criterion c : filt.conditions()) {
647 if (c.type() == Criterion.Type.ETH_DST) {
648 for (FlowRule rule : processEthDstFilter(c,
649 filt,
650 applicationId)) {
651 ops = install ? ops.add(rule) : ops.remove(rule);
652 }
653 } else if (c.type() == Criterion.Type.VLAN_VID) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700654 for (FlowRule rule : processVlanIdFilter(c,
655 filt,
656 applicationId)) {
657 ops = install ? ops.add(rule) : ops.remove(rule);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700658 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700659 } else if (c.type() == Criterion.Type.IPV4_DST) {
Saurav Das822c4e22015-10-23 10:51:11 -0700660 log.debug("driver does not process IP filtering rules as it " +
661 "sends all misses in the IP table to the controller");
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700662 } else {
663 log.warn("Driver does not currently process filtering condition"
664 + " of type: {}", c.type());
665 fail(filt, ObjectiveError.UNSUPPORTED);
666 }
667 }
668 // apply filtering flow rules
669 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
670 @Override
671 public void onSuccess(FlowRuleOperations ops) {
672 pass(filt);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700673 log.debug("Provisioned tables in {} with fitering "
674 + "rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700675 }
676
677 @Override
678 public void onError(FlowRuleOperations ops) {
679 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700680 log.warn("Failed to provision tables in {} with "
681 + "fitering rules for segment router", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700682 }
683 }));
684 }
685
686 protected void setTableMissEntries() {
687 // set all table-miss-entries
688 populateTableMissEntry(vlanTableId, true, false, false, -1);
689 populateTableMissEntry(tmacTableId, true, false, false, -1);
690 populateTableMissEntry(ipv4UnicastTableId, false, true, true,
691 aclTableId);
692 populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
693 populateTableMissEntry(aclTableId, false, false, false, -1);
694 }
695
696 protected void populateTableMissEntry(int tableToAdd,
697 boolean toControllerNow,
698 boolean toControllerWrite,
699 boolean toTable, int tableToSend) {
700 TrafficSelector selector = DefaultTrafficSelector.builder().build();
701 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
702
703 if (toControllerNow) {
704 tBuilder.setOutput(PortNumber.CONTROLLER);
705 }
706
707 if (toControllerWrite) {
708 tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
709 }
710
711 if (toTable) {
712 tBuilder.transition(tableToSend);
713 }
714
715 FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId)
716 .withSelector(selector).withTreatment(tBuilder.build())
717 .withPriority(0).fromApp(appId).makePermanent()
718 .forTable(tableToAdd).build();
719
720 flowRuleService.applyFlowRules(flow);
721 }
722
723 private void pass(Objective obj) {
724 if (obj.context().isPresent()) {
725 obj.context().get().onSuccess(obj);
726 }
727 }
728
729 protected void fail(Objective obj, ObjectiveError error) {
730 if (obj.context().isPresent()) {
731 obj.context().get().onError(obj, error);
732 }
733 }
734
735 private class InnerGroupListener implements GroupListener {
736 @Override
737 public void event(GroupEvent event) {
738 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700739 log.debug("InnerGroupListener: Group ADDED "
740 + "event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700741 GroupKey key = event.subject().appCookie();
742
743 NextObjective obj = pendingGroups.getIfPresent(key);
744 if (obj != null) {
745 flowObjectiveStore
746 .putNextGroup(obj.id(),
747 new SegmentRoutingGroup(key));
748 pass(obj);
749 pendingGroups.invalidate(key);
750 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700751 } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
752 log.warn("InnerGroupListener: Group ADD "
753 + "failed event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700754 }
755 }
756 }
757
758 private class GroupChecker implements Runnable {
759
760 @Override
761 public void run() {
762 Set<GroupKey> keys = pendingGroups
763 .asMap()
764 .keySet()
765 .stream()
766 .filter(key -> groupService.getGroup(deviceId, key) != null)
767 .collect(Collectors.toSet());
768
769 keys.stream()
770 .forEach(key -> {
771 NextObjective obj = pendingGroups
772 .getIfPresent(key);
773 if (obj == null) {
774 return;
775 }
776 pass(obj);
777 pendingGroups.invalidate(key);
778 flowObjectiveStore.putNextGroup(obj.id(),
779 new SegmentRoutingGroup(
780 key));
781 });
782 }
783 }
784
785 private class SegmentRoutingGroup implements NextGroup {
786
787 private final GroupKey key;
788
789 public SegmentRoutingGroup(GroupKey key) {
790 this.key = key;
791 }
792
Saurav Das822c4e22015-10-23 10:51:11 -0700793 @SuppressWarnings("unused")
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700794 public GroupKey key() {
795 return key;
796 }
797
798 @Override
799 public byte[] data() {
800 return appKryo.serialize(key);
801 }
802
803 }
804}