blob: de90b9d85c6244fb3c6f151582fb1c40a9308f77 [file] [log] [blame]
alshabib0ccde6d2015-05-30 18:22:36 -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
alshabibd61b77b2016-02-01 23:30:53 -080018import com.google.common.cache.Cache;
19import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.RemovalCause;
21import com.google.common.cache.RemovalNotification;
alshabibfd430b62015-12-16 18:56:38 -080022import com.google.common.collect.Lists;
23import org.apache.commons.lang3.tuple.ImmutablePair;
24import org.apache.commons.lang3.tuple.Pair;
alshabib0ccde6d2015-05-30 18:22:36 -070025import org.onlab.osgi.ServiceDirectory;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070026import org.onlab.packet.EthType;
alshabibfd430b62015-12-16 18:56:38 -080027import org.onlab.packet.IPv4;
28import org.onlab.packet.VlanId;
alshabibd61b77b2016-02-01 23:30:53 -080029import org.onlab.util.KryoNamespace;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070030import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
alshabib0ccde6d2015-05-30 18:22:36 -070032import org.onosproject.net.DeviceId;
33import org.onosproject.net.PortNumber;
alshabibd61b77b2016-02-01 23:30:53 -080034import org.onosproject.net.behaviour.NextGroup;
alshabib0ccde6d2015-05-30 18:22:36 -070035import org.onosproject.net.behaviour.Pipeliner;
36import org.onosproject.net.behaviour.PipelinerContext;
37import org.onosproject.net.driver.AbstractHandlerBehaviour;
38import org.onosproject.net.flow.DefaultFlowRule;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070039import org.onosproject.net.flow.DefaultTrafficSelector;
alshabib0ccde6d2015-05-30 18:22:36 -070040import 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;
alshabibfd430b62015-12-16 18:56:38 -080047import org.onosproject.net.flow.criteria.Criteria;
48import org.onosproject.net.flow.criteria.Criterion;
49import org.onosproject.net.flow.criteria.EthTypeCriterion;
50import org.onosproject.net.flow.criteria.IPProtocolCriterion;
51import org.onosproject.net.flow.criteria.PortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080052import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080053import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070054import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080055import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070056import org.onosproject.net.flowobjective.FilteringObjective;
alshabibd61b77b2016-02-01 23:30:53 -080057import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabib0ccde6d2015-05-30 18:22:36 -070058import org.onosproject.net.flowobjective.ForwardingObjective;
59import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080060import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070061import org.onosproject.net.flowobjective.ObjectiveError;
alshabibd61b77b2016-02-01 23:30:53 -080062import 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.onosproject.store.serializers.KryoNamespaces;
alshabib0ccde6d2015-05-30 18:22:36 -070074import org.slf4j.Logger;
75
alshabibfd430b62015-12-16 18:56:38 -080076import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080077import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080078import java.util.List;
79import java.util.Optional;
alshabibd61b77b2016-02-01 23:30:53 -080080import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080081import java.util.stream.Collectors;
82
alshabib0ccde6d2015-05-30 18:22:36 -070083import static org.slf4j.LoggerFactory.getLogger;
84
85/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070086 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070087 */
alshabibfd430b62015-12-16 18:56:38 -080088
Jonathan Hartb92cc512015-11-16 23:05:21 -080089public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070090
alshabibfd430b62015-12-16 18:56:38 -080091 private static final Integer QQ_TABLE = 1;
alshabibd61b77b2016-02-01 23:30:53 -080092 private static final short MCAST_VLAN = 4000;
alshabib0ccde6d2015-05-30 18:22:36 -070093 private final Logger log = getLogger(getClass());
94
95 private ServiceDirectory serviceDirectory;
96 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -080097 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070098 private CoreService coreService;
99
alshabibd61b77b2016-02-01 23:30:53 -0800100 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700101 private ApplicationId appId;
alshabib0ccde6d2015-05-30 18:22:36 -0700102
alshabibd61b77b2016-02-01 23:30:53 -0800103 protected FlowObjectiveStore flowObjectiveStore;
104
105 private Cache<GroupKey, NextObjective> pendingGroups;
106
107 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
108 .register(KryoNamespaces.API)
109 .register(GroupKey.class)
110 .register(DefaultGroupKey.class)
111 .register(OLTPipelineGroup.class)
112 .register(byte[].class)
113 .build();
alshabib2cc73cb2015-06-30 20:26:56 -0700114
alshabib0ccde6d2015-05-30 18:22:36 -0700115 @Override
116 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800117 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700118 this.serviceDirectory = context.directory();
119 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800120
alshabib0ccde6d2015-05-30 18:22:36 -0700121 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700122 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800123 groupService = serviceDirectory.get(GroupService.class);
124 flowObjectiveStore = context.store();
125
alshabibb32cefe2015-06-08 18:15:05 -0700126
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700127 appId = coreService.registerApplication(
128 "org.onosproject.driver.OLTPipeline");
129
alshabibd61b77b2016-02-01 23:30:53 -0800130
131 pendingGroups = CacheBuilder.newBuilder()
132 .expireAfterWrite(20, TimeUnit.SECONDS)
133 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
134 if (notification.getCause() == RemovalCause.EXPIRED) {
135 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
136 }
137 }).build();
138
139 groupService.addListener(new InnerGroupListener());
140
alshabibb32cefe2015-06-08 18:15:05 -0700141 }
142
alshabib0ccde6d2015-05-30 18:22:36 -0700143 @Override
144 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800145 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700146
alshabibfd430b62015-12-16 18:56:38 -0800147 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
148 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
149 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
150 .limit(1)
151 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700152
alshabibbb424232016-01-15 12:20:25 -0800153 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
154 log.error("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800155 fail(filter, ObjectiveError.UNSUPPORTED);
156 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700157 }
alshabibfd430b62015-12-16 18:56:38 -0800158 } else {
159 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700160 return;
161 }
162
alshabibfd430b62015-12-16 18:56:38 -0800163 if (filter.key().type() != Criterion.Type.IN_PORT) {
164 fail(filter, ObjectiveError.BADPARAMS);
165 return;
166 }
167
168 EthTypeCriterion ethType = (EthTypeCriterion)
169 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
170
171 if (ethType == null) {
172 fail(filter, ObjectiveError.BADPARAMS);
173 return;
174 }
175
alshabibbb424232016-01-15 12:20:25 -0800176 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800177 provisionEapol(filter, ethType, output);
alshabibbb424232016-01-15 12:20:25 -0800178 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800179 IPProtocolCriterion ipProto = (IPProtocolCriterion)
180 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
181 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700182 provisionIgmp(filter, ethType, ipProto, output);
alshabibbb424232016-01-15 12:20:25 -0800183 } else {
184 log.error("OLT can only filter igmp");
185 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800186 }
187 } else {
alshabibbb424232016-01-15 12:20:25 -0800188 log.error("OLT can only filter eapol and igmp");
alshabibfd430b62015-12-16 18:56:38 -0800189 fail(filter, ObjectiveError.UNSUPPORTED);
190 }
191
192 }
193
194
195 @Override
196 public void forward(ForwardingObjective fwd) {
alshabibd61b77b2016-02-01 23:30:53 -0800197
198 if (checkForMulticast(fwd)) {
199 processMulticastRule(fwd);
200 return;
201 }
202
alshabib0ccde6d2015-05-30 18:22:36 -0700203 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700204
alshabibfd430b62015-12-16 18:56:38 -0800205 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700206
alshabibfd430b62015-12-16 18:56:38 -0800207 Optional<Instruction> vlanIntruction = instructions.stream()
208 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
209 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
210 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
211 ((L2ModificationInstruction) i).subtype() ==
212 L2ModificationInstruction.L2SubType.VLAN_POP)
213 .findAny();
214
215 if (!vlanIntruction.isPresent()) {
216 fail(fwd, ObjectiveError.BADPARAMS);
217 return;
218 }
219
220 L2ModificationInstruction vlanIns =
221 (L2ModificationInstruction) vlanIntruction.get();
222
223 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
224 installUpstreamRules(fwd);
225 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
226 installDownstreamRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700227 } else {
alshabibfd430b62015-12-16 18:56:38 -0800228 log.error("Unknown OLT operation: {}", fwd);
229 fail(fwd, ObjectiveError.UNSUPPORTED);
230 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700231 }
232
alshabibfd430b62015-12-16 18:56:38 -0800233 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700234
alshabib0ccde6d2015-05-30 18:22:36 -0700235 }
236
alshabibd61b77b2016-02-01 23:30:53 -0800237
alshabib0ccde6d2015-05-30 18:22:36 -0700238 @Override
239 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800240 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
241 log.error("OLT only supports broadcast groups.");
242 fail(nextObjective, ObjectiveError.BADPARAMS);
243 }
244
245 if (nextObjective.next().size() != 1) {
246 log.error("OLT only supports singleton broadcast groups.");
247 fail(nextObjective, ObjectiveError.BADPARAMS);
248 }
249
250 TrafficTreatment treatment = nextObjective.next().stream().findFirst().get();
251
252
253 GroupBucket bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
254 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
255
256 GroupDescription groupDesc =
257 new DefaultGroupDescription(deviceId,
258 GroupDescription.Type.ALL,
259 new GroupBuckets(Collections.singletonList(bucket)),
260 key,
261 null,
262 nextObjective.appId());
263
264 pendingGroups.put(key, nextObjective);
265
266 switch (nextObjective.op()) {
267 case ADD:
268 groupService.addGroup(groupDesc);
269 break;
270 case REMOVE:
271 groupService.removeGroup(deviceId, key, nextObjective.appId());
272 break;
273 case ADD_TO_EXISTING:
274 case REMOVE_FROM_EXISTING:
275 //TODO: handle addition to group when caller signals it.
276 break;
277 default:
278 log.warn("Unknown next objective operation: {}", nextObjective.op());
279 }
280
281
282 }
283
284 private void processMulticastRule(ForwardingObjective fwd) {
285 if (fwd.nextId() == null) {
286 log.error("Multicast objective does not have a next id");
287 fail(fwd, ObjectiveError.BADPARAMS);
288 }
289
290 OLTPipelineGroup next = getGroupForNextObjective(fwd.nextId());
291
292 if (next == null) {
293 log.error("Group for forwarding objective missing: {}", fwd);
294 fail(fwd, ObjectiveError.GROUPMISSING);
295 }
296
297 Group group = groupService.getGroup(deviceId, next.key());
298 TrafficTreatment treatment =
299 buildTreatment(Instructions.createGroup(group.id()));
300
301 FlowRule rule = DefaultFlowRule.builder()
302 .forDevice(deviceId)
303 .forTable(0)
304 .fromApp(fwd.appId())
305 .makePermanent()
306 .withPriority(fwd.priority())
307 .withSelector(fwd.selector())
308 .withTreatment(treatment)
309 .build();
310
311 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
312 switch (fwd.op()) {
313
314 case ADD:
315 builder.add(rule);
316 break;
317 case REMOVE:
318 builder.remove(rule);
319 break;
320 case ADD_TO_EXISTING:
321 case REMOVE_FROM_EXISTING:
322 break;
323 default:
324 log.warn("Unknown forwarding operation: {}", fwd.op());
325 }
326
327 applyFlowRules(builder, fwd);
328
329 }
330
331 private boolean checkForMulticast(ForwardingObjective fwd) {
332
333 VlanIdCriterion vlan = (VlanIdCriterion) filterForCriterion(fwd.selector().criteria(),
334 Criterion.Type.VLAN_VID);
335
336 return (vlan != null && vlan.vlanId().equals(VlanId.vlanId(MCAST_VLAN)));
337
338 }
339
340 private OLTPipelineGroup getGroupForNextObjective(Integer nextId) {
341 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
342 return (OLTPipelineGroup) appKryo.deserialize(next.data());
343
alshabib0ccde6d2015-05-30 18:22:36 -0700344 }
345
alshabibfd430b62015-12-16 18:56:38 -0800346 private void installDownstreamRules(ForwardingObjective fwd) {
347 List<Pair<Instruction, Instruction>> vlanOps =
348 vlanOps(fwd,
349 L2ModificationInstruction.L2SubType.VLAN_POP);
350
351 if (vlanOps == null) {
352 return;
353 }
354
355 Instruction output = fetchOutput(fwd, "downstream");
356
357 if (output == null) {
358 return;
359 }
360
361 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
362
alshabibfa0dc662016-01-13 11:23:53 -0800363 TrafficSelector selector = fwd.selector();
364
365 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
366 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
367 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
368
369 if (outerVlan == null || innerVlan == null || inport == null) {
370 log.error("Forwarding objective is underspecified: {}", fwd);
371 fail(fwd, ObjectiveError.BADPARAMS);
372 return;
373 }
374
alshabib2f74f2c2016-01-14 13:29:35 -0800375 Criterion innerVid = Criteria.matchVlanId(((VlanIdCriterion) innerVlan).vlanId());
376
alshabibfa0dc662016-01-13 11:23:53 -0800377 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabibfd430b62015-12-16 18:56:38 -0800378 .forDevice(deviceId)
379 .fromApp(appId)
380 .makePermanent()
381 .withPriority(fwd.priority())
alshabibfa0dc662016-01-13 11:23:53 -0800382 .withSelector(buildSelector(inport, outerVlan))
alshabibfd430b62015-12-16 18:56:38 -0800383 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
384 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800385
alshabibfa0dc662016-01-13 11:23:53 -0800386 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabibfd430b62015-12-16 18:56:38 -0800387 .forDevice(deviceId)
388 .fromApp(appId)
389 .forTable(QQ_TABLE)
390 .makePermanent()
391 .withPriority(fwd.priority())
alshabib2f74f2c2016-01-14 13:29:35 -0800392 .withSelector(buildSelector(inport, innerVid))
alshabibfd430b62015-12-16 18:56:38 -0800393 .withTreatment(buildTreatment(popAndRewrite.getRight(),
394 output));
395
396 applyRules(fwd, inner, outer);
397
398 }
399
400 private void installUpstreamRules(ForwardingObjective fwd) {
401 List<Pair<Instruction, Instruction>> vlanOps =
402 vlanOps(fwd,
403 L2ModificationInstruction.L2SubType.VLAN_PUSH);
404
405 if (vlanOps == null) {
406 return;
407 }
408
409 Instruction output = fetchOutput(fwd, "upstream");
410
411 if (output == null) {
412 return;
413 }
414
415 Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
416
417 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
418
419 FlowRule.Builder inner = DefaultFlowRule.builder()
420 .forDevice(deviceId)
421 .fromApp(appId)
422 .makePermanent()
423 .withPriority(fwd.priority())
424 .withSelector(fwd.selector())
425 .withTreatment(buildTreatment(innerPair.getRight(),
426 Instructions.transition(QQ_TABLE)));
427
428 PortCriterion inPort = (PortCriterion)
429 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
430
431 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
432 innerPair.getRight()).vlanId();
433
434 FlowRule.Builder outer = DefaultFlowRule.builder()
435 .forDevice(deviceId)
436 .fromApp(appId)
437 .forTable(QQ_TABLE)
438 .makePermanent()
439 .withPriority(fwd.priority())
440 .withSelector(buildSelector(inPort,
441 Criteria.matchVlanId(cVlanId)))
442 .withTreatment(buildTreatment(outerPair.getLeft(),
443 outerPair.getRight(),
444 output));
445
446 applyRules(fwd, inner, outer);
447
448 }
449
450 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
451 Instruction output = fwd.treatment().allInstructions().stream()
452 .filter(i -> i.type() == Instruction.Type.OUTPUT)
453 .findFirst().orElse(null);
454
455 if (output == null) {
456 log.error("OLT {} rule has no output", direction);
457 fail(fwd, ObjectiveError.BADPARAMS);
458 return null;
459 }
460 return output;
461 }
462
463 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
464 L2ModificationInstruction.L2SubType type) {
465
466 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
467 fwd.treatment().allInstructions(), type);
468
469 if (vlanOps == null) {
470 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
471 ? "downstream" : "upstream";
472 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
473 fail(fwd, ObjectiveError.BADPARAMS);
474 return null;
475 }
476 return vlanOps;
477 }
478
479
480 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800481 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800482
483 List<Instruction> vlanPushs = findL2Instructions(
484 type,
485 instructions);
486 List<Instruction> vlanSets = findL2Instructions(
487 L2ModificationInstruction.L2SubType.VLAN_ID,
488 instructions);
489
490 if (vlanPushs.size() != vlanSets.size()) {
491 return null;
492 }
493
494 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
495
496 for (int i = 0; i < vlanPushs.size(); i++) {
497 pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
498 }
499 return pairs;
500 }
501
502 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
503 List<Instruction> actions) {
504 return actions.stream()
505 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
506 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
507 .collect(Collectors.toList());
508 }
509
510 private void provisionEapol(FilteringObjective filter,
511 EthTypeCriterion ethType,
512 Instructions.OutputInstruction output) {
513
514 TrafficSelector selector = buildSelector(filter.key(), ethType);
515 TrafficTreatment treatment = buildTreatment(output);
516 buildAndApplyRule(filter, selector, treatment);
517
518 }
519
Jonathan Hart51539b82015-10-29 09:53:04 -0700520 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800521 IPProtocolCriterion ipProto,
522 Instructions.OutputInstruction output) {
523 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
524 TrafficTreatment treatment = buildTreatment(output);
525 buildAndApplyRule(filter, selector, treatment);
526 }
527
528 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
529 TrafficTreatment treatment) {
530 FlowRule rule = DefaultFlowRule.builder()
531 .forDevice(deviceId)
532 .forTable(0)
533 .fromApp(filter.appId())
534 .makePermanent()
535 .withSelector(selector)
536 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800537 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800538 .build();
539
540 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
541
542 switch (filter.type()) {
543 case PERMIT:
544 opsBuilder.add(rule);
545 break;
546 case DENY:
547 opsBuilder.remove(rule);
548 break;
549 default:
550 log.warn("Unknown filter type : {}", filter.type());
551 fail(filter, ObjectiveError.UNSUPPORTED);
552 }
553
554 applyFlowRules(opsBuilder, filter);
555 }
556
557 private void applyRules(ForwardingObjective fwd,
558 FlowRule.Builder inner, FlowRule.Builder outer) {
559 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
560 switch (fwd.op()) {
561 case ADD:
562 builder.add(inner.build()).add(outer.build());
563 break;
564 case REMOVE:
565 builder.remove(inner.build()).remove(outer.build());
566 break;
567 case ADD_TO_EXISTING:
568 break;
569 case REMOVE_FROM_EXISTING:
570 break;
571 default:
572 log.warn("Unknown forwarding operation: {}", fwd.op());
573 }
574
575 applyFlowRules(builder, fwd);
576 }
577
578 private void applyFlowRules(FlowRuleOperations.Builder builder,
579 Objective objective) {
580 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
581 @Override
582 public void onSuccess(FlowRuleOperations ops) {
583 pass(objective);
584 }
585
586 @Override
587 public void onError(FlowRuleOperations ops) {
588 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
589 }
590 }));
591 }
592
593 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
594 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800595 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800596 .limit(1)
597 .findFirst().orElse(null);
598 }
599
600 private TrafficSelector buildSelector(Criterion... criteria) {
601
602
603 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
604
605 for (Criterion c : criteria) {
606 sBuilder.add(c);
607 }
608
609 return sBuilder.build();
610 }
611
612 private TrafficTreatment buildTreatment(Instruction... instructions) {
613
614
615 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
616
617 for (Instruction i : instructions) {
618 tBuilder.add(i);
619 }
620
621 return tBuilder.build();
622 }
623
624
625 private void fail(Objective obj, ObjectiveError error) {
626 if (obj.context().isPresent()) {
627 obj.context().get().onError(obj, error);
628 }
629 }
630
631 private void pass(Objective obj) {
632 if (obj.context().isPresent()) {
633 obj.context().get().onSuccess(obj);
634 }
635 }
636
alshabib2cc73cb2015-06-30 20:26:56 -0700637
alshabibd61b77b2016-02-01 23:30:53 -0800638 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -0700639 @Override
alshabibd61b77b2016-02-01 23:30:53 -0800640 public void event(GroupEvent event) {
641 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
642 GroupKey key = event.subject().appCookie();
alshabib2cc73cb2015-06-30 20:26:56 -0700643
alshabibd61b77b2016-02-01 23:30:53 -0800644 NextObjective obj = pendingGroups.getIfPresent(key);
645 if (obj != null) {
646 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
647 pass(obj);
648 pendingGroups.invalidate(key);
649 }
650 }
alshabib2cc73cb2015-06-30 20:26:56 -0700651 }
652 }
653
alshabibd61b77b2016-02-01 23:30:53 -0800654 private static class OLTPipelineGroup implements NextGroup {
655
656 private final GroupKey key;
657
658 public OLTPipelineGroup(GroupKey key) {
659 this.key = key;
660 }
661
662 public GroupKey key() {
663 return key;
664 }
665
666 @Override
667 public byte[] data() {
668 return appKryo.serialize(key);
669 }
670
671 }
alshabib0ccde6d2015-05-30 18:22:36 -0700672}