blob: 73eaa8b96d02eb11f1adf0c76f38e18040ffc465 [file] [log] [blame]
alshabib0ccde6d2015-05-30 18:22:36 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
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;
Amit Ghoshcbaf8672016-12-23 21:36:19 +000053import org.onosproject.net.flow.criteria.UdpPortCriterion;
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)
Charles Chaneefdedf2016-05-23 16:45:45 -0700118 .build("OltPipeline");
alshabib2cc73cb2015-06-30 20:26:56 -0700119
alshabib0ccde6d2015-05-30 18:22:36 -0700120 @Override
121 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800122 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700123 this.serviceDirectory = context.directory();
124 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800125
alshabib0ccde6d2015-05-30 18:22:36 -0700126 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700127 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800128 groupService = serviceDirectory.get(GroupService.class);
129 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800130 storageService = serviceDirectory.get(StorageService.class);
131
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700132 appId = coreService.registerApplication(
133 "org.onosproject.driver.OLTPipeline");
134
alshabibd61b77b2016-02-01 23:30:53 -0800135
136 pendingGroups = CacheBuilder.newBuilder()
137 .expireAfterWrite(20, TimeUnit.SECONDS)
138 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
139 if (notification.getCause() == RemovalCause.EXPIRED) {
140 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
141 }
142 }).build();
143
144 groupService.addListener(new InnerGroupListener());
145
alshabibb32cefe2015-06-08 18:15:05 -0700146 }
147
alshabib0ccde6d2015-05-30 18:22:36 -0700148 @Override
149 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800150 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700151
alshabibfd430b62015-12-16 18:56:38 -0800152 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
153 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
154 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
155 .limit(1)
156 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700157
alshabibbb424232016-01-15 12:20:25 -0800158 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
dvaddire8e6b89a2017-08-31 21:54:03 +0530159 log.warn("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800160 fail(filter, ObjectiveError.UNSUPPORTED);
161 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700162 }
alshabibfd430b62015-12-16 18:56:38 -0800163 } else {
164 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700165 return;
166 }
167
alshabibfd430b62015-12-16 18:56:38 -0800168 if (filter.key().type() != Criterion.Type.IN_PORT) {
169 fail(filter, ObjectiveError.BADPARAMS);
170 return;
171 }
172
173 EthTypeCriterion ethType = (EthTypeCriterion)
174 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
175
176 if (ethType == null) {
177 fail(filter, ObjectiveError.BADPARAMS);
178 return;
179 }
180
alshabibbb424232016-01-15 12:20:25 -0800181 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100182 provisionEthTypeBasedFilter(filter, ethType, output);
183 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType())) {
184 provisionEthTypeBasedFilter(filter, ethType, output);
185
alshabibbb424232016-01-15 12:20:25 -0800186 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800187 IPProtocolCriterion ipProto = (IPProtocolCriterion)
188 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530189 if (ipProto == null) {
190 log.warn("OLT can only filter IGMP and DHCP");
191 fail(filter, ObjectiveError.UNSUPPORTED);
192 return;
193 }
alshabibfd430b62015-12-16 18:56:38 -0800194 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700195 provisionIgmp(filter, ethType, ipProto, output);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000196 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
197 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
198 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
199
200 UdpPortCriterion udpDstPort = (UdpPortCriterion)
201 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
202
203 if (udpSrcPort.udpPort().toInt() != 68 || udpDstPort.udpPort().toInt() != 67) {
dvaddire8e6b89a2017-08-31 21:54:03 +0530204 log.warn("OLT can only filter DHCP, wrong UDP Src or Dst Port");
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000205 fail(filter, ObjectiveError.UNSUPPORTED);
206 }
207 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, output);
alshabibbb424232016-01-15 12:20:25 -0800208 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530209 log.warn("OLT can only filter IGMP and DHCP");
alshabibbb424232016-01-15 12:20:25 -0800210 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800211 }
212 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530213 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100214 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
dvaddire8e6b89a2017-08-31 21:54:03 +0530215 + "IPV4 TYPE: IGMP and UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800216 fail(filter, ObjectiveError.UNSUPPORTED);
217 }
218
219 }
220
221
222 @Override
223 public void forward(ForwardingObjective fwd) {
alshabibd61b77b2016-02-01 23:30:53 -0800224
225 if (checkForMulticast(fwd)) {
226 processMulticastRule(fwd);
227 return;
228 }
229
alshabib0ccde6d2015-05-30 18:22:36 -0700230 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700231
alshabibfd430b62015-12-16 18:56:38 -0800232 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700233
alshabibfd430b62015-12-16 18:56:38 -0800234 Optional<Instruction> vlanIntruction = instructions.stream()
235 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
236 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
237 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
238 ((L2ModificationInstruction) i).subtype() ==
239 L2ModificationInstruction.L2SubType.VLAN_POP)
240 .findAny();
241
242 if (!vlanIntruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100243 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700244 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100245 L2ModificationInstruction vlanIns =
246 (L2ModificationInstruction) vlanIntruction.get();
247
248 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
249 installUpstreamRules(fwd);
250 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
251 installDownstreamRules(fwd);
252 } else {
253 log.error("Unknown OLT operation: {}", fwd);
254 fail(fwd, ObjectiveError.UNSUPPORTED);
255 return;
256 }
alshabib0ccde6d2015-05-30 18:22:36 -0700257 }
258
alshabibfd430b62015-12-16 18:56:38 -0800259 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700260
alshabib0ccde6d2015-05-30 18:22:36 -0700261 }
262
alshabibd61b77b2016-02-01 23:30:53 -0800263
alshabib0ccde6d2015-05-30 18:22:36 -0700264 @Override
265 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800266 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
267 log.error("OLT only supports broadcast groups.");
268 fail(nextObjective, ObjectiveError.BADPARAMS);
269 }
270
271 if (nextObjective.next().size() != 1) {
272 log.error("OLT only supports singleton broadcast groups.");
273 fail(nextObjective, ObjectiveError.BADPARAMS);
274 }
275
276 TrafficTreatment treatment = nextObjective.next().stream().findFirst().get();
277
278
279 GroupBucket bucket = DefaultGroupBucket.createAllGroupBucket(treatment);
280 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
281
alshabib1aa58142016-02-17 15:37:56 -0800282
alshabibd61b77b2016-02-01 23:30:53 -0800283 pendingGroups.put(key, nextObjective);
284
285 switch (nextObjective.op()) {
286 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800287 GroupDescription groupDesc =
288 new DefaultGroupDescription(deviceId,
289 GroupDescription.Type.ALL,
290 new GroupBuckets(Collections.singletonList(bucket)),
291 key,
292 null,
293 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800294 groupService.addGroup(groupDesc);
295 break;
296 case REMOVE:
297 groupService.removeGroup(deviceId, key, nextObjective.appId());
298 break;
299 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800300 groupService.addBucketsToGroup(deviceId, key,
301 new GroupBuckets(Collections.singletonList(bucket)),
302 key, nextObjective.appId());
303 break;
alshabibd61b77b2016-02-01 23:30:53 -0800304 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800305 groupService.removeBucketsFromGroup(deviceId, key,
alshabib56efe432016-02-25 17:57:24 -0500306 new GroupBuckets(Collections.singletonList(bucket)),
307 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800308 break;
309 default:
310 log.warn("Unknown next objective operation: {}", nextObjective.op());
311 }
312
313
314 }
315
316 private void processMulticastRule(ForwardingObjective fwd) {
317 if (fwd.nextId() == null) {
318 log.error("Multicast objective does not have a next id");
319 fail(fwd, ObjectiveError.BADPARAMS);
320 }
321
alshabib1aa58142016-02-17 15:37:56 -0800322 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800323
alshabib1aa58142016-02-17 15:37:56 -0800324 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800325 log.error("Group for forwarding objective missing: {}", fwd);
326 fail(fwd, ObjectiveError.GROUPMISSING);
327 }
328
alshabib1aa58142016-02-17 15:37:56 -0800329 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800330 TrafficTreatment treatment =
331 buildTreatment(Instructions.createGroup(group.id()));
332
333 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700334 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800335 .forDevice(deviceId)
336 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800337 .makePermanent()
338 .withPriority(fwd.priority())
339 .withSelector(fwd.selector())
340 .withTreatment(treatment)
341 .build();
342
343 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
344 switch (fwd.op()) {
345
346 case ADD:
347 builder.add(rule);
348 break;
349 case REMOVE:
350 builder.remove(rule);
351 break;
352 case ADD_TO_EXISTING:
353 case REMOVE_FROM_EXISTING:
354 break;
355 default:
356 log.warn("Unknown forwarding operation: {}", fwd.op());
357 }
358
359 applyFlowRules(builder, fwd);
360
361 }
362
363 private boolean checkForMulticast(ForwardingObjective fwd) {
364
alshabib1aa58142016-02-17 15:37:56 -0800365 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500366 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800367
alshabib1aa58142016-02-17 15:37:56 -0800368 if (ip == null) {
369 return false;
370 }
371
Charles Chanaedabfd2016-02-26 09:31:48 -0800372 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800373
374 }
375
alshabib1aa58142016-02-17 15:37:56 -0800376 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800377 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800378 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800379
alshabib0ccde6d2015-05-30 18:22:36 -0700380 }
381
Amit Ghoshf1f22752018-08-14 07:28:01 +0100382 private void installNoModificationRules(ForwardingObjective fwd) {
383 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, "downstream");
384
385 TrafficSelector selector = fwd.selector();
386
387 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
388 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
389 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
390 Criterion metadata;
391
392 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
393 log.error("Forwarding objective is underspecified: {}", fwd);
394 fail(fwd, ObjectiveError.BADPARAMS);
395 return;
396 }
397
398 metadata = Criteria.matchMetadata(((VlanIdCriterion) innerVlan).vlanId().toShort());
399
400 FlowRule.Builder outer = DefaultFlowRule.builder()
401 .fromApp(fwd.appId())
402 .forDevice(deviceId)
403 .makePermanent()
404 .withPriority(fwd.priority())
405 .withSelector(buildSelector(inport, outerVlan, metadata))
406 .withTreatment(buildTreatment(output));
407
408 applyRules(fwd, outer);
409 }
410
alshabibfd430b62015-12-16 18:56:38 -0800411 private void installDownstreamRules(ForwardingObjective fwd) {
412 List<Pair<Instruction, Instruction>> vlanOps =
413 vlanOps(fwd,
414 L2ModificationInstruction.L2SubType.VLAN_POP);
415
416 if (vlanOps == null) {
417 return;
418 }
419
alshabibb3c14342016-03-04 17:05:01 -0800420 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, "downstream");
alshabibfd430b62015-12-16 18:56:38 -0800421
422 if (output == null) {
423 return;
424 }
425
426 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
427
alshabibfa0dc662016-01-13 11:23:53 -0800428 TrafficSelector selector = fwd.selector();
429
430 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
431 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
432 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
cboling651c6872018-10-05 11:09:22 -0500433
434 long cvid = ((VlanIdCriterion) innerVlan).vlanId().toShort();
435 long outPort = output.port().toLong() & 0x0FFFFFFFFL;
436
437 Criterion metadata = Criteria.matchMetadata((cvid << 32) | outPort);
alshabibfa0dc662016-01-13 11:23:53 -0800438
Ray Milkeyfe6afd82018-11-26 14:03:20 -0800439 if (outerVlan == null || inport == null) {
alshabibfa0dc662016-01-13 11:23:53 -0800440 log.error("Forwarding objective is underspecified: {}", fwd);
441 fail(fwd, ObjectiveError.BADPARAMS);
442 return;
443 }
444
alshabib2f74f2c2016-01-14 13:29:35 -0800445 Criterion innerVid = Criteria.matchVlanId(((VlanIdCriterion) innerVlan).vlanId());
446
alshabibfa0dc662016-01-13 11:23:53 -0800447 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700448 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800449 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800450 .makePermanent()
451 .withPriority(fwd.priority())
cboling651c6872018-10-05 11:09:22 -0500452 .withSelector(buildSelector(inport, outerVlan, metadata))
alshabibfd430b62015-12-16 18:56:38 -0800453 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
454 Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800455
alshabibfa0dc662016-01-13 11:23:53 -0800456 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700457 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800458 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800459 .forTable(QQ_TABLE)
460 .makePermanent()
461 .withPriority(fwd.priority())
alshabib2f74f2c2016-01-14 13:29:35 -0800462 .withSelector(buildSelector(inport, innerVid))
alshabibe5075842016-02-04 13:28:33 -0800463 .withTreatment(buildTreatment(popAndRewrite.getLeft(),
alshabibfd430b62015-12-16 18:56:38 -0800464 output));
465
466 applyRules(fwd, inner, outer);
467
468 }
469
470 private void installUpstreamRules(ForwardingObjective fwd) {
471 List<Pair<Instruction, Instruction>> vlanOps =
472 vlanOps(fwd,
473 L2ModificationInstruction.L2SubType.VLAN_PUSH);
474
475 if (vlanOps == null) {
476 return;
477 }
478
479 Instruction output = fetchOutput(fwd, "upstream");
480
481 if (output == null) {
482 return;
483 }
484
485 Pair<Instruction, Instruction> innerPair = vlanOps.remove(0);
486
487 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
488
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700489 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
490 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
491 boolean push = false;
492 if (vlanMatchCriterion != null) {
493 push = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
494 }
495
496 TrafficTreatment treatment;
497 if (push) {
498 treatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(),
499 Instructions.transition(QQ_TABLE));
500 } else {
501 treatment = buildTreatment(innerPair.getRight(), Instructions.transition(QQ_TABLE));
502 }
503
alshabibfd430b62015-12-16 18:56:38 -0800504 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700505 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800506 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800507 .makePermanent()
508 .withPriority(fwd.priority())
509 .withSelector(fwd.selector())
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700510 .withTreatment(treatment);
alshabibfd430b62015-12-16 18:56:38 -0800511
512 PortCriterion inPort = (PortCriterion)
513 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
514
515 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
516 innerPair.getRight()).vlanId();
517
518 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700519 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800520 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800521 .forTable(QQ_TABLE)
522 .makePermanent()
523 .withPriority(fwd.priority())
524 .withSelector(buildSelector(inPort,
525 Criteria.matchVlanId(cVlanId)))
526 .withTreatment(buildTreatment(outerPair.getLeft(),
527 outerPair.getRight(),
528 output));
529
530 applyRules(fwd, inner, outer);
531
532 }
533
534 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
535 Instruction output = fwd.treatment().allInstructions().stream()
536 .filter(i -> i.type() == Instruction.Type.OUTPUT)
537 .findFirst().orElse(null);
538
539 if (output == null) {
540 log.error("OLT {} rule has no output", direction);
541 fail(fwd, ObjectiveError.BADPARAMS);
542 return null;
543 }
544 return output;
545 }
546
547 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
548 L2ModificationInstruction.L2SubType type) {
549
550 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
551 fwd.treatment().allInstructions(), type);
552
553 if (vlanOps == null) {
554 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
555 ? "downstream" : "upstream";
556 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
557 fail(fwd, ObjectiveError.BADPARAMS);
558 return null;
559 }
560 return vlanOps;
561 }
562
563
564 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800565 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800566
567 List<Instruction> vlanPushs = findL2Instructions(
568 type,
569 instructions);
570 List<Instruction> vlanSets = findL2Instructions(
571 L2ModificationInstruction.L2SubType.VLAN_ID,
572 instructions);
573
574 if (vlanPushs.size() != vlanSets.size()) {
575 return null;
576 }
577
578 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
579
580 for (int i = 0; i < vlanPushs.size(); i++) {
581 pairs.add(new ImmutablePair<>(vlanPushs.get(i), vlanSets.get(i)));
582 }
583 return pairs;
584 }
585
586 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
587 List<Instruction> actions) {
588 return actions.stream()
589 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
590 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
591 .collect(Collectors.toList());
592 }
593
Amit Ghoshf1f22752018-08-14 07:28:01 +0100594 private void provisionEthTypeBasedFilter(FilteringObjective filter,
595 EthTypeCriterion ethType,
596 Instructions.OutputInstruction output) {
alshabibfd430b62015-12-16 18:56:38 -0800597
598 TrafficSelector selector = buildSelector(filter.key(), ethType);
599 TrafficTreatment treatment = buildTreatment(output);
600 buildAndApplyRule(filter, selector, treatment);
601
602 }
603
Jonathan Hart51539b82015-10-29 09:53:04 -0700604 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800605 IPProtocolCriterion ipProto,
606 Instructions.OutputInstruction output) {
607 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto);
608 TrafficTreatment treatment = buildTreatment(output);
609 buildAndApplyRule(filter, selector, treatment);
610 }
611
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000612 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
613 IPProtocolCriterion ipProto,
614 UdpPortCriterion udpSrcPort,
615 UdpPortCriterion udpDstPort,
616 Instructions.OutputInstruction output) {
617 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
618 TrafficTreatment treatment = buildTreatment(output);
619 buildAndApplyRule(filter, selector, treatment);
620 }
alshabibfd430b62015-12-16 18:56:38 -0800621 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
622 TrafficTreatment treatment) {
623 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700624 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800625 .forDevice(deviceId)
626 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800627 .makePermanent()
628 .withSelector(selector)
629 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800630 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800631 .build();
632
633 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
634
635 switch (filter.type()) {
636 case PERMIT:
637 opsBuilder.add(rule);
638 break;
639 case DENY:
640 opsBuilder.remove(rule);
641 break;
642 default:
643 log.warn("Unknown filter type : {}", filter.type());
644 fail(filter, ObjectiveError.UNSUPPORTED);
645 }
646
647 applyFlowRules(opsBuilder, filter);
648 }
649
650 private void applyRules(ForwardingObjective fwd,
Amit Ghoshf1f22752018-08-14 07:28:01 +0100651 FlowRule.Builder outer) {
652 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
653 switch (fwd.op()) {
654 case ADD:
655 builder.add(outer.build());
656 break;
657 case REMOVE:
658 builder.remove(outer.build());
659 break;
660 case ADD_TO_EXISTING:
661 break;
662 case REMOVE_FROM_EXISTING:
663 break;
664 default:
665 log.warn("Unknown forwarding operation: {}", fwd.op());
666 }
667
668 applyFlowRules(builder, fwd);
669 }
670
671 private void applyRules(ForwardingObjective fwd,
alshabibfd430b62015-12-16 18:56:38 -0800672 FlowRule.Builder inner, FlowRule.Builder outer) {
673 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
674 switch (fwd.op()) {
675 case ADD:
676 builder.add(inner.build()).add(outer.build());
677 break;
678 case REMOVE:
alshabibb05be2d2016-04-11 12:52:36 -0700679 builder.remove(inner.build()).remove(outer.build());
alshabibfd430b62015-12-16 18:56:38 -0800680 break;
681 case ADD_TO_EXISTING:
682 break;
683 case REMOVE_FROM_EXISTING:
684 break;
685 default:
686 log.warn("Unknown forwarding operation: {}", fwd.op());
687 }
688
689 applyFlowRules(builder, fwd);
690 }
691
692 private void applyFlowRules(FlowRuleOperations.Builder builder,
693 Objective objective) {
694 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
695 @Override
696 public void onSuccess(FlowRuleOperations ops) {
697 pass(objective);
698 }
699
700 @Override
701 public void onError(FlowRuleOperations ops) {
702 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
703 }
704 }));
705 }
706
707 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
708 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800709 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800710 .limit(1)
711 .findFirst().orElse(null);
712 }
713
714 private TrafficSelector buildSelector(Criterion... criteria) {
715
716
717 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
718
719 for (Criterion c : criteria) {
720 sBuilder.add(c);
721 }
722
723 return sBuilder.build();
724 }
725
726 private TrafficTreatment buildTreatment(Instruction... instructions) {
727
728
729 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
730
731 for (Instruction i : instructions) {
732 tBuilder.add(i);
733 }
734
735 return tBuilder.build();
736 }
737
738
739 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800740 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -0800741 }
742
743 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800744 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -0800745 }
746
alshabib2cc73cb2015-06-30 20:26:56 -0700747
alshabibd61b77b2016-02-01 23:30:53 -0800748 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -0700749 @Override
alshabibd61b77b2016-02-01 23:30:53 -0800750 public void event(GroupEvent event) {
ke hanf5086672016-08-12 11:09:17 +0800751 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
752 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -0800753 GroupKey key = event.subject().appCookie();
alshabib2cc73cb2015-06-30 20:26:56 -0700754
alshabibd61b77b2016-02-01 23:30:53 -0800755 NextObjective obj = pendingGroups.getIfPresent(key);
756 if (obj != null) {
757 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
758 pass(obj);
759 pendingGroups.invalidate(key);
760 }
761 }
alshabib2cc73cb2015-06-30 20:26:56 -0700762 }
763 }
764
alshabibd61b77b2016-02-01 23:30:53 -0800765 private static class OLTPipelineGroup implements NextGroup {
766
767 private final GroupKey key;
768
769 public OLTPipelineGroup(GroupKey key) {
770 this.key = key;
771 }
772
773 public GroupKey key() {
774 return key;
775 }
776
777 @Override
778 public byte[] data() {
779 return appKryo.serialize(key);
780 }
781
782 }
Saurav Das24431192016-03-07 19:13:00 -0800783
784 @Override
785 public List<String> getNextMappings(NextGroup nextGroup) {
786 // TODO Implementation deferred to vendor
787 return null;
788 }
alshabib0ccde6d2015-05-30 18:22:36 -0700789}