blob: 0d78def88ff0d7a67136ee9f601af6ce0fad6c7d [file] [log] [blame]
alshabib0ccde6d2015-05-30 18:22:36 -07001/*
Charles Chanaedabfd2016-02-26 09:31:48 -08002 * Copyright 2015-2016 Open Networking Laboratory
alshabib0ccde6d2015-05-30 18:22:36 -07003 *
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;
alshabib6cb86362016-03-03 18:00:58 -080041import org.onosproject.net.flow.FlowEntry;
alshabib0ccde6d2015-05-30 18:22:36 -070042import 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;
alshabibfd430b62015-12-16 18:56:38 -080048import org.onosproject.net.flow.criteria.Criteria;
49import org.onosproject.net.flow.criteria.Criterion;
50import org.onosproject.net.flow.criteria.EthTypeCriterion;
alshabib1aa58142016-02-17 15:37:56 -080051import org.onosproject.net.flow.criteria.IPCriterion;
alshabibfd430b62015-12-16 18:56:38 -080052import org.onosproject.net.flow.criteria.IPProtocolCriterion;
53import org.onosproject.net.flow.criteria.PortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080054import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080055import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070056import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080057import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070058import org.onosproject.net.flowobjective.FilteringObjective;
alshabibd61b77b2016-02-01 23:30:53 -080059import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabib0ccde6d2015-05-30 18:22:36 -070060import org.onosproject.net.flowobjective.ForwardingObjective;
61import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080062import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070063import org.onosproject.net.flowobjective.ObjectiveError;
alshabibd61b77b2016-02-01 23:30:53 -080064import org.onosproject.net.group.DefaultGroupBucket;
65import org.onosproject.net.group.DefaultGroupDescription;
66import org.onosproject.net.group.DefaultGroupKey;
67import org.onosproject.net.group.Group;
68import org.onosproject.net.group.GroupBucket;
69import org.onosproject.net.group.GroupBuckets;
70import org.onosproject.net.group.GroupDescription;
71import org.onosproject.net.group.GroupEvent;
72import org.onosproject.net.group.GroupKey;
73import org.onosproject.net.group.GroupListener;
74import org.onosproject.net.group.GroupService;
75import org.onosproject.store.serializers.KryoNamespaces;
alshabib5ccbe3f2016-03-02 22:36:02 -080076import org.onosproject.store.service.AtomicCounter;
77import org.onosproject.store.service.StorageService;
alshabib0ccde6d2015-05-30 18:22:36 -070078import org.slf4j.Logger;
79
alshabibfd430b62015-12-16 18:56:38 -080080import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080081import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080082import java.util.List;
83import java.util.Optional;
alshabibd61b77b2016-02-01 23:30:53 -080084import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080085import java.util.stream.Collectors;
86
alshabib0ccde6d2015-05-30 18:22:36 -070087import static org.slf4j.LoggerFactory.getLogger;
88
89/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070090 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070091 */
alshabibfd430b62015-12-16 18:56:38 -080092
Jonathan Hartb92cc512015-11-16 23:05:21 -080093public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070094
alshabibfd430b62015-12-16 18:56:38 -080095 private static final Integer QQ_TABLE = 1;
alshabibd61b77b2016-02-01 23:30:53 -080096 private static final short MCAST_VLAN = 4000;
alshabib5ccbe3f2016-03-02 22:36:02 -080097 private static final String OLTCOOKIES = "olt-cookies-must-be-unique";
alshabib0ccde6d2015-05-30 18:22:36 -070098 private final Logger log = getLogger(getClass());
99
100 private ServiceDirectory serviceDirectory;
101 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800102 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700103 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800104 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700105
alshabibd61b77b2016-02-01 23:30:53 -0800106 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700107 private ApplicationId appId;
Charles Chanaedabfd2016-02-26 09:31:48 -0800108 // NOTE: OLT currently has some issue with cookie 0. Pick something larger
109 // to avoid collision
alshabib5ccbe3f2016-03-02 22:36:02 -0800110 private AtomicCounter counter;
alshabib0ccde6d2015-05-30 18:22:36 -0700111
alshabibd61b77b2016-02-01 23:30:53 -0800112 protected FlowObjectiveStore flowObjectiveStore;
113
114 private Cache<GroupKey, NextObjective> pendingGroups;
115
116 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
117 .register(KryoNamespaces.API)
118 .register(GroupKey.class)
119 .register(DefaultGroupKey.class)
120 .register(OLTPipelineGroup.class)
121 .register(byte[].class)
122 .build();
alshabib2cc73cb2015-06-30 20:26:56 -0700123
alshabib0ccde6d2015-05-30 18:22:36 -0700124 @Override
125 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800126 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700127 this.serviceDirectory = context.directory();
128 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800129
alshabib0ccde6d2015-05-30 18:22:36 -0700130 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700131 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800132 groupService = serviceDirectory.get(GroupService.class);
133 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800134 storageService = serviceDirectory.get(StorageService.class);
135
136 counter = storageService.atomicCounterBuilder()
137 .withName(String.format(OLTCOOKIES, deviceId))
138 .build()
139 .asAtomicCounter();
140
141 /*
142 magic olt number to make sure we don't collide with it's internal
143 processing
144 */
145 counter.set(123);
alshabibd61b77b2016-02-01 23:30:53 -0800146
alshabibb32cefe2015-06-08 18:15:05 -0700147
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700148 appId = coreService.registerApplication(
149 "org.onosproject.driver.OLTPipeline");
150
alshabibd61b77b2016-02-01 23:30:53 -0800151
152 pendingGroups = CacheBuilder.newBuilder()
153 .expireAfterWrite(20, TimeUnit.SECONDS)
154 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
155 if (notification.getCause() == RemovalCause.EXPIRED) {
156 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
157 }
158 }).build();
159
160 groupService.addListener(new InnerGroupListener());
161
alshabibb32cefe2015-06-08 18:15:05 -0700162 }
163
alshabib0ccde6d2015-05-30 18:22:36 -0700164 @Override
165 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800166 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700167
alshabibfd430b62015-12-16 18:56:38 -0800168 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
169 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
170 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
171 .limit(1)
172 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700173
alshabibbb424232016-01-15 12:20:25 -0800174 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
175 log.error("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800176 fail(filter, ObjectiveError.UNSUPPORTED);
177 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700178 }
alshabibfd430b62015-12-16 18:56:38 -0800179 } else {
180 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700181 return;
182 }
183
alshabibfd430b62015-12-16 18:56:38 -0800184 if (filter.key().type() != Criterion.Type.IN_PORT) {
185 fail(filter, ObjectiveError.BADPARAMS);
186 return;
187 }
188
189 EthTypeCriterion ethType = (EthTypeCriterion)
190 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
191
192 if (ethType == null) {
193 fail(filter, ObjectiveError.BADPARAMS);
194 return;
195 }
196
alshabibbb424232016-01-15 12:20:25 -0800197 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800198 provisionEapol(filter, ethType, output);
alshabibbb424232016-01-15 12:20:25 -0800199 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800200 IPProtocolCriterion ipProto = (IPProtocolCriterion)
201 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
202 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700203 provisionIgmp(filter, ethType, ipProto, output);
alshabibbb424232016-01-15 12:20:25 -0800204 } else {
205 log.error("OLT can only filter igmp");
206 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800207 }
208 } else {
alshabibbb424232016-01-15 12:20:25 -0800209 log.error("OLT can only filter eapol and igmp");
alshabibfd430b62015-12-16 18:56:38 -0800210 fail(filter, ObjectiveError.UNSUPPORTED);
211 }
212
213 }
214
215
216 @Override
217 public void forward(ForwardingObjective fwd) {
alshabibd61b77b2016-02-01 23:30:53 -0800218
219 if (checkForMulticast(fwd)) {
220 processMulticastRule(fwd);
221 return;
222 }
223
alshabib0ccde6d2015-05-30 18:22:36 -0700224 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700225
alshabibfd430b62015-12-16 18:56:38 -0800226 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700227
alshabibfd430b62015-12-16 18:56:38 -0800228 Optional<Instruction> vlanIntruction = instructions.stream()
229 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
230 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
231 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
232 ((L2ModificationInstruction) i).subtype() ==
233 L2ModificationInstruction.L2SubType.VLAN_POP)
234 .findAny();
235
236 if (!vlanIntruction.isPresent()) {
237 fail(fwd, ObjectiveError.BADPARAMS);
238 return;
239 }
240
241 L2ModificationInstruction vlanIns =
242 (L2ModificationInstruction) vlanIntruction.get();
243
244 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
245 installUpstreamRules(fwd);
246 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
247 installDownstreamRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700248 } else {
alshabibfd430b62015-12-16 18:56:38 -0800249 log.error("Unknown OLT operation: {}", fwd);
250 fail(fwd, ObjectiveError.UNSUPPORTED);
251 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700252 }
253
alshabibfd430b62015-12-16 18:56:38 -0800254 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700255
alshabib0ccde6d2015-05-30 18:22:36 -0700256 }
257
alshabibd61b77b2016-02-01 23:30:53 -0800258
alshabib0ccde6d2015-05-30 18:22:36 -0700259 @Override
260 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800261 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
262 log.error("OLT only supports broadcast groups.");
263 fail(nextObjective, ObjectiveError.BADPARAMS);
264 }
265
266 if (nextObjective.next().size() != 1) {
267 log.error("OLT only supports singleton broadcast groups.");
268 fail(nextObjective, ObjectiveError.BADPARAMS);
269 }
270
271 TrafficTreatment treatment = nextObjective.next().stream().findFirst().get();
272
273
274 GroupBucket bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
275 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
276
alshabib1aa58142016-02-17 15:37:56 -0800277
alshabibd61b77b2016-02-01 23:30:53 -0800278 pendingGroups.put(key, nextObjective);
279
280 switch (nextObjective.op()) {
281 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800282 GroupDescription groupDesc =
283 new DefaultGroupDescription(deviceId,
284 GroupDescription.Type.ALL,
285 new GroupBuckets(Collections.singletonList(bucket)),
286 key,
287 null,
288 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800289 groupService.addGroup(groupDesc);
290 break;
291 case REMOVE:
292 groupService.removeGroup(deviceId, key, nextObjective.appId());
293 break;
294 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800295 groupService.addBucketsToGroup(deviceId, key,
296 new GroupBuckets(Collections.singletonList(bucket)),
297 key, nextObjective.appId());
298 break;
alshabibd61b77b2016-02-01 23:30:53 -0800299 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800300 groupService.removeBucketsFromGroup(deviceId, key,
alshabib56efe432016-02-25 17:57:24 -0500301 new GroupBuckets(Collections.singletonList(bucket)),
302 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800303 break;
304 default:
305 log.warn("Unknown next objective operation: {}", nextObjective.op());
306 }
307
308
309 }
310
311 private void processMulticastRule(ForwardingObjective fwd) {
312 if (fwd.nextId() == null) {
313 log.error("Multicast objective does not have a next id");
314 fail(fwd, ObjectiveError.BADPARAMS);
315 }
316
alshabib1aa58142016-02-17 15:37:56 -0800317 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800318
alshabib1aa58142016-02-17 15:37:56 -0800319 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800320 log.error("Group for forwarding objective missing: {}", fwd);
321 fail(fwd, ObjectiveError.GROUPMISSING);
322 }
323
alshabib1aa58142016-02-17 15:37:56 -0800324 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800325 TrafficTreatment treatment =
326 buildTreatment(Instructions.createGroup(group.id()));
327
328 FlowRule rule = DefaultFlowRule.builder()
alshabib56efe432016-02-25 17:57:24 -0500329 .withCookie(counter.getAndIncrement())
alshabibd61b77b2016-02-01 23:30:53 -0800330 .forDevice(deviceId)
331 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800332 .makePermanent()
333 .withPriority(fwd.priority())
334 .withSelector(fwd.selector())
335 .withTreatment(treatment)
336 .build();
337
338 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
339 switch (fwd.op()) {
340
341 case ADD:
342 builder.add(rule);
343 break;
344 case REMOVE:
345 builder.remove(rule);
346 break;
347 case ADD_TO_EXISTING:
348 case REMOVE_FROM_EXISTING:
349 break;
350 default:
351 log.warn("Unknown forwarding operation: {}", fwd.op());
352 }
353
354 applyFlowRules(builder, fwd);
355
356 }
357
358 private boolean checkForMulticast(ForwardingObjective fwd) {
359
alshabib1aa58142016-02-17 15:37:56 -0800360 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500361 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800362
alshabib1aa58142016-02-17 15:37:56 -0800363 if (ip == null) {
364 return false;
365 }
366
Charles Chanaedabfd2016-02-26 09:31:48 -0800367 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800368
369 }
370
alshabib1aa58142016-02-17 15:37:56 -0800371 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800372 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800373 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800374
alshabib0ccde6d2015-05-30 18:22:36 -0700375 }
376
alshabibfd430b62015-12-16 18:56:38 -0800377 private void installDownstreamRules(ForwardingObjective fwd) {
378 List<Pair<Instruction, Instruction>> vlanOps =
379 vlanOps(fwd,
380 L2ModificationInstruction.L2SubType.VLAN_POP);
381
382 if (vlanOps == null) {
383 return;
384 }
385
alshabibb3c14342016-03-04 17:05:01 -0800386 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, "downstream");
alshabibfd430b62015-12-16 18:56:38 -0800387
388 if (output == null) {
389 return;
390 }
391
392 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
393
alshabibfa0dc662016-01-13 11:23:53 -0800394 TrafficSelector selector = fwd.selector();
395
396 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
397 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
398 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
alshabibb3c14342016-03-04 17:05:01 -0800399 Criterion bullshit = Criteria.matchMetadata(output.port().toLong());
alshabibfa0dc662016-01-13 11:23:53 -0800400
401 if (outerVlan == null || innerVlan == null || inport == null) {
402 log.error("Forwarding objective is underspecified: {}", fwd);
403 fail(fwd, ObjectiveError.BADPARAMS);
404 return;
405 }
406
alshabib2f74f2c2016-01-14 13:29:35 -0800407 Criterion innerVid = Criteria.matchVlanId(((VlanIdCriterion) innerVlan).vlanId());
408
alshabibfa0dc662016-01-13 11:23:53 -0800409 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib56efe432016-02-25 17:57:24 -0500410 .withCookie(counter.getAndIncrement())
alshabibfd430b62015-12-16 18:56:38 -0800411 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800412 .makePermanent()
413 .withPriority(fwd.priority())
alshabibb3c14342016-03-04 17:05:01 -0800414 .withSelector(buildSelector(inport, outerVlan, bullshit))
alshabibfd430b62015-12-16 18:56:38 -0800415 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
416 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800417
alshabibfa0dc662016-01-13 11:23:53 -0800418 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib56efe432016-02-25 17:57:24 -0500419 .withCookie(counter.getAndIncrement())
alshabibfd430b62015-12-16 18:56:38 -0800420 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800421 .forTable(QQ_TABLE)
422 .makePermanent()
423 .withPriority(fwd.priority())
alshabib2f74f2c2016-01-14 13:29:35 -0800424 .withSelector(buildSelector(inport, innerVid))
alshabibe5075842016-02-04 13:28:33 -0800425 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
alshabibfd430b62015-12-16 18:56:38 -0800426 output));
427
428 applyRules(fwd, inner, outer);
429
430 }
431
432 private void installUpstreamRules(ForwardingObjective fwd) {
433 List<Pair<Instruction, Instruction>> vlanOps =
434 vlanOps(fwd,
435 L2ModificationInstruction.L2SubType.VLAN_PUSH);
436
437 if (vlanOps == null) {
438 return;
439 }
440
441 Instruction output = fetchOutput(fwd, "upstream");
442
443 if (output == null) {
444 return;
445 }
446
447 Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
448
449 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
450
451 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib56efe432016-02-25 17:57:24 -0500452 .withCookie(counter.getAndIncrement())
alshabibfd430b62015-12-16 18:56:38 -0800453 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800454 .makePermanent()
455 .withPriority(fwd.priority())
456 .withSelector(fwd.selector())
457 .withTreatment(buildTreatment(innerPair.getRight(),
458 Instructions.transition(QQ_TABLE)));
459
460 PortCriterion inPort = (PortCriterion)
461 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
462
463 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
464 innerPair.getRight()).vlanId();
465
466 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib56efe432016-02-25 17:57:24 -0500467 .withCookie(counter.getAndIncrement())
alshabibfd430b62015-12-16 18:56:38 -0800468 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800469 .forTable(QQ_TABLE)
470 .makePermanent()
471 .withPriority(fwd.priority())
472 .withSelector(buildSelector(inPort,
473 Criteria.matchVlanId(cVlanId)))
474 .withTreatment(buildTreatment(outerPair.getLeft(),
475 outerPair.getRight(),
476 output));
477
478 applyRules(fwd, inner, outer);
479
480 }
481
482 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
483 Instruction output = fwd.treatment().allInstructions().stream()
484 .filter(i -> i.type() == Instruction.Type.OUTPUT)
485 .findFirst().orElse(null);
486
487 if (output == null) {
488 log.error("OLT {} rule has no output", direction);
489 fail(fwd, ObjectiveError.BADPARAMS);
490 return null;
491 }
492 return output;
493 }
494
495 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
496 L2ModificationInstruction.L2SubType type) {
497
498 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
499 fwd.treatment().allInstructions(), type);
500
501 if (vlanOps == null) {
502 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
503 ? "downstream" : "upstream";
504 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
505 fail(fwd, ObjectiveError.BADPARAMS);
506 return null;
507 }
508 return vlanOps;
509 }
510
511
512 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800513 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800514
515 List<Instruction> vlanPushs = findL2Instructions(
516 type,
517 instructions);
518 List<Instruction> vlanSets = findL2Instructions(
519 L2ModificationInstruction.L2SubType.VLAN_ID,
520 instructions);
521
522 if (vlanPushs.size() != vlanSets.size()) {
523 return null;
524 }
525
526 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
527
528 for (int i = 0; i < vlanPushs.size(); i++) {
529 pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
530 }
531 return pairs;
532 }
533
534 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
535 List<Instruction> actions) {
536 return actions.stream()
537 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
538 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
539 .collect(Collectors.toList());
540 }
541
542 private void provisionEapol(FilteringObjective filter,
543 EthTypeCriterion ethType,
544 Instructions.OutputInstruction output) {
545
546 TrafficSelector selector = buildSelector(filter.key(), ethType);
547 TrafficTreatment treatment = buildTreatment(output);
548 buildAndApplyRule(filter, selector, treatment);
549
550 }
551
Jonathan Hart51539b82015-10-29 09:53:04 -0700552 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800553 IPProtocolCriterion ipProto,
554 Instructions.OutputInstruction output) {
555 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
556 TrafficTreatment treatment = buildTreatment(output);
557 buildAndApplyRule(filter, selector, treatment);
558 }
559
560 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
561 TrafficTreatment treatment) {
562 FlowRule rule = DefaultFlowRule.builder()
alshabib56efe432016-02-25 17:57:24 -0500563 .withCookie(counter.getAndIncrement())
alshabibfd430b62015-12-16 18:56:38 -0800564 .forDevice(deviceId)
565 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800566 .makePermanent()
567 .withSelector(selector)
568 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800569 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800570 .build();
571
572 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
573
574 switch (filter.type()) {
575 case PERMIT:
576 opsBuilder.add(rule);
577 break;
578 case DENY:
579 opsBuilder.remove(rule);
580 break;
581 default:
582 log.warn("Unknown filter type : {}", filter.type());
583 fail(filter, ObjectiveError.UNSUPPORTED);
584 }
585
586 applyFlowRules(opsBuilder, filter);
587 }
588
589 private void applyRules(ForwardingObjective fwd,
590 FlowRule.Builder inner, FlowRule.Builder outer) {
591 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
592 switch (fwd.op()) {
593 case ADD:
594 builder.add(inner.build()).add(outer.build());
595 break;
596 case REMOVE:
alshabib6cb86362016-03-03 18:00:58 -0800597 Iterable<FlowEntry> flows = flowRuleService.getFlowEntries(deviceId);
598 for (FlowEntry fe : flows) {
599 if (fe.equals(inner.build()) || fe.equals(outer.build())) {
600 builder.remove(fe);
601 }
602 }
alshabibfd430b62015-12-16 18:56:38 -0800603 break;
604 case ADD_TO_EXISTING:
605 break;
606 case REMOVE_FROM_EXISTING:
607 break;
608 default:
609 log.warn("Unknown forwarding operation: {}", fwd.op());
610 }
611
612 applyFlowRules(builder, fwd);
613 }
614
615 private void applyFlowRules(FlowRuleOperations.Builder builder,
616 Objective objective) {
617 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
618 @Override
619 public void onSuccess(FlowRuleOperations ops) {
620 pass(objective);
621 }
622
623 @Override
624 public void onError(FlowRuleOperations ops) {
625 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
626 }
627 }));
628 }
629
630 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
631 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800632 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800633 .limit(1)
634 .findFirst().orElse(null);
635 }
636
637 private TrafficSelector buildSelector(Criterion... criteria) {
638
639
640 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
641
642 for (Criterion c : criteria) {
643 sBuilder.add(c);
644 }
645
646 return sBuilder.build();
647 }
648
649 private TrafficTreatment buildTreatment(Instruction... instructions) {
650
651
652 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
653
654 for (Instruction i : instructions) {
655 tBuilder.add(i);
656 }
657
658 return tBuilder.build();
659 }
660
661
662 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800663 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -0800664 }
665
666 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800667 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -0800668 }
669
alshabib2cc73cb2015-06-30 20:26:56 -0700670
alshabibd61b77b2016-02-01 23:30:53 -0800671 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -0700672 @Override
alshabibd61b77b2016-02-01 23:30:53 -0800673 public void event(GroupEvent event) {
674 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
675 GroupKey key = event.subject().appCookie();
alshabib2cc73cb2015-06-30 20:26:56 -0700676
alshabibd61b77b2016-02-01 23:30:53 -0800677 NextObjective obj = pendingGroups.getIfPresent(key);
678 if (obj != null) {
679 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
680 pass(obj);
681 pendingGroups.invalidate(key);
682 }
683 }
alshabib2cc73cb2015-06-30 20:26:56 -0700684 }
685 }
686
alshabibd61b77b2016-02-01 23:30:53 -0800687 private static class OLTPipelineGroup implements NextGroup {
688
689 private final GroupKey key;
690
691 public OLTPipelineGroup(GroupKey key) {
692 this.key = key;
693 }
694
695 public GroupKey key() {
696 return key;
697 }
698
699 @Override
700 public byte[] data() {
701 return appKryo.serialize(key);
702 }
703
704 }
Saurav Das24431192016-03-07 19:13:00 -0800705
706 @Override
707 public List<String> getNextMappings(NextGroup nextGroup) {
708 // TODO Implementation deferred to vendor
709 return null;
710 }
alshabib0ccde6d2015-05-30 18:22:36 -0700711}