blob: 5be8a3f0912d99291466cf489dedb00752d17415 [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;
Charles Chan68aa62d2015-11-09 16:37:23 -080028import org.onlab.packet.MacAddress;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070029import org.onlab.packet.VlanId;
30import org.onlab.util.KryoNamespace;
31import org.onosproject.core.ApplicationId;
32import org.onosproject.core.CoreService;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.PortNumber;
35import org.onosproject.net.behaviour.NextGroup;
36import org.onosproject.net.behaviour.Pipeliner;
37import org.onosproject.net.behaviour.PipelinerContext;
38import org.onosproject.net.driver.AbstractHandlerBehaviour;
39import org.onosproject.net.flow.DefaultFlowRule;
40import org.onosproject.net.flow.DefaultTrafficSelector;
41import org.onosproject.net.flow.DefaultTrafficTreatment;
42import org.onosproject.net.flow.FlowRule;
43import org.onosproject.net.flow.FlowRuleOperations;
44import org.onosproject.net.flow.FlowRuleOperationsContext;
45import org.onosproject.net.flow.FlowRuleService;
46import org.onosproject.net.flow.TrafficSelector;
47import org.onosproject.net.flow.TrafficTreatment;
48import org.onosproject.net.flow.criteria.Criteria;
49import org.onosproject.net.flow.criteria.Criterion;
Saurav Das8a0732e2015-11-20 15:27:53 -080050import org.onosproject.net.flow.criteria.Criterion.Type;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070051import org.onosproject.net.flow.criteria.EthCriterion;
52import org.onosproject.net.flow.criteria.EthTypeCriterion;
53import org.onosproject.net.flow.criteria.IPCriterion;
Charles Chan188ebf52015-12-23 00:15:11 -080054import org.onosproject.net.flow.criteria.MplsBosCriterion;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070055import org.onosproject.net.flow.criteria.MplsCriterion;
56import org.onosproject.net.flow.criteria.PortCriterion;
57import org.onosproject.net.flow.criteria.VlanIdCriterion;
58import org.onosproject.net.flow.instructions.Instruction;
Saurav Das822c4e22015-10-23 10:51:11 -070059import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Charles Chan68aa62d2015-11-09 16:37:23 -080060import org.onosproject.net.flow.instructions.L2ModificationInstruction.ModVlanIdInstruction;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070061import org.onosproject.net.flowobjective.FilteringObjective;
62import org.onosproject.net.flowobjective.FlowObjectiveStore;
63import org.onosproject.net.flowobjective.ForwardingObjective;
64import org.onosproject.net.flowobjective.NextObjective;
65import org.onosproject.net.flowobjective.Objective;
66import org.onosproject.net.flowobjective.ObjectiveError;
67import org.onosproject.net.group.DefaultGroupBucket;
68import org.onosproject.net.group.DefaultGroupDescription;
69import org.onosproject.net.group.DefaultGroupKey;
70import org.onosproject.net.group.Group;
71import org.onosproject.net.group.GroupBucket;
72import org.onosproject.net.group.GroupBuckets;
73import org.onosproject.net.group.GroupDescription;
74import org.onosproject.net.group.GroupEvent;
75import org.onosproject.net.group.GroupKey;
76import org.onosproject.net.group.GroupListener;
77import org.onosproject.net.group.GroupService;
Saurav Das8a0732e2015-11-20 15:27:53 -080078import org.onosproject.store.serializers.KryoNamespaces;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070079import org.slf4j.Logger;
80
81import java.util.ArrayList;
82import java.util.Collection;
83import java.util.Collections;
84import java.util.List;
85import java.util.Set;
86import java.util.concurrent.Executors;
87import java.util.concurrent.ScheduledExecutorService;
88import java.util.concurrent.TimeUnit;
89import java.util.stream.Collectors;
90
91/**
92 * Driver for SPRING-OPEN pipeline.
93 */
94public class SpringOpenTTP extends AbstractHandlerBehaviour
95 implements Pipeliner {
96
97 // Default table ID - compatible with CpqD switch
98 private static final int TABLE_VLAN = 0;
99 private static final int TABLE_TMAC = 1;
100 private static final int TABLE_IPV4_UNICAST = 2;
101 private static final int TABLE_MPLS = 3;
Charles Chan68aa62d2015-11-09 16:37:23 -0800102 private static final int TABLE_DMAC = 4;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700103 private static final int TABLE_ACL = 5;
Charles Chan68aa62d2015-11-09 16:37:23 -0800104 private static final int TABLE_SMAC = 6;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700105
106 /**
107 * Set the default values. These variables will get overwritten based on the
108 * switch vendor type
109 */
110 protected int vlanTableId = TABLE_VLAN;
111 protected int tmacTableId = TABLE_TMAC;
112 protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST;
113 protected int mplsTableId = TABLE_MPLS;
Charles Chan68aa62d2015-11-09 16:37:23 -0800114 protected int dstMacTableId = TABLE_DMAC;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700115 protected int aclTableId = TABLE_ACL;
Charles Chan68aa62d2015-11-09 16:37:23 -0800116 protected int srcMacTableId = TABLE_SMAC;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700117
118 protected final Logger log = getLogger(getClass());
119
120 private ServiceDirectory serviceDirectory;
121 private FlowRuleService flowRuleService;
122 private CoreService coreService;
123 protected GroupService groupService;
124 protected FlowObjectiveStore flowObjectiveStore;
125 protected DeviceId deviceId;
126 private ApplicationId appId;
127
128 private Cache<GroupKey, NextObjective> pendingGroups;
129
130 private ScheduledExecutorService groupChecker = Executors
131 .newScheduledThreadPool(2,
132 groupedThreads("onos/pipeliner",
133 "spring-open-%d"));
134 protected KryoNamespace appKryo = new KryoNamespace.Builder()
Saurav Das8a0732e2015-11-20 15:27:53 -0800135 .register(KryoNamespaces.API)
136 .register(GroupKey.class)
137 .register(DefaultGroupKey.class)
138 .register(TrafficTreatment.class)
139 .register(SpringOpenGroup.class)
140 .register(byte[].class)
141 .build();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700142
143 @Override
144 public void init(DeviceId deviceId, PipelinerContext context) {
145 this.serviceDirectory = context.directory();
146 this.deviceId = deviceId;
147
148 pendingGroups = CacheBuilder
149 .newBuilder()
150 .expireAfterWrite(20, TimeUnit.SECONDS)
151 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
152 if (notification.getCause() == RemovalCause.EXPIRED) {
153 fail(notification.getValue(),
154 ObjectiveError.GROUPINSTALLATIONFAILED);
155 }
156 }).build();
157
158 groupChecker.scheduleAtFixedRate(new GroupChecker(), 0, 500,
159 TimeUnit.MILLISECONDS);
160
161 coreService = serviceDirectory.get(CoreService.class);
162 flowRuleService = serviceDirectory.get(FlowRuleService.class);
163 groupService = serviceDirectory.get(GroupService.class);
164 flowObjectiveStore = context.store();
165
166 groupService.addListener(new InnerGroupListener());
167
168 appId = coreService
169 .registerApplication("org.onosproject.driver.SpringOpenTTP");
170
171 setTableMissEntries();
172 log.info("Spring Open TTP driver initialized");
173 }
174
175 @Override
176 public void filter(FilteringObjective filteringObjective) {
177 if (filteringObjective.type() == FilteringObjective.Type.PERMIT) {
178 log.debug("processing PERMIT filter objective");
179 processFilter(filteringObjective,
180 filteringObjective.op() == Objective.Operation.ADD,
181 filteringObjective.appId());
182 } else {
183 log.debug("filter objective other than PERMIT not supported");
184 fail(filteringObjective, ObjectiveError.UNSUPPORTED);
185 }
186 }
187
188 @Override
189 public void forward(ForwardingObjective fwd) {
190 Collection<FlowRule> rules;
191 FlowRuleOperations.Builder flowBuilder = FlowRuleOperations.builder();
192
193 rules = processForward(fwd);
194 switch (fwd.op()) {
195 case ADD:
196 rules.stream().filter(rule -> rule != null)
197 .forEach(flowBuilder::add);
198 break;
199 case REMOVE:
200 rules.stream().filter(rule -> rule != null)
201 .forEach(flowBuilder::remove);
202 break;
203 default:
204 fail(fwd, ObjectiveError.UNKNOWN);
205 log.warn("Unknown forwarding type {}", fwd.op());
206 }
207
208 flowRuleService.apply(flowBuilder
209 .build(new FlowRuleOperationsContext() {
210 @Override
211 public void onSuccess(FlowRuleOperations ops) {
212 pass(fwd);
Saurav Das8a0732e2015-11-20 15:27:53 -0800213 log.debug("Provisioned tables in {} successfully with "
214 + "forwarding rules", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700215 }
216
217 @Override
218 public void onError(FlowRuleOperations ops) {
219 fail(fwd, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700220 log.warn("Failed to provision tables in {} with "
Saurav Das8a0732e2015-11-20 15:27:53 -0800221 + "forwarding rules", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700222 }
223 }));
224
225 }
226
227 @Override
228 public void next(NextObjective nextObjective) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800229 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
230 switch (nextObjective.op()) {
231 case ADD:
sangho834e4b02015-05-01 09:38:25 -0700232 if (nextGroup != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800233 log.warn("Cannot add next {} that already exists in device {}",
234 nextObjective.id(), deviceId);
235 return;
236 }
237 log.debug("Processing NextObjective id{} in dev{} - add group",
238 nextObjective.id(), deviceId);
239 addGroup(nextObjective);
240 break;
241 case ADD_TO_EXISTING:
242 if (nextGroup != null) {
243 log.debug("Processing NextObjective id{} in dev{} - add bucket",
244 nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700245 addBucketToGroup(nextObjective);
246 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -0800247 log.warn("Cannot add to group that does not exist");
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700248 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800249 break;
250 case REMOVE:
251 if (nextGroup == null) {
252 log.warn("Cannot remove next {} that does not exist in device {}",
253 nextObjective.id(), deviceId);
254 return;
255 }
256 log.debug("Processing NextObjective id{} in dev{} - remove group",
257 nextObjective.id(), deviceId);
258 removeGroup(nextObjective);
259 break;
260 case REMOVE_FROM_EXISTING:
261 if (nextGroup == null) {
262 log.warn("Cannot remove from next {} that does not exist in device {}",
263 nextObjective.id(), deviceId);
264 return;
265 }
266 log.debug("Processing NextObjective id{} in dev{} - remove bucket",
267 nextObjective.id(), deviceId);
268 removeBucketFromGroup(nextObjective);
269 break;
270 default:
sangho834e4b02015-05-01 09:38:25 -0700271 log.warn("Unsupported operation {}", nextObjective.op());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700272 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700273 }
274
sangho834e4b02015-05-01 09:38:25 -0700275 private void removeGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700276 log.debug("removeGroup in {}: for next objective id {}",
277 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700278 final GroupKey key = new DefaultGroupKey(
279 appKryo.serialize(nextObjective.id()));
280 groupService.removeGroup(deviceId, key, appId);
281 }
282
283 private void addGroup(NextObjective nextObjective) {
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700284 log.debug("addGroup with type{} for nextObjective id {}",
285 nextObjective.type(), nextObjective.id());
Charles Chanc42e84e2015-10-20 16:24:19 -0700286 List<GroupBucket> buckets;
sangho834e4b02015-05-01 09:38:25 -0700287 switch (nextObjective.type()) {
288 case SIMPLE:
sangho834e4b02015-05-01 09:38:25 -0700289 Collection<TrafficTreatment> treatments = nextObjective.next();
290 if (treatments.size() == 1) {
Saurav Das4ce45962015-11-24 23:21:05 -0800291 // Spring Open TTP converts simple nextObjective to flow-actions
292 // in a dummy group
293 TrafficTreatment treatment = nextObjective.next().iterator().next();
294 log.debug("Converting SIMPLE group for next objective id {} " +
295 "to {} flow-actions in device:{}", nextObjective.id(),
296 treatment.allInstructions().size(), deviceId);
297 flowObjectiveStore.putNextGroup(nextObjective.id(),
298 new SpringOpenGroup(null, treatment));
sangho834e4b02015-05-01 09:38:25 -0700299 }
300 break;
301 case HASHED:
Saurav Das8a0732e2015-11-20 15:27:53 -0800302 // we convert MPLS ECMP groups to flow-actions for a single
303 // bucket(output port).
304 boolean mplsEcmp = false;
305 if (nextObjective.meta() != null) {
306 for (Criterion c : nextObjective.meta().criteria()) {
307 if (c.type() == Type.MPLS_LABEL) {
308 mplsEcmp = true;
309 }
310 }
311 }
312 if (mplsEcmp) {
313 // covert to flow-actions in a dummy group by choosing the first bucket
314 log.debug("Converting HASHED group for next objective id {} " +
315 "to flow-actions in device:{}", nextObjective.id(),
316 deviceId);
317 TrafficTreatment treatment = nextObjective.next().iterator().next();
318 flowObjectiveStore.putNextGroup(nextObjective.id(),
319 new SpringOpenGroup(null, treatment));
320 } else {
321 // process as ECMP group
322 buckets = nextObjective
323 .next()
324 .stream()
325 .map((treatment) -> DefaultGroupBucket
326 .createSelectGroupBucket(treatment))
327 .collect(Collectors.toList());
328 if (!buckets.isEmpty()) {
329 final GroupKey key = new DefaultGroupKey(
330 appKryo.serialize(nextObjective.id()));
331 GroupDescription groupDescription = new DefaultGroupDescription(
332 deviceId,
333 GroupDescription.Type.SELECT,
334 new GroupBuckets(buckets),
335 key,
336 null,
337 nextObjective.appId());
338 log.debug("Creating HASHED group for next objective id {}"
339 + " in dev:{}", nextObjective.id(), deviceId);
340 pendingGroups.put(key, nextObjective);
341 groupService.addGroup(groupDescription);
342 }
sangho834e4b02015-05-01 09:38:25 -0700343 }
344 break;
345 case BROADCAST:
Charles Chanc42e84e2015-10-20 16:24:19 -0700346 buckets = nextObjective
347 .next()
348 .stream()
349 .map((treatment) -> DefaultGroupBucket
350 .createAllGroupBucket(treatment))
351 .collect(Collectors.toList());
352 if (!buckets.isEmpty()) {
353 final GroupKey key = new DefaultGroupKey(
354 appKryo.serialize(nextObjective
355 .id()));
356 GroupDescription groupDescription = new DefaultGroupDescription(
357 deviceId,
358 GroupDescription.Type.ALL,
359 new GroupBuckets(buckets),
360 key,
361 null,
362 nextObjective.appId());
Saurav Das8a0732e2015-11-20 15:27:53 -0800363 log.debug("Creating BROADCAST group for next objective id {} "
364 + "in device {}", nextObjective.id(), deviceId);
Charles Chanc42e84e2015-10-20 16:24:19 -0700365 pendingGroups.put(key, nextObjective);
Saurav Das8a0732e2015-11-20 15:27:53 -0800366 groupService.addGroup(groupDescription);
Charles Chanc42e84e2015-10-20 16:24:19 -0700367 }
368 break;
sangho834e4b02015-05-01 09:38:25 -0700369 case FAILOVER:
Charles Chanc42e84e2015-10-20 16:24:19 -0700370 log.debug("FAILOVER next objectives not supported");
sangho834e4b02015-05-01 09:38:25 -0700371 fail(nextObjective, ObjectiveError.UNSUPPORTED);
372 log.warn("Unsupported next objective type {}", nextObjective.type());
373 break;
374 default:
375 fail(nextObjective, ObjectiveError.UNKNOWN);
376 log.warn("Unknown next objective type {}", nextObjective.type());
377 }
378 }
379
380 private void addBucketToGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700381 log.debug("addBucketToGroup in {}: for next objective id {}",
382 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700383 Collection<TrafficTreatment> treatments = nextObjective.next();
384 TrafficTreatment treatment = treatments.iterator().next();
385 final GroupKey key = new DefaultGroupKey(
386 appKryo.serialize(nextObjective
387 .id()));
388 Group group = groupService.getGroup(deviceId, key);
389 if (group == null) {
390 log.warn("Group is not found in {} for {}", deviceId, key);
391 return;
392 }
393 GroupBucket bucket;
394 if (group.type() == GroupDescription.Type.INDIRECT) {
395 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
396 } else if (group.type() == GroupDescription.Type.SELECT) {
397 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
Charles Chanc42e84e2015-10-20 16:24:19 -0700398 } else if (group.type() == GroupDescription.Type.ALL) {
399 bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
sangho834e4b02015-05-01 09:38:25 -0700400 } else {
401 log.warn("Unsupported Group type {}", group.type());
402 return;
403 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700404 GroupBuckets bucketsToAdd = new GroupBuckets(Collections.singletonList(bucket));
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700405 log.debug("Adding buckets to group id {} of next objective id {} in device {}",
406 group.id(), nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700407 groupService.addBucketsToGroup(deviceId, key, bucketsToAdd, key, appId);
408 }
409
410 private void removeBucketFromGroup(NextObjective nextObjective) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700411 log.debug("removeBucketFromGroup in {}: for next objective id {}",
412 deviceId, nextObjective.id());
sangho834e4b02015-05-01 09:38:25 -0700413 NextGroup nextGroup = flowObjectiveStore.getNextGroup(nextObjective.id());
414 if (nextGroup != null) {
415 Collection<TrafficTreatment> treatments = nextObjective.next();
416 TrafficTreatment treatment = treatments.iterator().next();
417 final GroupKey key = new DefaultGroupKey(
418 appKryo.serialize(nextObjective
419 .id()));
420 Group group = groupService.getGroup(deviceId, key);
421 if (group == null) {
422 log.warn("Group is not found in {} for {}", deviceId, key);
423 return;
424 }
425 GroupBucket bucket;
426 if (group.type() == GroupDescription.Type.INDIRECT) {
427 bucket = DefaultGroupBucket.createIndirectGroupBucket(treatment);
428 } else if (group.type() == GroupDescription.Type.SELECT) {
429 bucket = DefaultGroupBucket.createSelectGroupBucket(treatment);
Charles Chanc42e84e2015-10-20 16:24:19 -0700430 } else if (group.type() == GroupDescription.Type.ALL) {
431 bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
sangho834e4b02015-05-01 09:38:25 -0700432 } else {
433 log.warn("Unsupported Group type {}", group.type());
434 return;
435 }
Sho SHIMIZU98ffca82015-05-11 08:39:24 -0700436 GroupBuckets removeBuckets = new GroupBuckets(Collections.singletonList(bucket));
Srikanth Vavilapalli5428b6c2015-05-14 20:22:47 -0700437 log.debug("Removing buckets from group id {} of next objective id {} in device {}",
438 group.id(), nextObjective.id(), deviceId);
sangho834e4b02015-05-01 09:38:25 -0700439 groupService.removeBucketsFromGroup(deviceId, key, removeBuckets, key, appId);
440 }
441 }
442
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700443 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
444 switch (fwd.flag()) {
445 case SPECIFIC:
446 return processSpecific(fwd);
447 case VERSATILE:
448 return processVersatile(fwd);
449 default:
450 fail(fwd, ObjectiveError.UNKNOWN);
451 log.warn("Unknown forwarding flag {}", fwd.flag());
452 }
453 return Collections.emptySet();
454 }
455
456 private Collection<FlowRule> processVersatile(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800457 log.debug("Processing versatile forwarding objective in dev:{}", deviceId);
sangho1e575652015-05-14 00:39:53 -0700458 TrafficSelector selector = fwd.selector();
sangho1e575652015-05-14 00:39:53 -0700459 EthTypeCriterion ethType =
460 (EthTypeCriterion) selector.getCriterion(Criterion.Type.ETH_TYPE);
461 if (ethType == null) {
462 log.error("Versatile forwarding objective must include ethType");
463 fail(fwd, ObjectiveError.UNKNOWN);
464 return Collections.emptySet();
465 }
466
Saurav Das8a0732e2015-11-20 15:27:53 -0800467 if (fwd.treatment() == null && fwd.nextId() == null) {
468 log.error("VERSATILE forwarding objective needs next objective ID "
469 + "or treatment.");
470 return Collections.emptySet();
471 }
472 // emulation of ACL table (for versatile fwd objective) requires
473 // overriding any previous instructions
sangho1e575652015-05-14 00:39:53 -0700474 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
475 .builder();
476 treatmentBuilder.wipeDeferred();
477
478 if (fwd.nextId() != null) {
479 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
sangho1e575652015-05-14 00:39:53 -0700480 if (next != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800481 SpringOpenGroup soGroup = appKryo.deserialize(next.data());
482 if (soGroup.dummy) {
483 // need to convert to flow-actions
484 for (Instruction ins : soGroup.treatment.allInstructions()) {
485 treatmentBuilder.add(ins);
486 }
487 } else {
488 GroupKey key = soGroup.key;
489 Group group = groupService.getGroup(deviceId, key);
490 if (group == null) {
491 log.warn("The group left!");
492 fail(fwd, ObjectiveError.GROUPMISSING);
493 return Collections.emptySet();
494 }
495 treatmentBuilder.deferred().group(group.id());
496 log.debug("Adding OUTGROUP action");
sangho1e575652015-05-14 00:39:53 -0700497 }
sangho1e575652015-05-14 00:39:53 -0700498 }
Saurav Das8a0732e2015-11-20 15:27:53 -0800499 }
500
501 if (fwd.treatment() != null) {
Saurav Das822c4e22015-10-23 10:51:11 -0700502 if (fwd.treatment().allInstructions().size() == 1 &&
503 fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
504 OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
505 if (o.port() == PortNumber.CONTROLLER) {
Charles Chan68aa62d2015-11-09 16:37:23 -0800506 treatmentBuilder.punt();
Charles Chan68aa62d2015-11-09 16:37:23 -0800507 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -0800508 treatmentBuilder.add(o);
Saurav Das822c4e22015-10-23 10:51:11 -0700509 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800510 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -0800511 for (Instruction ins : fwd.treatment().allInstructions()) {
512 treatmentBuilder.add(ins);
513 }
Saurav Das822c4e22015-10-23 10:51:11 -0700514 }
sangho1e575652015-05-14 00:39:53 -0700515 }
516
sangho1e575652015-05-14 00:39:53 -0700517 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
518 .fromApp(fwd.appId()).withPriority(fwd.priority())
sanghof9d0bf12015-05-19 11:57:42 -0700519 .forDevice(deviceId).withSelector(fwd.selector())
Saurav Das8a0732e2015-11-20 15:27:53 -0800520 .withTreatment(treatmentBuilder.build());
sangho1e575652015-05-14 00:39:53 -0700521
522 if (fwd.permanent()) {
523 ruleBuilder.makePermanent();
524 } else {
525 ruleBuilder.makeTemporary(fwd.timeout());
526 }
527
528 ruleBuilder.forTable(aclTableId);
529 return Collections.singletonList(ruleBuilder.build());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700530 }
531
Charles Chan68aa62d2015-11-09 16:37:23 -0800532 private boolean isSupportedEthTypeObjective(ForwardingObjective fwd) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700533 TrafficSelector selector = fwd.selector();
534 EthTypeCriterion ethType = (EthTypeCriterion) selector
535 .getCriterion(Criterion.Type.ETH_TYPE);
536 if ((ethType == null) ||
Charles Chan68aa62d2015-11-09 16:37:23 -0800537 ((ethType.ethType().toShort() != Ethernet.TYPE_IPV4) &&
538 (ethType.ethType().toShort() != Ethernet.MPLS_UNICAST))) {
539 return false;
540 }
541 return true;
542 }
543
544 private boolean isSupportedEthDstObjective(ForwardingObjective fwd) {
545 TrafficSelector selector = fwd.selector();
546 EthCriterion ethDst = (EthCriterion) selector
547 .getCriterion(Criterion.Type.ETH_DST);
548 VlanIdCriterion vlanId = (VlanIdCriterion) selector
549 .getCriterion(Criterion.Type.VLAN_VID);
550 if (ethDst == null && vlanId == null) {
551 return false;
552 }
553 return true;
554 }
555
556 protected Collection<FlowRule> processSpecific(ForwardingObjective fwd) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800557 log.debug("Processing specific fwd objective:{} in dev:{} with next:{}",
558 fwd.id(), deviceId, fwd.nextId());
Charles Chan68aa62d2015-11-09 16:37:23 -0800559 boolean isEthTypeObj = isSupportedEthTypeObjective(fwd);
560 boolean isEthDstObj = isSupportedEthDstObjective(fwd);
561
562 if (isEthTypeObj) {
563 return processEthTypeSpecificObjective(fwd);
564 } else if (isEthDstObj) {
565 return processEthDstSpecificObjective(fwd);
566 } else {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700567 log.warn("processSpecific: Unsupported "
Saurav Das8a0732e2015-11-20 15:27:53 -0800568 + "forwarding objective criteria");
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700569 fail(fwd, ObjectiveError.UNSUPPORTED);
570 return Collections.emptySet();
571 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800572 }
573
574 protected Collection<FlowRule>
575 processEthTypeSpecificObjective(ForwardingObjective fwd) {
576 TrafficSelector selector = fwd.selector();
577 EthTypeCriterion ethType = (EthTypeCriterion) selector
578 .getCriterion(Criterion.Type.ETH_TYPE);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700579
580 TrafficSelector.Builder filteredSelectorBuilder =
581 DefaultTrafficSelector.builder();
582 int forTableId = -1;
alshabibcaf1ca22015-06-25 15:18:16 -0700583 if (ethType.ethType().toShort() == Ethernet.TYPE_IPV4) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700584 filteredSelectorBuilder = filteredSelectorBuilder
585 .matchEthType(Ethernet.TYPE_IPV4)
586 .matchIPDst(((IPCriterion) selector
587 .getCriterion(Criterion.Type.IPV4_DST))
588 .ip());
589 forTableId = ipv4UnicastTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800590 log.debug("processing IPv4 specific forwarding objective:{} in dev:{}",
591 fwd.id(), deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700592 } else {
593 filteredSelectorBuilder = filteredSelectorBuilder
594 .matchEthType(Ethernet.MPLS_UNICAST)
595 .matchMplsLabel(((MplsCriterion)
596 selector.getCriterion(Criterion.Type.MPLS_LABEL)).label());
Charles Chan188ebf52015-12-23 00:15:11 -0800597 if (selector.getCriterion(Criterion.Type.MPLS_BOS) != null) {
598 filteredSelectorBuilder.matchMplsBos(((MplsBosCriterion)
599 selector.getCriterion(Type.MPLS_BOS)).mplsBos());
600 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700601 forTableId = mplsTableId;
Saurav Das8a0732e2015-11-20 15:27:53 -0800602 log.debug("processing MPLS specific forwarding objective:{} in dev:{}",
603 fwd.id(), deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700604 }
605
606 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment
607 .builder();
608 if (fwd.treatment() != null) {
609 for (Instruction i : fwd.treatment().allInstructions()) {
610 treatmentBuilder.add(i);
611 }
612 }
613
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700614 if (fwd.nextId() != null) {
615 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700616 if (next != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800617 SpringOpenGroup soGroup = appKryo.deserialize(next.data());
618 if (soGroup.dummy) {
Saurav Das4ce45962015-11-24 23:21:05 -0800619 log.debug("Adding {} flow-actions for fwd. obj. {} -> next:{} "
620 + "in dev: {}", soGroup.treatment.allInstructions().size(),
621 fwd.id(), fwd.nextId(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800622 for (Instruction ins : soGroup.treatment.allInstructions()) {
623 treatmentBuilder.add(ins);
624 }
625 } else {
626 GroupKey key = soGroup.key;
627 Group group = groupService.getGroup(deviceId, key);
628 if (group == null) {
629 log.warn("The group left!");
630 fail(fwd, ObjectiveError.GROUPMISSING);
631 return Collections.emptySet();
632 }
633 treatmentBuilder.deferred().group(group.id());
634 log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} "
Saurav Das4ce45962015-11-24 23:21:05 -0800635 + "for next:{} in dev: {}", group.id(), fwd.id(),
636 fwd.nextId(), deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700637 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700638 } else {
639 log.warn("processSpecific: No associated next objective object");
640 fail(fwd, ObjectiveError.GROUPMISSING);
641 return Collections.emptySet();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700642 }
643 }
644
645 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
646 TrafficTreatment treatment = treatmentBuilder.transition(aclTableId)
647 .build();
648
649 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
650 .fromApp(fwd.appId()).withPriority(fwd.priority())
651 .forDevice(deviceId).withSelector(filteredSelector)
652 .withTreatment(treatment);
653
654 if (fwd.permanent()) {
655 ruleBuilder.makePermanent();
656 } else {
657 ruleBuilder.makeTemporary(fwd.timeout());
658 }
659
660 ruleBuilder.forTable(forTableId);
661 return Collections.singletonList(ruleBuilder.build());
662
663 }
664
Charles Chan68aa62d2015-11-09 16:37:23 -0800665 protected Collection<FlowRule>
666 processEthDstSpecificObjective(ForwardingObjective fwd) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700667 List<FlowRule> rules = new ArrayList<>();
Charles Chan68aa62d2015-11-09 16:37:23 -0800668
669 // Build filtered selector
670 TrafficSelector selector = fwd.selector();
671 EthCriterion ethCriterion = (EthCriterion) selector
672 .getCriterion(Criterion.Type.ETH_DST);
673 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) selector
674 .getCriterion(Criterion.Type.VLAN_VID);
675 TrafficSelector.Builder filteredSelectorBuilder =
676 DefaultTrafficSelector.builder();
677 // Do not match MacAddress for subnet broadcast entry
678 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
679 filteredSelectorBuilder.matchEthDst(ethCriterion.mac());
Saurav Das8a0732e2015-11-20 15:27:53 -0800680 log.debug("processing L2 forwarding objective:{} in dev:{}",
681 fwd.id(), deviceId);
682 } else {
683 log.debug("processing L2 Broadcast forwarding objective:{} "
684 + "in dev:{} for vlan:{}",
685 fwd.id(), deviceId, vlanIdCriterion.vlanId());
Charles Chan68aa62d2015-11-09 16:37:23 -0800686 }
687 filteredSelectorBuilder.matchVlanId(vlanIdCriterion.vlanId());
688 TrafficSelector filteredSelector = filteredSelectorBuilder.build();
689
690 // Build filtered treatment
691 TrafficTreatment.Builder treatmentBuilder =
692 DefaultTrafficTreatment.builder();
693 if (fwd.treatment() != null) {
694 treatmentBuilder.deferred();
695 fwd.treatment().allInstructions().forEach(treatmentBuilder::add);
696 }
697 if (fwd.nextId() != null) {
698 NextGroup next = flowObjectiveStore.getNextGroup(fwd.nextId());
699 if (next != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -0800700 SpringOpenGroup soGrp = appKryo.deserialize(next.data());
701 if (soGrp.dummy) {
Saurav Das4ce45962015-11-24 23:21:05 -0800702 log.debug("Adding {} flow-actions for fwd. obj. {} "
703 + "in dev: {}", soGrp.treatment.allInstructions().size(),
704 fwd.id(), deviceId);
Saurav Das8a0732e2015-11-20 15:27:53 -0800705 for (Instruction ins : soGrp.treatment.allInstructions()) {
Saurav Das4ce45962015-11-24 23:21:05 -0800706 treatmentBuilder.deferred().add(ins);
Saurav Das8a0732e2015-11-20 15:27:53 -0800707 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800708 } else {
Saurav Das8a0732e2015-11-20 15:27:53 -0800709 GroupKey key = soGrp.key;
710 Group group = groupService.getGroup(deviceId, key);
711 if (group == null) {
712 log.warn("The group left!");
713 fail(fwd, ObjectiveError.GROUPMISSING);
714 return Collections.emptySet();
715 }
716 treatmentBuilder.deferred().group(group.id());
717 log.debug("Adding OUTGROUP action to group:{} for fwd. obj. {} "
718 + "in dev: {}", group.id(), fwd.id(), deviceId);
Charles Chan68aa62d2015-11-09 16:37:23 -0800719 }
720 }
721 }
722 treatmentBuilder.immediate().transition(aclTableId);
723 TrafficTreatment filteredTreatment = treatmentBuilder.build();
724
725 // Build bridging table entries
726 FlowRule.Builder flowRuleBuilder = DefaultFlowRule.builder();
727 flowRuleBuilder.fromApp(fwd.appId())
728 .withPriority(fwd.priority())
729 .forDevice(deviceId)
730 .withSelector(filteredSelector)
731 .withTreatment(filteredTreatment)
732 .forTable(dstMacTableId);
733 if (fwd.permanent()) {
734 flowRuleBuilder.makePermanent();
735 } else {
736 flowRuleBuilder.makeTemporary(fwd.timeout());
737 }
738 rules.add(flowRuleBuilder.build());
739
740 /*
741 // TODO Emulate source MAC table behavior
742 // Do not install source MAC table entry for subnet broadcast
743 if (!ethCriterion.mac().equals(MacAddress.NONE)) {
744 // Build filtered selector
745 selector = fwd.selector();
746 ethCriterion = (EthCriterion) selector.getCriterion(Criterion.Type.ETH_DST);
747 filteredSelectorBuilder = DefaultTrafficSelector.builder();
748 filteredSelectorBuilder.matchEthSrc(ethCriterion.mac());
749 filteredSelector = filteredSelectorBuilder.build();
750
751 // Build empty treatment. Apply existing instruction if match.
752 treatmentBuilder = DefaultTrafficTreatment.builder();
753 filteredTreatment = treatmentBuilder.build();
754
755 // Build bridging table entries
756 flowRuleBuilder = DefaultFlowRule.builder();
757 flowRuleBuilder.fromApp(fwd.appId())
758 .withPriority(fwd.priority())
759 .forDevice(deviceId)
760 .withSelector(filteredSelector)
761 .withTreatment(filteredTreatment)
762 .forTable(srcMacTableId)
763 .makePermanent();
764 rules.add(flowRuleBuilder.build());
765 }
766 */
767
768 return rules;
769 }
770
Saurav Das4ce45962015-11-24 23:21:05 -0800771 /*
772 * Note: CpqD switches do not handle MPLS-related operation properly
773 * for a packet with VLAN tag. We pop VLAN here as a workaround.
774 * Side effect: HostService learns redundant hosts with same MAC but
775 * different VLAN. No known side effect on the network reachability.
776 */
Charles Chan68aa62d2015-11-09 16:37:23 -0800777 protected List<FlowRule> processEthDstFilter(EthCriterion ethCriterion,
778 VlanIdCriterion vlanIdCriterion,
779 FilteringObjective filt,
780 VlanId assignedVlan,
781 ApplicationId applicationId) {
782 //handling untagged packets via assigned VLAN
783 if (vlanIdCriterion.vlanId() == VlanId.NONE) {
784 vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
785 }
786
Charles Chan68aa62d2015-11-09 16:37:23 -0800787 List<FlowRule> rules = new ArrayList<>();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700788 TrafficSelector.Builder selectorIp = DefaultTrafficSelector
789 .builder();
790 TrafficTreatment.Builder treatmentIp = DefaultTrafficTreatment
791 .builder();
Charles Chan68aa62d2015-11-09 16:37:23 -0800792 selectorIp.matchEthDst(ethCriterion.mac());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700793 selectorIp.matchEthType(Ethernet.TYPE_IPV4);
Charles Chan68aa62d2015-11-09 16:37:23 -0800794 selectorIp.matchVlanId(vlanIdCriterion.vlanId());
795 treatmentIp.popVlan();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700796 treatmentIp.transition(ipv4UnicastTableId);
797 FlowRule ruleIp = DefaultFlowRule.builder().forDevice(deviceId)
798 .withSelector(selectorIp.build())
799 .withTreatment(treatmentIp.build())
800 .withPriority(filt.priority()).fromApp(applicationId)
801 .makePermanent().forTable(tmacTableId).build();
Charles Chan68aa62d2015-11-09 16:37:23 -0800802 log.debug("adding IP ETH rule for MAC: {}", ethCriterion.mac());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700803 rules.add(ruleIp);
804
805 TrafficSelector.Builder selectorMpls = DefaultTrafficSelector
806 .builder();
807 TrafficTreatment.Builder treatmentMpls = DefaultTrafficTreatment
808 .builder();
Charles Chan68aa62d2015-11-09 16:37:23 -0800809 selectorMpls.matchEthDst(ethCriterion.mac());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700810 selectorMpls.matchEthType(Ethernet.MPLS_UNICAST);
Charles Chan68aa62d2015-11-09 16:37:23 -0800811 selectorMpls.matchVlanId(vlanIdCriterion.vlanId());
812 treatmentMpls.popVlan();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700813 treatmentMpls.transition(mplsTableId);
814 FlowRule ruleMpls = DefaultFlowRule.builder()
815 .forDevice(deviceId).withSelector(selectorMpls.build())
816 .withTreatment(treatmentMpls.build())
817 .withPriority(filt.priority()).fromApp(applicationId)
818 .makePermanent().forTable(tmacTableId).build();
Charles Chan68aa62d2015-11-09 16:37:23 -0800819 log.debug("adding MPLS ETH rule for MAC: {}", ethCriterion.mac());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700820 rules.add(ruleMpls);
821
822 return rules;
823 }
824
Charles Chan68aa62d2015-11-09 16:37:23 -0800825 protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700826 FilteringObjective filt,
Charles Chan68aa62d2015-11-09 16:37:23 -0800827 VlanId assignedVlan,
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700828 ApplicationId applicationId) {
Charles Chanc42e84e2015-10-20 16:24:19 -0700829 List<FlowRule> rules = new ArrayList<>();
Charles Chan68aa62d2015-11-09 16:37:23 -0800830 log.debug("adding rule for VLAN: {}", vlanIdCriterion.vlanId());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700831 TrafficSelector.Builder selector = DefaultTrafficSelector
832 .builder();
833 TrafficTreatment.Builder treatment = DefaultTrafficTreatment
834 .builder();
835 PortCriterion p = (PortCriterion) filt.key();
Charles Chan68aa62d2015-11-09 16:37:23 -0800836 if (vlanIdCriterion.vlanId() != VlanId.NONE) {
837 selector.matchVlanId(vlanIdCriterion.vlanId());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700838 selector.matchInPort(p.port());
839 treatment.deferred().popVlan();
Charles Chan68aa62d2015-11-09 16:37:23 -0800840 } else {
841 selector.matchInPort(p.port());
842 treatment.immediate().pushVlan().setVlanId(assignedVlan);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700843 }
844 treatment.transition(tmacTableId);
845 FlowRule rule = DefaultFlowRule.builder().forDevice(deviceId)
846 .withSelector(selector.build())
847 .withTreatment(treatment.build())
848 .withPriority(filt.priority()).fromApp(applicationId)
849 .makePermanent().forTable(vlanTableId).build();
850 rules.add(rule);
851
852 return rules;
853 }
854
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700855 private void processFilter(FilteringObjective filt, boolean install,
856 ApplicationId applicationId) {
857 // This driver only processes filtering criteria defined with switch
858 // ports as the key
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700859 if (filt.key().equals(Criteria.dummy())
860 || filt.key().type() != Criterion.Type.IN_PORT) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700861 log.warn("No key defined in filtering objective from app: {}. Not"
862 + "processing filtering objective", applicationId);
863 fail(filt, ObjectiveError.UNKNOWN);
864 return;
865 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800866
867 EthCriterion ethCriterion = null;
868 VlanIdCriterion vlanIdCriterion = null;
869
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700870 // convert filtering conditions for switch-intfs into flowrules
871 FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
Charles Chan68aa62d2015-11-09 16:37:23 -0800872
873 for (Criterion criterion : filt.conditions()) {
874 if (criterion.type() == Criterion.Type.ETH_DST) {
875 ethCriterion = (EthCriterion) criterion;
876 } else if (criterion.type() == Criterion.Type.VLAN_VID) {
877 vlanIdCriterion = (VlanIdCriterion) criterion;
878 } else if (criterion.type() == Criterion.Type.IPV4_DST) {
Saurav Das822c4e22015-10-23 10:51:11 -0700879 log.debug("driver does not process IP filtering rules as it " +
880 "sends all misses in the IP table to the controller");
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700881 } else {
882 log.warn("Driver does not currently process filtering condition"
Charles Chan68aa62d2015-11-09 16:37:23 -0800883 + " of type: {}", criterion.type());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700884 fail(filt, ObjectiveError.UNSUPPORTED);
885 }
886 }
Charles Chan68aa62d2015-11-09 16:37:23 -0800887
888 VlanId assignedVlan = null;
889 if (vlanIdCriterion != null && vlanIdCriterion.vlanId() == VlanId.NONE) {
890 // Assign a VLAN ID to untagged packets
891 if (filt.meta() == null) {
892 log.error("Missing metadata in filtering objective required "
893 + "for vlan assignment in dev {}", deviceId);
894 fail(filt, ObjectiveError.BADPARAMS);
895 return;
896 }
897 for (Instruction i : filt.meta().allInstructions()) {
898 if (i instanceof ModVlanIdInstruction) {
899 assignedVlan = ((ModVlanIdInstruction) i).vlanId();
900 }
901 }
902 if (assignedVlan == null) {
903 log.error("Driver requires an assigned vlan-id to tag incoming "
904 + "untagged packets. Not processing vlan filters on "
905 + "device {}", deviceId);
906 fail(filt, ObjectiveError.BADPARAMS);
907 return;
908 }
909 }
910
911 if (ethCriterion == null) {
912 log.debug("filtering objective missing dstMac, cannot program TMAC table");
913 } else {
914 for (FlowRule tmacRule : processEthDstFilter(ethCriterion,
915 vlanIdCriterion,
916 filt,
917 assignedVlan,
918 applicationId)) {
919 log.debug("adding MAC filtering rules in TMAC table: {} for dev: {}",
920 tmacRule, deviceId);
921 ops = install ? ops.add(tmacRule) : ops.remove(tmacRule);
922 }
923 }
924
925 if (ethCriterion == null || vlanIdCriterion == null) {
926 log.debug("filtering objective missing dstMac or vlan, cannot program"
927 + "Vlan Table");
928 } else {
929 for (FlowRule vlanRule : processVlanIdFilter(vlanIdCriterion,
930 filt,
931 assignedVlan,
932 applicationId)) {
933 log.debug("adding VLAN filtering rule in VLAN table: {} for dev: {}",
934 vlanRule, deviceId);
935 ops = install ? ops.add(vlanRule) : ops.remove(vlanRule);
936 }
937 }
938
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700939 // apply filtering flow rules
940 flowRuleService.apply(ops.build(new FlowRuleOperationsContext() {
941 @Override
942 public void onSuccess(FlowRuleOperations ops) {
943 pass(filt);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700944 log.debug("Provisioned tables in {} with fitering "
Saurav Das8a0732e2015-11-20 15:27:53 -0800945 + "rules", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700946 }
947
948 @Override
949 public void onError(FlowRuleOperations ops) {
950 fail(filt, ObjectiveError.FLOWINSTALLATIONFAILED);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700951 log.warn("Failed to provision tables in {} with "
Saurav Das8a0732e2015-11-20 15:27:53 -0800952 + "fitering rules", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700953 }
954 }));
955 }
956
957 protected void setTableMissEntries() {
958 // set all table-miss-entries
959 populateTableMissEntry(vlanTableId, true, false, false, -1);
Charles Chan68aa62d2015-11-09 16:37:23 -0800960 populateTableMissEntry(tmacTableId, false, false, true, dstMacTableId);
961 populateTableMissEntry(ipv4UnicastTableId, false, true, true, aclTableId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700962 populateTableMissEntry(mplsTableId, false, true, true, aclTableId);
Charles Chan68aa62d2015-11-09 16:37:23 -0800963 populateTableMissEntry(dstMacTableId, false, false, true, aclTableId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700964 populateTableMissEntry(aclTableId, false, false, false, -1);
965 }
966
967 protected void populateTableMissEntry(int tableToAdd,
968 boolean toControllerNow,
969 boolean toControllerWrite,
970 boolean toTable, int tableToSend) {
971 TrafficSelector selector = DefaultTrafficSelector.builder().build();
972 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
973
974 if (toControllerNow) {
975 tBuilder.setOutput(PortNumber.CONTROLLER);
976 }
977
978 if (toControllerWrite) {
979 tBuilder.deferred().setOutput(PortNumber.CONTROLLER);
980 }
981
982 if (toTable) {
983 tBuilder.transition(tableToSend);
984 }
985
986 FlowRule flow = DefaultFlowRule.builder().forDevice(deviceId)
987 .withSelector(selector).withTreatment(tBuilder.build())
988 .withPriority(0).fromApp(appId).makePermanent()
989 .forTable(tableToAdd).build();
990
991 flowRuleService.applyFlowRules(flow);
992 }
993
994 private void pass(Objective obj) {
995 if (obj.context().isPresent()) {
996 obj.context().get().onSuccess(obj);
997 }
998 }
999
1000 protected void fail(Objective obj, ObjectiveError error) {
1001 if (obj.context().isPresent()) {
1002 obj.context().get().onError(obj, error);
1003 }
1004 }
1005
1006 private class InnerGroupListener implements GroupListener {
1007 @Override
1008 public void event(GroupEvent event) {
1009 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001010 log.trace("InnerGroupListener: Group ADDED "
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001011 + "event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001012 GroupKey key = event.subject().appCookie();
1013
1014 NextObjective obj = pendingGroups.getIfPresent(key);
1015 if (obj != null) {
Saurav Das8a0732e2015-11-20 15:27:53 -08001016 log.debug("Group verified: dev:{} gid:{} <<->> nextId:{}",
1017 deviceId, event.subject().id(), obj.id());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001018 flowObjectiveStore
1019 .putNextGroup(obj.id(),
Saurav Das8a0732e2015-11-20 15:27:53 -08001020 new SpringOpenGroup(key, null));
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001021 pass(obj);
1022 pendingGroups.invalidate(key);
1023 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -07001024 } else if (event.type() == GroupEvent.Type.GROUP_ADD_FAILED) {
1025 log.warn("InnerGroupListener: Group ADD "
1026 + "failed event received in device {}", deviceId);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001027 }
1028 }
1029 }
1030
1031 private class GroupChecker implements Runnable {
1032
1033 @Override
1034 public void run() {
1035 Set<GroupKey> keys = pendingGroups
1036 .asMap()
1037 .keySet()
1038 .stream()
1039 .filter(key -> groupService.getGroup(deviceId, key) != null)
1040 .collect(Collectors.toSet());
1041
1042 keys.stream()
1043 .forEach(key -> {
1044 NextObjective obj = pendingGroups
1045 .getIfPresent(key);
1046 if (obj == null) {
1047 return;
1048 }
Saurav Das8a0732e2015-11-20 15:27:53 -08001049 log.debug("Group verified: dev:{} gid:{} <<->> nextId:{}",
1050 deviceId,
1051 groupService.getGroup(deviceId, key).id(),
1052 obj.id());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001053 pass(obj);
1054 pendingGroups.invalidate(key);
Saurav Das8a0732e2015-11-20 15:27:53 -08001055 flowObjectiveStore.putNextGroup(
1056 obj.id(),
1057 new SpringOpenGroup(key, null));
1058 });
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001059 }
1060 }
1061
Saurav Das8a0732e2015-11-20 15:27:53 -08001062 /**
1063 * SpringOpenGroup can either serve as storage for a GroupKey which can be
1064 * used to fetch the group from the Group Service, or it can be serve as storage
1065 * for Traffic Treatments which can be used as flow actions. In the latter
1066 * case, we refer to this as a dummy group.
1067 *
1068 */
1069 private class SpringOpenGroup implements NextGroup {
1070 private final boolean dummy;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001071 private final GroupKey key;
Saurav Das8a0732e2015-11-20 15:27:53 -08001072 private final TrafficTreatment treatment;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001073
Saurav Das8a0732e2015-11-20 15:27:53 -08001074 /**
1075 * Storage for a GroupKey or a TrafficTreatment. One of the params
1076 * to this constructor must be null.
1077 * @param key represents a GroupKey
1078 * @param treatment represents flow actions in a dummy group
1079 */
1080 public SpringOpenGroup(GroupKey key, TrafficTreatment treatment) {
1081 if (key == null) {
1082 this.key = new DefaultGroupKey(new byte[]{0});
1083 this.treatment = treatment;
1084 this.dummy = true;
1085 } else {
1086 this.key = key;
1087 this.treatment = DefaultTrafficTreatment.builder().build();
1088 this.dummy = false;
1089 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001090 }
1091
Saurav Das822c4e22015-10-23 10:51:11 -07001092 @SuppressWarnings("unused")
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001093 public GroupKey key() {
1094 return key;
1095 }
1096
1097 @Override
1098 public byte[] data() {
Saurav Das8a0732e2015-11-20 15:27:53 -08001099 return appKryo.serialize(this);
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -07001100 }
1101
1102 }
1103}