blob: 3b4025d05c12e95c726d81b6a4de369c1f2e1b58 [file] [log] [blame]
alshabib0ccde6d2015-05-30 18:22:36 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present 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;
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;
alshabib1aa58142016-02-17 15:37:56 -080050import org.onosproject.net.flow.criteria.IPCriterion;
alshabibfd430b62015-12-16 18:56:38 -080051import org.onosproject.net.flow.criteria.IPProtocolCriterion;
52import org.onosproject.net.flow.criteria.PortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080053import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080054import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070055import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080056import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070057import org.onosproject.net.flowobjective.FilteringObjective;
alshabibd61b77b2016-02-01 23:30:53 -080058import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabib0ccde6d2015-05-30 18:22:36 -070059import org.onosproject.net.flowobjective.ForwardingObjective;
60import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080061import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070062import org.onosproject.net.flowobjective.ObjectiveError;
alshabibd61b77b2016-02-01 23:30:53 -080063import org.onosproject.net.group.DefaultGroupBucket;
64import org.onosproject.net.group.DefaultGroupDescription;
65import org.onosproject.net.group.DefaultGroupKey;
66import org.onosproject.net.group.Group;
67import org.onosproject.net.group.GroupBucket;
68import org.onosproject.net.group.GroupBuckets;
69import org.onosproject.net.group.GroupDescription;
70import org.onosproject.net.group.GroupEvent;
71import org.onosproject.net.group.GroupKey;
72import org.onosproject.net.group.GroupListener;
73import org.onosproject.net.group.GroupService;
74import org.onosproject.store.serializers.KryoNamespaces;
alshabib5ccbe3f2016-03-02 22:36:02 -080075import org.onosproject.store.service.StorageService;
alshabib0ccde6d2015-05-30 18:22:36 -070076import org.slf4j.Logger;
77
alshabibfd430b62015-12-16 18:56:38 -080078import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080079import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080080import java.util.List;
81import java.util.Optional;
alshabibd61b77b2016-02-01 23:30:53 -080082import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080083import java.util.stream.Collectors;
84
alshabib0ccde6d2015-05-30 18:22:36 -070085import static org.slf4j.LoggerFactory.getLogger;
86
87/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070088 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070089 */
alshabibfd430b62015-12-16 18:56:38 -080090
Jonathan Hartb92cc512015-11-16 23:05:21 -080091public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070092
alshabibfd430b62015-12-16 18:56:38 -080093 private static final Integer QQ_TABLE = 1;
alshabibd61b77b2016-02-01 23:30:53 -080094 private static final short MCAST_VLAN = 4000;
alshabib5ccbe3f2016-03-02 22:36:02 -080095 private static final String OLTCOOKIES = "olt-cookies-must-be-unique";
alshabib0ccde6d2015-05-30 18:22:36 -070096 private final Logger log = getLogger(getClass());
97
98 private ServiceDirectory serviceDirectory;
99 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800100 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700101 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800102 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700103
alshabibd61b77b2016-02-01 23:30:53 -0800104 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700105 private ApplicationId appId;
alshabib83364472016-03-25 09:59:55 -0700106
alshabib0ccde6d2015-05-30 18:22:36 -0700107
alshabibd61b77b2016-02-01 23:30:53 -0800108 protected FlowObjectiveStore flowObjectiveStore;
109
110 private Cache<GroupKey, NextObjective> pendingGroups;
111
112 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
113 .register(KryoNamespaces.API)
114 .register(GroupKey.class)
115 .register(DefaultGroupKey.class)
116 .register(OLTPipelineGroup.class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700117 .build("OltPipeline");
alshabib2cc73cb2015-06-30 20:26:56 -0700118
alshabib0ccde6d2015-05-30 18:22:36 -0700119 @Override
120 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800121 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700122 this.serviceDirectory = context.directory();
123 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800124
alshabib0ccde6d2015-05-30 18:22:36 -0700125 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700126 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800127 groupService = serviceDirectory.get(GroupService.class);
128 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800129 storageService = serviceDirectory.get(StorageService.class);
130
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700131 appId = coreService.registerApplication(
132 "org.onosproject.driver.OLTPipeline");
133
alshabibd61b77b2016-02-01 23:30:53 -0800134
135 pendingGroups = CacheBuilder.newBuilder()
136 .expireAfterWrite(20, TimeUnit.SECONDS)
137 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
138 if (notification.getCause() == RemovalCause.EXPIRED) {
139 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
140 }
141 }).build();
142
143 groupService.addListener(new InnerGroupListener());
144
alshabibb32cefe2015-06-08 18:15:05 -0700145 }
146
alshabib0ccde6d2015-05-30 18:22:36 -0700147 @Override
148 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800149 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700150
alshabibfd430b62015-12-16 18:56:38 -0800151 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
152 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
153 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
154 .limit(1)
155 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700156
alshabibbb424232016-01-15 12:20:25 -0800157 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
158 log.error("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800159 fail(filter, ObjectiveError.UNSUPPORTED);
160 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700161 }
alshabibfd430b62015-12-16 18:56:38 -0800162 } else {
163 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700164 return;
165 }
166
alshabibfd430b62015-12-16 18:56:38 -0800167 if (filter.key().type() != Criterion.Type.IN_PORT) {
168 fail(filter, ObjectiveError.BADPARAMS);
169 return;
170 }
171
172 EthTypeCriterion ethType = (EthTypeCriterion)
173 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
174
175 if (ethType == null) {
176 fail(filter, ObjectiveError.BADPARAMS);
177 return;
178 }
179
alshabibbb424232016-01-15 12:20:25 -0800180 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800181 provisionEapol(filter, ethType, output);
alshabibbb424232016-01-15 12:20:25 -0800182 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800183 IPProtocolCriterion ipProto = (IPProtocolCriterion)
184 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
185 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700186 provisionIgmp(filter, ethType, ipProto, output);
alshabibbb424232016-01-15 12:20:25 -0800187 } else {
188 log.error("OLT can only filter igmp");
189 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800190 }
191 } else {
alshabibbb424232016-01-15 12:20:25 -0800192 log.error("OLT can only filter eapol and igmp");
alshabibfd430b62015-12-16 18:56:38 -0800193 fail(filter, ObjectiveError.UNSUPPORTED);
194 }
195
196 }
197
198
199 @Override
200 public void forward(ForwardingObjective fwd) {
alshabibd61b77b2016-02-01 23:30:53 -0800201
202 if (checkForMulticast(fwd)) {
203 processMulticastRule(fwd);
204 return;
205 }
206
alshabib0ccde6d2015-05-30 18:22:36 -0700207 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700208
alshabibfd430b62015-12-16 18:56:38 -0800209 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700210
alshabibfd430b62015-12-16 18:56:38 -0800211 Optional<Instruction> vlanIntruction = instructions.stream()
212 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
213 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
214 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
215 ((L2ModificationInstruction) i).subtype() ==
216 L2ModificationInstruction.L2SubType.VLAN_POP)
217 .findAny();
218
219 if (!vlanIntruction.isPresent()) {
220 fail(fwd, ObjectiveError.BADPARAMS);
221 return;
222 }
223
224 L2ModificationInstruction vlanIns =
225 (L2ModificationInstruction) vlanIntruction.get();
226
227 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
228 installUpstreamRules(fwd);
229 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
230 installDownstreamRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700231 } else {
alshabibfd430b62015-12-16 18:56:38 -0800232 log.error("Unknown OLT operation: {}", fwd);
233 fail(fwd, ObjectiveError.UNSUPPORTED);
234 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700235 }
236
alshabibfd430b62015-12-16 18:56:38 -0800237 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700238
alshabib0ccde6d2015-05-30 18:22:36 -0700239 }
240
alshabibd61b77b2016-02-01 23:30:53 -0800241
alshabib0ccde6d2015-05-30 18:22:36 -0700242 @Override
243 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800244 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
245 log.error("OLT only supports broadcast groups.");
246 fail(nextObjective, ObjectiveError.BADPARAMS);
247 }
248
249 if (nextObjective.next().size() != 1) {
250 log.error("OLT only supports singleton broadcast groups.");
251 fail(nextObjective, ObjectiveError.BADPARAMS);
252 }
253
254 TrafficTreatment treatment = nextObjective.next().stream().findFirst().get();
255
256
257 GroupBucket bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
258 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
259
alshabib1aa58142016-02-17 15:37:56 -0800260
alshabibd61b77b2016-02-01 23:30:53 -0800261 pendingGroups.put(key, nextObjective);
262
263 switch (nextObjective.op()) {
264 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800265 GroupDescription groupDesc =
266 new DefaultGroupDescription(deviceId,
267 GroupDescription.Type.ALL,
268 new GroupBuckets(Collections.singletonList(bucket)),
269 key,
270 null,
271 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800272 groupService.addGroup(groupDesc);
273 break;
274 case REMOVE:
275 groupService.removeGroup(deviceId, key, nextObjective.appId());
276 break;
277 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800278 groupService.addBucketsToGroup(deviceId, key,
279 new GroupBuckets(Collections.singletonList(bucket)),
280 key, nextObjective.appId());
281 break;
alshabibd61b77b2016-02-01 23:30:53 -0800282 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800283 groupService.removeBucketsFromGroup(deviceId, key,
alshabib56efe432016-02-25 17:57:24 -0500284 new GroupBuckets(Collections.singletonList(bucket)),
285 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800286 break;
287 default:
288 log.warn("Unknown next objective operation: {}", nextObjective.op());
289 }
290
291
292 }
293
294 private void processMulticastRule(ForwardingObjective fwd) {
295 if (fwd.nextId() == null) {
296 log.error("Multicast objective does not have a next id");
297 fail(fwd, ObjectiveError.BADPARAMS);
298 }
299
alshabib1aa58142016-02-17 15:37:56 -0800300 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800301
alshabib1aa58142016-02-17 15:37:56 -0800302 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800303 log.error("Group for forwarding objective missing: {}", fwd);
304 fail(fwd, ObjectiveError.GROUPMISSING);
305 }
306
alshabib1aa58142016-02-17 15:37:56 -0800307 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800308 TrafficTreatment treatment =
309 buildTreatment(Instructions.createGroup(group.id()));
310
311 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700312 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800313 .forDevice(deviceId)
314 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800315 .makePermanent()
316 .withPriority(fwd.priority())
317 .withSelector(fwd.selector())
318 .withTreatment(treatment)
319 .build();
320
321 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
322 switch (fwd.op()) {
323
324 case ADD:
325 builder.add(rule);
326 break;
327 case REMOVE:
328 builder.remove(rule);
329 break;
330 case ADD_TO_EXISTING:
331 case REMOVE_FROM_EXISTING:
332 break;
333 default:
334 log.warn("Unknown forwarding operation: {}", fwd.op());
335 }
336
337 applyFlowRules(builder, fwd);
338
339 }
340
341 private boolean checkForMulticast(ForwardingObjective fwd) {
342
alshabib1aa58142016-02-17 15:37:56 -0800343 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500344 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800345
alshabib1aa58142016-02-17 15:37:56 -0800346 if (ip == null) {
347 return false;
348 }
349
Charles Chanaedabfd2016-02-26 09:31:48 -0800350 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800351
352 }
353
alshabib1aa58142016-02-17 15:37:56 -0800354 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800355 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800356 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800357
alshabib0ccde6d2015-05-30 18:22:36 -0700358 }
359
alshabibfd430b62015-12-16 18:56:38 -0800360 private void installDownstreamRules(ForwardingObjective fwd) {
361 List<Pair<Instruction, Instruction>> vlanOps =
362 vlanOps(fwd,
363 L2ModificationInstruction.L2SubType.VLAN_POP);
364
365 if (vlanOps == null) {
366 return;
367 }
368
alshabibb3c14342016-03-04 17:05:01 -0800369 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, "downstream");
alshabibfd430b62015-12-16 18:56:38 -0800370
371 if (output == null) {
372 return;
373 }
374
375 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
376
alshabibfa0dc662016-01-13 11:23:53 -0800377 TrafficSelector selector = fwd.selector();
378
379 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
380 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
381 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
alshabibb3c14342016-03-04 17:05:01 -0800382 Criterion bullshit = Criteria.matchMetadata(output.port().toLong());
alshabibfa0dc662016-01-13 11:23:53 -0800383
384 if (outerVlan == null || innerVlan == null || inport == null) {
385 log.error("Forwarding objective is underspecified: {}", fwd);
386 fail(fwd, ObjectiveError.BADPARAMS);
387 return;
388 }
389
alshabib2f74f2c2016-01-14 13:29:35 -0800390 Criterion innerVid = Criteria.matchVlanId(((VlanIdCriterion) innerVlan).vlanId());
391
alshabibfa0dc662016-01-13 11:23:53 -0800392 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700393 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800394 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800395 .makePermanent()
396 .withPriority(fwd.priority())
alshabibb3c14342016-03-04 17:05:01 -0800397 .withSelector(buildSelector(inport, outerVlan, bullshit))
alshabibfd430b62015-12-16 18:56:38 -0800398 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
399 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800400
alshabibfa0dc662016-01-13 11:23:53 -0800401 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700402 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800403 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800404 .forTable(QQ_TABLE)
405 .makePermanent()
406 .withPriority(fwd.priority())
alshabib2f74f2c2016-01-14 13:29:35 -0800407 .withSelector(buildSelector(inport, innerVid))
alshabibe5075842016-02-04 13:28:33 -0800408 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
alshabibfd430b62015-12-16 18:56:38 -0800409 output));
410
411 applyRules(fwd, inner, outer);
412
413 }
414
415 private void installUpstreamRules(ForwardingObjective fwd) {
416 List<Pair<Instruction, Instruction>> vlanOps =
417 vlanOps(fwd,
418 L2ModificationInstruction.L2SubType.VLAN_PUSH);
419
420 if (vlanOps == null) {
421 return;
422 }
423
424 Instruction output = fetchOutput(fwd, "upstream");
425
426 if (output == null) {
427 return;
428 }
429
430 Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
431
432 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
433
434 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700435 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800436 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800437 .makePermanent()
438 .withPriority(fwd.priority())
439 .withSelector(fwd.selector())
440 .withTreatment(buildTreatment(innerPair.getRight(),
441 Instructions.transition(QQ_TABLE)));
442
443 PortCriterion inPort = (PortCriterion)
444 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
445
446 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
447 innerPair.getRight()).vlanId();
448
449 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700450 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800451 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800452 .forTable(QQ_TABLE)
453 .makePermanent()
454 .withPriority(fwd.priority())
455 .withSelector(buildSelector(inPort,
456 Criteria.matchVlanId(cVlanId)))
457 .withTreatment(buildTreatment(outerPair.getLeft(),
458 outerPair.getRight(),
459 output));
460
461 applyRules(fwd, inner, outer);
462
463 }
464
465 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
466 Instruction output = fwd.treatment().allInstructions().stream()
467 .filter(i -> i.type() == Instruction.Type.OUTPUT)
468 .findFirst().orElse(null);
469
470 if (output == null) {
471 log.error("OLT {} rule has no output", direction);
472 fail(fwd, ObjectiveError.BADPARAMS);
473 return null;
474 }
475 return output;
476 }
477
478 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
479 L2ModificationInstruction.L2SubType type) {
480
481 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
482 fwd.treatment().allInstructions(), type);
483
484 if (vlanOps == null) {
485 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
486 ? "downstream" : "upstream";
487 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
488 fail(fwd, ObjectiveError.BADPARAMS);
489 return null;
490 }
491 return vlanOps;
492 }
493
494
495 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800496 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800497
498 List<Instruction> vlanPushs = findL2Instructions(
499 type,
500 instructions);
501 List<Instruction> vlanSets = findL2Instructions(
502 L2ModificationInstruction.L2SubType.VLAN_ID,
503 instructions);
504
505 if (vlanPushs.size() != vlanSets.size()) {
506 return null;
507 }
508
509 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
510
511 for (int i = 0; i < vlanPushs.size(); i++) {
512 pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
513 }
514 return pairs;
515 }
516
517 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
518 List<Instruction> actions) {
519 return actions.stream()
520 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
521 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
522 .collect(Collectors.toList());
523 }
524
525 private void provisionEapol(FilteringObjective filter,
526 EthTypeCriterion ethType,
527 Instructions.OutputInstruction output) {
528
529 TrafficSelector selector = buildSelector(filter.key(), ethType);
530 TrafficTreatment treatment = buildTreatment(output);
531 buildAndApplyRule(filter, selector, treatment);
532
533 }
534
Jonathan Hart51539b82015-10-29 09:53:04 -0700535 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800536 IPProtocolCriterion ipProto,
537 Instructions.OutputInstruction output) {
538 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
539 TrafficTreatment treatment = buildTreatment(output);
540 buildAndApplyRule(filter, selector, treatment);
541 }
542
543 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
544 TrafficTreatment treatment) {
545 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700546 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800547 .forDevice(deviceId)
548 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800549 .makePermanent()
550 .withSelector(selector)
551 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800552 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800553 .build();
554
555 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
556
557 switch (filter.type()) {
558 case PERMIT:
559 opsBuilder.add(rule);
560 break;
561 case DENY:
562 opsBuilder.remove(rule);
563 break;
564 default:
565 log.warn("Unknown filter type : {}", filter.type());
566 fail(filter, ObjectiveError.UNSUPPORTED);
567 }
568
569 applyFlowRules(opsBuilder, filter);
570 }
571
572 private void applyRules(ForwardingObjective fwd,
573 FlowRule.Builder inner, FlowRule.Builder outer) {
574 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
575 switch (fwd.op()) {
576 case ADD:
577 builder.add(inner.build()).add(outer.build());
578 break;
579 case REMOVE:
alshabibb05be2d2016-04-11 12:52:36 -0700580 builder.remove(inner.build()).remove(outer.build());
alshabibfd430b62015-12-16 18:56:38 -0800581 break;
582 case ADD_TO_EXISTING:
583 break;
584 case REMOVE_FROM_EXISTING:
585 break;
586 default:
587 log.warn("Unknown forwarding operation: {}", fwd.op());
588 }
589
590 applyFlowRules(builder, fwd);
591 }
592
593 private void applyFlowRules(FlowRuleOperations.Builder builder,
594 Objective objective) {
595 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
596 @Override
597 public void onSuccess(FlowRuleOperations ops) {
598 pass(objective);
599 }
600
601 @Override
602 public void onError(FlowRuleOperations ops) {
603 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
604 }
605 }));
606 }
607
608 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
609 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800610 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800611 .limit(1)
612 .findFirst().orElse(null);
613 }
614
615 private TrafficSelector buildSelector(Criterion... criteria) {
616
617
618 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
619
620 for (Criterion c : criteria) {
621 sBuilder.add(c);
622 }
623
624 return sBuilder.build();
625 }
626
627 private TrafficTreatment buildTreatment(Instruction... instructions) {
628
629
630 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
631
632 for (Instruction i : instructions) {
633 tBuilder.add(i);
634 }
635
636 return tBuilder.build();
637 }
638
639
640 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800641 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -0800642 }
643
644 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800645 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -0800646 }
647
alshabib2cc73cb2015-06-30 20:26:56 -0700648
alshabibd61b77b2016-02-01 23:30:53 -0800649 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -0700650 @Override
alshabibd61b77b2016-02-01 23:30:53 -0800651 public void event(GroupEvent event) {
ke hanf5086672016-08-12 11:09:17 +0800652 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
653 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -0800654 GroupKey key = event.subject().appCookie();
alshabib2cc73cb2015-06-30 20:26:56 -0700655
alshabibd61b77b2016-02-01 23:30:53 -0800656 NextObjective obj = pendingGroups.getIfPresent(key);
657 if (obj != null) {
658 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
659 pass(obj);
660 pendingGroups.invalidate(key);
661 }
662 }
alshabib2cc73cb2015-06-30 20:26:56 -0700663 }
664 }
665
alshabibd61b77b2016-02-01 23:30:53 -0800666 private static class OLTPipelineGroup implements NextGroup {
667
668 private final GroupKey key;
669
670 public OLTPipelineGroup(GroupKey key) {
671 this.key = key;
672 }
673
674 public GroupKey key() {
675 return key;
676 }
677
678 @Override
679 public byte[] data() {
680 return appKryo.serialize(key);
681 }
682
683 }
Saurav Das24431192016-03-07 19:13:00 -0800684
685 @Override
686 public List<String> getNextMappings(NextGroup nextGroup) {
687 // TODO Implementation deferred to vendor
688 return null;
689 }
alshabib0ccde6d2015-05-30 18:22:36 -0700690}