blob: e8b441103f86e9517d35c6641c8a1dddca989f37 [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;
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.StorageService;
alshabib0ccde6d2015-05-30 18:22:36 -070077import org.slf4j.Logger;
78
alshabibfd430b62015-12-16 18:56:38 -080079import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080080import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080081import java.util.List;
82import java.util.Optional;
alshabibd61b77b2016-02-01 23:30:53 -080083import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080084import java.util.stream.Collectors;
85
alshabib0ccde6d2015-05-30 18:22:36 -070086import static org.slf4j.LoggerFactory.getLogger;
87
88/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070089 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070090 */
alshabibfd430b62015-12-16 18:56:38 -080091
Jonathan Hartb92cc512015-11-16 23:05:21 -080092public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070093
alshabibfd430b62015-12-16 18:56:38 -080094 private static final Integer QQ_TABLE = 1;
alshabibd61b77b2016-02-01 23:30:53 -080095 private static final short MCAST_VLAN = 4000;
alshabib5ccbe3f2016-03-02 22:36:02 -080096 private static final String OLTCOOKIES = "olt-cookies-must-be-unique";
alshabib0ccde6d2015-05-30 18:22:36 -070097 private final Logger log = getLogger(getClass());
98
99 private ServiceDirectory serviceDirectory;
100 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800101 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700102 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800103 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700104
alshabibd61b77b2016-02-01 23:30:53 -0800105 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700106 private ApplicationId appId;
alshabib83364472016-03-25 09:59:55 -0700107
alshabib0ccde6d2015-05-30 18:22:36 -0700108
alshabibd61b77b2016-02-01 23:30:53 -0800109 protected FlowObjectiveStore flowObjectiveStore;
110
111 private Cache<GroupKey, NextObjective> pendingGroups;
112
113 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
114 .register(KryoNamespaces.API)
115 .register(GroupKey.class)
116 .register(DefaultGroupKey.class)
117 .register(OLTPipelineGroup.class)
118 .register(byte[].class)
119 .build();
alshabib2cc73cb2015-06-30 20:26:56 -0700120
alshabib0ccde6d2015-05-30 18:22:36 -0700121 @Override
122 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800123 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700124 this.serviceDirectory = context.directory();
125 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800126
alshabib0ccde6d2015-05-30 18:22:36 -0700127 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700128 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800129 groupService = serviceDirectory.get(GroupService.class);
130 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800131 storageService = serviceDirectory.get(StorageService.class);
132
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700133 appId = coreService.registerApplication(
134 "org.onosproject.driver.OLTPipeline");
135
alshabibd61b77b2016-02-01 23:30:53 -0800136
137 pendingGroups = CacheBuilder.newBuilder()
138 .expireAfterWrite(20, TimeUnit.SECONDS)
139 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
140 if (notification.getCause() == RemovalCause.EXPIRED) {
141 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
142 }
143 }).build();
144
145 groupService.addListener(new InnerGroupListener());
146
alshabibb32cefe2015-06-08 18:15:05 -0700147 }
148
alshabib0ccde6d2015-05-30 18:22:36 -0700149 @Override
150 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800151 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700152
alshabibfd430b62015-12-16 18:56:38 -0800153 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
154 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
155 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
156 .limit(1)
157 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700158
alshabibbb424232016-01-15 12:20:25 -0800159 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
160 log.error("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800161 fail(filter, ObjectiveError.UNSUPPORTED);
162 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700163 }
alshabibfd430b62015-12-16 18:56:38 -0800164 } else {
165 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700166 return;
167 }
168
alshabibfd430b62015-12-16 18:56:38 -0800169 if (filter.key().type() != Criterion.Type.IN_PORT) {
170 fail(filter, ObjectiveError.BADPARAMS);
171 return;
172 }
173
174 EthTypeCriterion ethType = (EthTypeCriterion)
175 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
176
177 if (ethType == null) {
178 fail(filter, ObjectiveError.BADPARAMS);
179 return;
180 }
181
alshabibbb424232016-01-15 12:20:25 -0800182 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800183 provisionEapol(filter, ethType, output);
alshabibbb424232016-01-15 12:20:25 -0800184 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800185 IPProtocolCriterion ipProto = (IPProtocolCriterion)
186 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
187 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700188 provisionIgmp(filter, ethType, ipProto, output);
alshabibbb424232016-01-15 12:20:25 -0800189 } else {
190 log.error("OLT can only filter igmp");
191 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800192 }
193 } else {
alshabibbb424232016-01-15 12:20:25 -0800194 log.error("OLT can only filter eapol and igmp");
alshabibfd430b62015-12-16 18:56:38 -0800195 fail(filter, ObjectiveError.UNSUPPORTED);
196 }
197
198 }
199
200
201 @Override
202 public void forward(ForwardingObjective fwd) {
alshabibd61b77b2016-02-01 23:30:53 -0800203
204 if (checkForMulticast(fwd)) {
205 processMulticastRule(fwd);
206 return;
207 }
208
alshabib0ccde6d2015-05-30 18:22:36 -0700209 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700210
alshabibfd430b62015-12-16 18:56:38 -0800211 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700212
alshabibfd430b62015-12-16 18:56:38 -0800213 Optional<Instruction> vlanIntruction = instructions.stream()
214 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
215 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
216 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
217 ((L2ModificationInstruction) i).subtype() ==
218 L2ModificationInstruction.L2SubType.VLAN_POP)
219 .findAny();
220
221 if (!vlanIntruction.isPresent()) {
222 fail(fwd, ObjectiveError.BADPARAMS);
223 return;
224 }
225
226 L2ModificationInstruction vlanIns =
227 (L2ModificationInstruction) vlanIntruction.get();
228
229 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
230 installUpstreamRules(fwd);
231 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
232 installDownstreamRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700233 } else {
alshabibfd430b62015-12-16 18:56:38 -0800234 log.error("Unknown OLT operation: {}", fwd);
235 fail(fwd, ObjectiveError.UNSUPPORTED);
236 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700237 }
238
alshabibfd430b62015-12-16 18:56:38 -0800239 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700240
alshabib0ccde6d2015-05-30 18:22:36 -0700241 }
242
alshabibd61b77b2016-02-01 23:30:53 -0800243
alshabib0ccde6d2015-05-30 18:22:36 -0700244 @Override
245 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800246 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
247 log.error("OLT only supports broadcast groups.");
248 fail(nextObjective, ObjectiveError.BADPARAMS);
249 }
250
251 if (nextObjective.next().size() != 1) {
252 log.error("OLT only supports singleton broadcast groups.");
253 fail(nextObjective, ObjectiveError.BADPARAMS);
254 }
255
256 TrafficTreatment treatment = nextObjective.next().stream().findFirst().get();
257
258
259 GroupBucket bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
260 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
261
alshabib1aa58142016-02-17 15:37:56 -0800262
alshabibd61b77b2016-02-01 23:30:53 -0800263 pendingGroups.put(key, nextObjective);
264
265 switch (nextObjective.op()) {
266 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800267 GroupDescription groupDesc =
268 new DefaultGroupDescription(deviceId,
269 GroupDescription.Type.ALL,
270 new GroupBuckets(Collections.singletonList(bucket)),
271 key,
272 null,
273 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800274 groupService.addGroup(groupDesc);
275 break;
276 case REMOVE:
277 groupService.removeGroup(deviceId, key, nextObjective.appId());
278 break;
279 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800280 groupService.addBucketsToGroup(deviceId, key,
281 new GroupBuckets(Collections.singletonList(bucket)),
282 key, nextObjective.appId());
283 break;
alshabibd61b77b2016-02-01 23:30:53 -0800284 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800285 groupService.removeBucketsFromGroup(deviceId, key,
alshabib56efe432016-02-25 17:57:24 -0500286 new GroupBuckets(Collections.singletonList(bucket)),
287 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800288 break;
289 default:
290 log.warn("Unknown next objective operation: {}", nextObjective.op());
291 }
292
293
294 }
295
296 private void processMulticastRule(ForwardingObjective fwd) {
297 if (fwd.nextId() == null) {
298 log.error("Multicast objective does not have a next id");
299 fail(fwd, ObjectiveError.BADPARAMS);
300 }
301
alshabib1aa58142016-02-17 15:37:56 -0800302 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800303
alshabib1aa58142016-02-17 15:37:56 -0800304 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800305 log.error("Group for forwarding objective missing: {}", fwd);
306 fail(fwd, ObjectiveError.GROUPMISSING);
307 }
308
alshabib1aa58142016-02-17 15:37:56 -0800309 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800310 TrafficTreatment treatment =
311 buildTreatment(Instructions.createGroup(group.id()));
312
313 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700314 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800315 .forDevice(deviceId)
316 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800317 .makePermanent()
318 .withPriority(fwd.priority())
319 .withSelector(fwd.selector())
320 .withTreatment(treatment)
321 .build();
322
323 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
324 switch (fwd.op()) {
325
326 case ADD:
327 builder.add(rule);
328 break;
329 case REMOVE:
330 builder.remove(rule);
331 break;
332 case ADD_TO_EXISTING:
333 case REMOVE_FROM_EXISTING:
334 break;
335 default:
336 log.warn("Unknown forwarding operation: {}", fwd.op());
337 }
338
339 applyFlowRules(builder, fwd);
340
341 }
342
343 private boolean checkForMulticast(ForwardingObjective fwd) {
344
alshabib1aa58142016-02-17 15:37:56 -0800345 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500346 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800347
alshabib1aa58142016-02-17 15:37:56 -0800348 if (ip == null) {
349 return false;
350 }
351
Charles Chanaedabfd2016-02-26 09:31:48 -0800352 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800353
354 }
355
alshabib1aa58142016-02-17 15:37:56 -0800356 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800357 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800358 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800359
alshabib0ccde6d2015-05-30 18:22:36 -0700360 }
361
alshabibfd430b62015-12-16 18:56:38 -0800362 private void installDownstreamRules(ForwardingObjective fwd) {
363 List<Pair<Instruction, Instruction>> vlanOps =
364 vlanOps(fwd,
365 L2ModificationInstruction.L2SubType.VLAN_POP);
366
367 if (vlanOps == null) {
368 return;
369 }
370
alshabibb3c14342016-03-04 17:05:01 -0800371 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, "downstream");
alshabibfd430b62015-12-16 18:56:38 -0800372
373 if (output == null) {
374 return;
375 }
376
377 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
378
alshabibfa0dc662016-01-13 11:23:53 -0800379 TrafficSelector selector = fwd.selector();
380
381 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
382 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
383 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
alshabibb3c14342016-03-04 17:05:01 -0800384 Criterion bullshit = Criteria.matchMetadata(output.port().toLong());
alshabibfa0dc662016-01-13 11:23:53 -0800385
386 if (outerVlan == null || innerVlan == null || inport == null) {
387 log.error("Forwarding objective is underspecified: {}", fwd);
388 fail(fwd, ObjectiveError.BADPARAMS);
389 return;
390 }
391
alshabib2f74f2c2016-01-14 13:29:35 -0800392 Criterion innerVid = Criteria.matchVlanId(((VlanIdCriterion) innerVlan).vlanId());
393
alshabibfa0dc662016-01-13 11:23:53 -0800394 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700395 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800396 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800397 .makePermanent()
398 .withPriority(fwd.priority())
alshabibb3c14342016-03-04 17:05:01 -0800399 .withSelector(buildSelector(inport, outerVlan, bullshit))
alshabibfd430b62015-12-16 18:56:38 -0800400 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
401 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800402
alshabibfa0dc662016-01-13 11:23:53 -0800403 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700404 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800405 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800406 .forTable(QQ_TABLE)
407 .makePermanent()
408 .withPriority(fwd.priority())
alshabib2f74f2c2016-01-14 13:29:35 -0800409 .withSelector(buildSelector(inport, innerVid))
alshabibe5075842016-02-04 13:28:33 -0800410 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
alshabibfd430b62015-12-16 18:56:38 -0800411 output));
412
413 applyRules(fwd, inner, outer);
414
415 }
416
417 private void installUpstreamRules(ForwardingObjective fwd) {
418 List<Pair<Instruction, Instruction>> vlanOps =
419 vlanOps(fwd,
420 L2ModificationInstruction.L2SubType.VLAN_PUSH);
421
422 if (vlanOps == null) {
423 return;
424 }
425
426 Instruction output = fetchOutput(fwd, "upstream");
427
428 if (output == null) {
429 return;
430 }
431
432 Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
433
434 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
435
436 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700437 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800438 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800439 .makePermanent()
440 .withPriority(fwd.priority())
441 .withSelector(fwd.selector())
442 .withTreatment(buildTreatment(innerPair.getRight(),
443 Instructions.transition(QQ_TABLE)));
444
445 PortCriterion inPort = (PortCriterion)
446 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
447
448 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
449 innerPair.getRight()).vlanId();
450
451 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700452 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800453 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800454 .forTable(QQ_TABLE)
455 .makePermanent()
456 .withPriority(fwd.priority())
457 .withSelector(buildSelector(inPort,
458 Criteria.matchVlanId(cVlanId)))
459 .withTreatment(buildTreatment(outerPair.getLeft(),
460 outerPair.getRight(),
461 output));
462
463 applyRules(fwd, inner, outer);
464
465 }
466
467 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
468 Instruction output = fwd.treatment().allInstructions().stream()
469 .filter(i -> i.type() == Instruction.Type.OUTPUT)
470 .findFirst().orElse(null);
471
472 if (output == null) {
473 log.error("OLT {} rule has no output", direction);
474 fail(fwd, ObjectiveError.BADPARAMS);
475 return null;
476 }
477 return output;
478 }
479
480 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
481 L2ModificationInstruction.L2SubType type) {
482
483 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
484 fwd.treatment().allInstructions(), type);
485
486 if (vlanOps == null) {
487 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
488 ? "downstream" : "upstream";
489 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
490 fail(fwd, ObjectiveError.BADPARAMS);
491 return null;
492 }
493 return vlanOps;
494 }
495
496
497 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800498 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800499
500 List<Instruction> vlanPushs = findL2Instructions(
501 type,
502 instructions);
503 List<Instruction> vlanSets = findL2Instructions(
504 L2ModificationInstruction.L2SubType.VLAN_ID,
505 instructions);
506
507 if (vlanPushs.size() != vlanSets.size()) {
508 return null;
509 }
510
511 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
512
513 for (int i = 0; i < vlanPushs.size(); i++) {
514 pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
515 }
516 return pairs;
517 }
518
519 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
520 List<Instruction> actions) {
521 return actions.stream()
522 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
523 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
524 .collect(Collectors.toList());
525 }
526
527 private void provisionEapol(FilteringObjective filter,
528 EthTypeCriterion ethType,
529 Instructions.OutputInstruction output) {
530
531 TrafficSelector selector = buildSelector(filter.key(), ethType);
532 TrafficTreatment treatment = buildTreatment(output);
533 buildAndApplyRule(filter, selector, treatment);
534
535 }
536
Jonathan Hart51539b82015-10-29 09:53:04 -0700537 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800538 IPProtocolCriterion ipProto,
539 Instructions.OutputInstruction output) {
540 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
541 TrafficTreatment treatment = buildTreatment(output);
542 buildAndApplyRule(filter, selector, treatment);
543 }
544
545 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
546 TrafficTreatment treatment) {
547 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700548 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800549 .forDevice(deviceId)
550 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800551 .makePermanent()
552 .withSelector(selector)
553 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800554 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800555 .build();
556
557 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
558
559 switch (filter.type()) {
560 case PERMIT:
561 opsBuilder.add(rule);
562 break;
563 case DENY:
564 opsBuilder.remove(rule);
565 break;
566 default:
567 log.warn("Unknown filter type : {}", filter.type());
568 fail(filter, ObjectiveError.UNSUPPORTED);
569 }
570
571 applyFlowRules(opsBuilder, filter);
572 }
573
574 private void applyRules(ForwardingObjective fwd,
575 FlowRule.Builder inner, FlowRule.Builder outer) {
576 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
577 switch (fwd.op()) {
578 case ADD:
579 builder.add(inner.build()).add(outer.build());
580 break;
581 case REMOVE:
alshabib6cb86362016-03-03 18:00:58 -0800582 Iterable<FlowEntry> flows = flowRuleService.getFlowEntries(deviceId);
583 for (FlowEntry fe : flows) {
584 if (fe.equals(inner.build()) || fe.equals(outer.build())) {
585 builder.remove(fe);
586 }
587 }
alshabibfd430b62015-12-16 18:56:38 -0800588 break;
589 case ADD_TO_EXISTING:
590 break;
591 case REMOVE_FROM_EXISTING:
592 break;
593 default:
594 log.warn("Unknown forwarding operation: {}", fwd.op());
595 }
596
597 applyFlowRules(builder, fwd);
598 }
599
600 private void applyFlowRules(FlowRuleOperations.Builder builder,
601 Objective objective) {
602 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
603 @Override
604 public void onSuccess(FlowRuleOperations ops) {
605 pass(objective);
606 }
607
608 @Override
609 public void onError(FlowRuleOperations ops) {
610 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
611 }
612 }));
613 }
614
615 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
616 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800617 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800618 .limit(1)
619 .findFirst().orElse(null);
620 }
621
622 private TrafficSelector buildSelector(Criterion... criteria) {
623
624
625 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
626
627 for (Criterion c : criteria) {
628 sBuilder.add(c);
629 }
630
631 return sBuilder.build();
632 }
633
634 private TrafficTreatment buildTreatment(Instruction... instructions) {
635
636
637 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
638
639 for (Instruction i : instructions) {
640 tBuilder.add(i);
641 }
642
643 return tBuilder.build();
644 }
645
646
647 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800648 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -0800649 }
650
651 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800652 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -0800653 }
654
alshabib2cc73cb2015-06-30 20:26:56 -0700655
alshabibd61b77b2016-02-01 23:30:53 -0800656 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -0700657 @Override
alshabibd61b77b2016-02-01 23:30:53 -0800658 public void event(GroupEvent event) {
659 if (event.type() == GroupEvent.Type.GROUP_ADDED) {
660 GroupKey key = event.subject().appCookie();
alshabib2cc73cb2015-06-30 20:26:56 -0700661
alshabibd61b77b2016-02-01 23:30:53 -0800662 NextObjective obj = pendingGroups.getIfPresent(key);
663 if (obj != null) {
664 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
665 pass(obj);
666 pendingGroups.invalidate(key);
667 }
668 }
alshabib2cc73cb2015-06-30 20:26:56 -0700669 }
670 }
671
alshabibd61b77b2016-02-01 23:30:53 -0800672 private static class OLTPipelineGroup implements NextGroup {
673
674 private final GroupKey key;
675
676 public OLTPipelineGroup(GroupKey key) {
677 this.key = key;
678 }
679
680 public GroupKey key() {
681 return key;
682 }
683
684 @Override
685 public byte[] data() {
686 return appKryo.serialize(key);
687 }
688
689 }
Saurav Das24431192016-03-07 19:13:00 -0800690
691 @Override
692 public List<String> getNextMappings(NextGroup nextGroup) {
693 // TODO Implementation deferred to vendor
694 return null;
695 }
alshabib0ccde6d2015-05-30 18:22:36 -0700696}