blob: 9afef9ad0c5bb11a2c8d1e435e473f0b33a5a7ed [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;
Gamze Abakadadae722018-09-12 10:55:35 +000022import com.google.common.collect.ImmutableList;
alshabibfd430b62015-12-16 18:56:38 -080023import com.google.common.collect.Lists;
24import org.apache.commons.lang3.tuple.ImmutablePair;
25import org.apache.commons.lang3.tuple.Pair;
alshabib0ccde6d2015-05-30 18:22:36 -070026import org.onlab.osgi.ServiceDirectory;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070027import org.onlab.packet.EthType;
alshabibfd430b62015-12-16 18:56:38 -080028import org.onlab.packet.IPv4;
Matteo Scandolo9f4f0072018-11-02 16:09:39 -070029import org.onlab.packet.IPv6;
Gamze Abakafe9d54f2019-12-02 06:42:39 +000030import org.onlab.packet.IpPrefix;
alshabibfd430b62015-12-16 18:56:38 -080031import org.onlab.packet.VlanId;
alshabibd61b77b2016-02-01 23:30:53 -080032import org.onlab.util.KryoNamespace;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
alshabib0ccde6d2015-05-30 18:22:36 -070035import org.onosproject.net.DeviceId;
36import org.onosproject.net.PortNumber;
alshabibd61b77b2016-02-01 23:30:53 -080037import org.onosproject.net.behaviour.NextGroup;
alshabib0ccde6d2015-05-30 18:22:36 -070038import org.onosproject.net.behaviour.Pipeliner;
39import org.onosproject.net.behaviour.PipelinerContext;
40import org.onosproject.net.driver.AbstractHandlerBehaviour;
41import org.onosproject.net.flow.DefaultFlowRule;
Jonathan Hartdfc3b862015-07-01 14:49:56 -070042import org.onosproject.net.flow.DefaultTrafficSelector;
alshabib0ccde6d2015-05-30 18:22:36 -070043import org.onosproject.net.flow.DefaultTrafficTreatment;
44import org.onosproject.net.flow.FlowRule;
45import org.onosproject.net.flow.FlowRuleOperations;
46import org.onosproject.net.flow.FlowRuleOperationsContext;
47import org.onosproject.net.flow.FlowRuleService;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flow.TrafficTreatment;
alshabibfd430b62015-12-16 18:56:38 -080050import org.onosproject.net.flow.criteria.Criteria;
51import org.onosproject.net.flow.criteria.Criterion;
52import org.onosproject.net.flow.criteria.EthTypeCriterion;
alshabib1aa58142016-02-17 15:37:56 -080053import org.onosproject.net.flow.criteria.IPCriterion;
alshabibfd430b62015-12-16 18:56:38 -080054import org.onosproject.net.flow.criteria.IPProtocolCriterion;
55import org.onosproject.net.flow.criteria.PortCriterion;
Amit Ghoshcbaf8672016-12-23 21:36:19 +000056import org.onosproject.net.flow.criteria.UdpPortCriterion;
alshabib2f74f2c2016-01-14 13:29:35 -080057import org.onosproject.net.flow.criteria.VlanIdCriterion;
alshabibfd430b62015-12-16 18:56:38 -080058import org.onosproject.net.flow.instructions.Instruction;
alshabib0ccde6d2015-05-30 18:22:36 -070059import org.onosproject.net.flow.instructions.Instructions;
alshabibfd430b62015-12-16 18:56:38 -080060import org.onosproject.net.flow.instructions.L2ModificationInstruction;
alshabib0ccde6d2015-05-30 18:22:36 -070061import org.onosproject.net.flowobjective.FilteringObjective;
alshabibd61b77b2016-02-01 23:30:53 -080062import org.onosproject.net.flowobjective.FlowObjectiveStore;
alshabib0ccde6d2015-05-30 18:22:36 -070063import org.onosproject.net.flowobjective.ForwardingObjective;
64import org.onosproject.net.flowobjective.NextObjective;
alshabibfd430b62015-12-16 18:56:38 -080065import org.onosproject.net.flowobjective.Objective;
alshabib0ccde6d2015-05-30 18:22:36 -070066import org.onosproject.net.flowobjective.ObjectiveError;
alshabibd61b77b2016-02-01 23:30:53 -080067import org.onosproject.net.group.DefaultGroupBucket;
68import org.onosproject.net.group.DefaultGroupDescription;
69import org.onosproject.net.group.DefaultGroupKey;
70import org.onosproject.net.group.Group;
71import org.onosproject.net.group.GroupBucket;
72import org.onosproject.net.group.GroupBuckets;
73import org.onosproject.net.group.GroupDescription;
74import org.onosproject.net.group.GroupEvent;
75import org.onosproject.net.group.GroupKey;
76import org.onosproject.net.group.GroupListener;
77import org.onosproject.net.group.GroupService;
78import org.onosproject.store.serializers.KryoNamespaces;
alshabib5ccbe3f2016-03-02 22:36:02 -080079import org.onosproject.store.service.StorageService;
alshabib0ccde6d2015-05-30 18:22:36 -070080import org.slf4j.Logger;
81
Gamze Abakafe9d54f2019-12-02 06:42:39 +000082import java.util.Arrays;
alshabibfd430b62015-12-16 18:56:38 -080083import java.util.Collection;
alshabibd61b77b2016-02-01 23:30:53 -080084import java.util.Collections;
alshabibfd430b62015-12-16 18:56:38 -080085import java.util.List;
Gamze Abakafe9d54f2019-12-02 06:42:39 +000086import java.util.Objects;
alshabibfd430b62015-12-16 18:56:38 -080087import java.util.Optional;
alshabibd61b77b2016-02-01 23:30:53 -080088import java.util.concurrent.TimeUnit;
alshabibfd430b62015-12-16 18:56:38 -080089import java.util.stream.Collectors;
90
alshabib0ccde6d2015-05-30 18:22:36 -070091import static org.slf4j.LoggerFactory.getLogger;
92
93/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070094 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070095 */
alshabibfd430b62015-12-16 18:56:38 -080096
Jonathan Hartb92cc512015-11-16 23:05:21 -080097public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070098
alshabibfd430b62015-12-16 18:56:38 -080099 private static final Integer QQ_TABLE = 1;
Gamze Abakadadae722018-09-12 10:55:35 +0000100 private static final int NO_ACTION_PRIORITY = 500;
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000101 private static final String DOWNSTREAM = "downstream";
102 private static final String UPSTREAM = "upstream";
alshabib0ccde6d2015-05-30 18:22:36 -0700103 private final Logger log = getLogger(getClass());
104
105 private ServiceDirectory serviceDirectory;
106 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800107 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700108 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800109 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700110
alshabibd61b77b2016-02-01 23:30:53 -0800111 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700112 private ApplicationId appId;
alshabib83364472016-03-25 09:59:55 -0700113
alshabib0ccde6d2015-05-30 18:22:36 -0700114
alshabibd61b77b2016-02-01 23:30:53 -0800115 protected FlowObjectiveStore flowObjectiveStore;
116
117 private Cache<GroupKey, NextObjective> pendingGroups;
118
119 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
120 .register(KryoNamespaces.API)
121 .register(GroupKey.class)
122 .register(DefaultGroupKey.class)
123 .register(OLTPipelineGroup.class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700124 .build("OltPipeline");
alshabib2cc73cb2015-06-30 20:26:56 -0700125
alshabib0ccde6d2015-05-30 18:22:36 -0700126 @Override
127 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800128 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700129 this.serviceDirectory = context.directory();
130 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800131
alshabib0ccde6d2015-05-30 18:22:36 -0700132 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700133 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800134 groupService = serviceDirectory.get(GroupService.class);
135 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800136 storageService = serviceDirectory.get(StorageService.class);
137
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700138 appId = coreService.registerApplication(
139 "org.onosproject.driver.OLTPipeline");
140
alshabibd61b77b2016-02-01 23:30:53 -0800141
142 pendingGroups = CacheBuilder.newBuilder()
143 .expireAfterWrite(20, TimeUnit.SECONDS)
144 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
145 if (notification.getCause() == RemovalCause.EXPIRED) {
146 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
147 }
148 }).build();
149
150 groupService.addListener(new InnerGroupListener());
151
alshabibb32cefe2015-06-08 18:15:05 -0700152 }
153
alshabib0ccde6d2015-05-30 18:22:36 -0700154 @Override
155 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800156 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700157
alshabibfd430b62015-12-16 18:56:38 -0800158 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
159 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
160 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
161 .limit(1)
162 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700163
alshabibbb424232016-01-15 12:20:25 -0800164 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
dvaddire8e6b89a2017-08-31 21:54:03 +0530165 log.warn("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800166 fail(filter, ObjectiveError.UNSUPPORTED);
167 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700168 }
alshabibfd430b62015-12-16 18:56:38 -0800169 } else {
170 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700171 return;
172 }
173
alshabibfd430b62015-12-16 18:56:38 -0800174 if (filter.key().type() != Criterion.Type.IN_PORT) {
175 fail(filter, ObjectiveError.BADPARAMS);
176 return;
177 }
178
179 EthTypeCriterion ethType = (EthTypeCriterion)
180 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
181
182 if (ethType == null) {
183 fail(filter, ObjectiveError.BADPARAMS);
184 return;
185 }
186
alshabibbb424232016-01-15 12:20:25 -0800187 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100188 provisionEthTypeBasedFilter(filter, ethType, output);
189 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType())) {
190 provisionEthTypeBasedFilter(filter, ethType, output);
191
alshabibbb424232016-01-15 12:20:25 -0800192 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800193 IPProtocolCriterion ipProto = (IPProtocolCriterion)
194 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530195 if (ipProto == null) {
196 log.warn("OLT can only filter IGMP and DHCP");
197 fail(filter, ObjectiveError.UNSUPPORTED);
198 return;
199 }
alshabibfd430b62015-12-16 18:56:38 -0800200 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700201 provisionIgmp(filter, ethType, ipProto, output);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000202 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
203 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
204 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
205
206 UdpPortCriterion udpDstPort = (UdpPortCriterion)
207 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
208
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700209 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
210 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
211 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, output);
212 } else {
213 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000214 fail(filter, ObjectiveError.UNSUPPORTED);
215 }
alshabibbb424232016-01-15 12:20:25 -0800216 } else {
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700217 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
218 fail(filter, ObjectiveError.UNSUPPORTED);
219 }
220 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
221 IPProtocolCriterion ipProto = (IPProtocolCriterion)
222 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
223 if (ipProto == null) {
224 log.warn("OLT can only filter DHCP");
225 fail(filter, ObjectiveError.UNSUPPORTED);
226 return;
227 }
228 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
229 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
230 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
231
232 UdpPortCriterion udpDstPort = (UdpPortCriterion)
233 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
234
235 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
236 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
237 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, output);
238 } else {
239 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
240 fail(filter, ObjectiveError.UNSUPPORTED);
241 }
242 } else {
243 log.warn("Currently supporting only DHCP filters for IPv6 packets");
alshabibbb424232016-01-15 12:20:25 -0800244 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800245 }
246 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530247 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100248 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700249 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
250 + "IPV6 TYPE: UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800251 fail(filter, ObjectiveError.UNSUPPORTED);
252 }
253
254 }
255
256
257 @Override
258 public void forward(ForwardingObjective fwd) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100259 log.debug("Installing forwarding objective {}", fwd);
alshabibd61b77b2016-02-01 23:30:53 -0800260 if (checkForMulticast(fwd)) {
261 processMulticastRule(fwd);
262 return;
263 }
264
alshabib0ccde6d2015-05-30 18:22:36 -0700265 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700266
alshabibfd430b62015-12-16 18:56:38 -0800267 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700268
Gamze Abakadadae722018-09-12 10:55:35 +0000269 Optional<Instruction> vlanInstruction = instructions.stream()
alshabibfd430b62015-12-16 18:56:38 -0800270 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
271 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
272 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
273 ((L2ModificationInstruction) i).subtype() ==
274 L2ModificationInstruction.L2SubType.VLAN_POP)
275 .findAny();
276
Gamze Abakadadae722018-09-12 10:55:35 +0000277
278 if (!vlanInstruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100279 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700280 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100281 L2ModificationInstruction vlanIns =
Gamze Abakadadae722018-09-12 10:55:35 +0000282 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshf1f22752018-08-14 07:28:01 +0100283 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
284 installUpstreamRules(fwd);
285 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
286 installDownstreamRules(fwd);
287 } else {
288 log.error("Unknown OLT operation: {}", fwd);
289 fail(fwd, ObjectiveError.UNSUPPORTED);
290 return;
291 }
alshabib0ccde6d2015-05-30 18:22:36 -0700292 }
293
alshabibfd430b62015-12-16 18:56:38 -0800294 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700295
alshabib0ccde6d2015-05-30 18:22:36 -0700296 }
297
alshabibd61b77b2016-02-01 23:30:53 -0800298
alshabib0ccde6d2015-05-30 18:22:36 -0700299 @Override
300 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800301 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
302 log.error("OLT only supports broadcast groups.");
303 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200304 return;
alshabibd61b77b2016-02-01 23:30:53 -0800305 }
306
Andrea Campanella5908b562020-05-06 16:09:10 +0200307 if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
alshabibd61b77b2016-02-01 23:30:53 -0800308 log.error("OLT only supports singleton broadcast groups.");
309 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200310 return;
alshabibd61b77b2016-02-01 23:30:53 -0800311 }
312
Andrea Campanella5908b562020-05-06 16:09:10 +0200313 Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
314 if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
315 log.error("Next objective {} does not have a treatment", nextObjective);
316 fail(nextObjective, ObjectiveError.BADPARAMS);
317 return;
318 }
alshabibd61b77b2016-02-01 23:30:53 -0800319
alshabibd61b77b2016-02-01 23:30:53 -0800320 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
321
alshabibd61b77b2016-02-01 23:30:53 -0800322 pendingGroups.put(key, nextObjective);
Andrea Campanella5908b562020-05-06 16:09:10 +0200323 log.trace("NextObjective Operation {}", nextObjective.op());
alshabibd61b77b2016-02-01 23:30:53 -0800324 switch (nextObjective.op()) {
325 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800326 GroupDescription groupDesc =
327 new DefaultGroupDescription(deviceId,
328 GroupDescription.Type.ALL,
Andrea Campanella5908b562020-05-06 16:09:10 +0200329 new GroupBuckets(
330 Collections.singletonList(
331 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800332 key,
333 null,
334 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800335 groupService.addGroup(groupDesc);
336 break;
337 case REMOVE:
338 groupService.removeGroup(deviceId, key, nextObjective.appId());
339 break;
340 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800341 groupService.addBucketsToGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200342 new GroupBuckets(
343 Collections.singletonList(
344 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800345 key, nextObjective.appId());
346 break;
alshabibd61b77b2016-02-01 23:30:53 -0800347 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800348 groupService.removeBucketsFromGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200349 new GroupBuckets(
350 Collections.singletonList(
351 buildBucket(treatmentOpt.get()))),
alshabib56efe432016-02-25 17:57:24 -0500352 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800353 break;
354 default:
355 log.warn("Unknown next objective operation: {}", nextObjective.op());
356 }
357
358
359 }
360
Andrea Campanella5908b562020-05-06 16:09:10 +0200361 private GroupBucket buildBucket(TrafficTreatment treatment) {
362 return DefaultGroupBucket.createAllGroupBucket(treatment);
363 }
364
alshabibd61b77b2016-02-01 23:30:53 -0800365 private void processMulticastRule(ForwardingObjective fwd) {
366 if (fwd.nextId() == null) {
367 log.error("Multicast objective does not have a next id");
368 fail(fwd, ObjectiveError.BADPARAMS);
369 }
370
alshabib1aa58142016-02-17 15:37:56 -0800371 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800372
alshabib1aa58142016-02-17 15:37:56 -0800373 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800374 log.error("Group for forwarding objective missing: {}", fwd);
375 fail(fwd, ObjectiveError.GROUPMISSING);
376 }
377
alshabib1aa58142016-02-17 15:37:56 -0800378 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800379 TrafficTreatment treatment =
380 buildTreatment(Instructions.createGroup(group.id()));
381
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000382 TrafficSelector.Builder selectorBuilder = buildIpv4SelectorForMulticast(fwd);
383
alshabibd61b77b2016-02-01 23:30:53 -0800384 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700385 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800386 .forDevice(deviceId)
387 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800388 .makePermanent()
389 .withPriority(fwd.priority())
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000390 .withSelector(selectorBuilder.build())
alshabibd61b77b2016-02-01 23:30:53 -0800391 .withTreatment(treatment)
392 .build();
393
394 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
395 switch (fwd.op()) {
396
397 case ADD:
398 builder.add(rule);
399 break;
400 case REMOVE:
401 builder.remove(rule);
402 break;
403 case ADD_TO_EXISTING:
404 case REMOVE_FROM_EXISTING:
405 break;
406 default:
407 log.warn("Unknown forwarding operation: {}", fwd.op());
408 }
409
410 applyFlowRules(builder, fwd);
411
412 }
413
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000414 private TrafficSelector.Builder buildIpv4SelectorForMulticast(ForwardingObjective fwd) {
415 TrafficSelector.Builder builderToUpdate = DefaultTrafficSelector.builder();
416
417 Optional<Criterion> vlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.VLAN_VID);
418 if (vlanIdCriterion.isPresent()) {
419 VlanId assignedVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
420 builderToUpdate.matchVlanId(assignedVlan);
421 }
422
Esin Karamanec25a0a2020-03-18 14:29:29 +0000423 Optional<Criterion> innerVlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.INNER_VLAN_VID);
424 if (innerVlanIdCriterion.isPresent()) {
425 VlanId assignedInnerVlan = ((VlanIdCriterion) innerVlanIdCriterion.get()).vlanId();
426 builderToUpdate.matchMetadata(assignedInnerVlan.toShort());
427 }
428
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000429 Optional<Criterion> ethTypeCriterion = readFromSelector(fwd.selector(), Criterion.Type.ETH_TYPE);
430 if (ethTypeCriterion.isPresent()) {
431 EthType ethType = ((EthTypeCriterion) ethTypeCriterion.get()).ethType();
432 builderToUpdate.matchEthType(ethType.toShort());
433 }
434
435 Optional<Criterion> ipv4DstCriterion = readFromSelector(fwd.selector(), Criterion.Type.IPV4_DST);
436 if (ipv4DstCriterion.isPresent()) {
437 IpPrefix ipv4Dst = ((IPCriterion) ipv4DstCriterion.get()).ip();
438 builderToUpdate.matchIPDst(ipv4Dst);
439 }
440
441 return builderToUpdate;
442 }
443
444 static Optional<Criterion> readFromSelector(TrafficSelector selector, Criterion.Type type) {
445 if (selector == null) {
446 return Optional.empty();
447 }
448 Criterion criterion = selector.getCriterion(type);
449 return (criterion == null)
450 ? Optional.empty() : Optional.of(criterion);
451 }
452
alshabibd61b77b2016-02-01 23:30:53 -0800453 private boolean checkForMulticast(ForwardingObjective fwd) {
454
alshabib1aa58142016-02-17 15:37:56 -0800455 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500456 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800457
alshabib1aa58142016-02-17 15:37:56 -0800458 if (ip == null) {
459 return false;
460 }
461
Charles Chanaedabfd2016-02-26 09:31:48 -0800462 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800463
464 }
465
alshabib1aa58142016-02-17 15:37:56 -0800466 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800467 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800468 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800469
alshabib0ccde6d2015-05-30 18:22:36 -0700470 }
471
Amit Ghoshf1f22752018-08-14 07:28:01 +0100472 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000473 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Gamze Abakaa34469f2019-04-19 08:30:16 +0000474 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
475 Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100476
477 TrafficSelector selector = fwd.selector();
478
479 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
480 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
481 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100482
483 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
484 log.error("Forwarding objective is underspecified: {}", fwd);
485 fail(fwd, ObjectiveError.BADPARAMS);
486 return;
487 }
488
Amit Ghoshf1f22752018-08-14 07:28:01 +0100489
490 FlowRule.Builder outer = DefaultFlowRule.builder()
491 .fromApp(fwd.appId())
492 .forDevice(deviceId)
493 .makePermanent()
494 .withPriority(fwd.priority())
Gamze Abakaa34469f2019-04-19 08:30:16 +0000495 .withSelector(buildSelector(inport, outerVlan))
496 .withTreatment(buildTreatment(output, writeMetadata, meter));
Amit Ghoshf1f22752018-08-14 07:28:01 +0100497
498 applyRules(fwd, outer);
499 }
500
alshabibfd430b62015-12-16 18:56:38 -0800501 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000502 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800503
504 if (output == null) {
505 return;
506 }
507
alshabibfa0dc662016-01-13 11:23:53 -0800508 TrafficSelector selector = fwd.selector();
509
510 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000511 Criterion outerPbit = selector.getCriterion(Criterion.Type.VLAN_PCP);
Gamze Abakadadae722018-09-12 10:55:35 +0000512 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
alshabibfa0dc662016-01-13 11:23:53 -0800513 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000514 Criterion dstMac = selector.getCriterion(Criterion.Type.ETH_DST);
cboling651c6872018-10-05 11:09:22 -0500515
Gamze Abakadadae722018-09-12 10:55:35 +0000516 if (outerVlan == null || innerVlanCriterion == null || inport == null) {
alshabibfa0dc662016-01-13 11:23:53 -0800517 log.error("Forwarding objective is underspecified: {}", fwd);
518 fail(fwd, ObjectiveError.BADPARAMS);
519 return;
520 }
521
Gamze Abakadadae722018-09-12 10:55:35 +0000522 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
523 Criterion innerVid = Criteria.matchVlanId(innerVlan);
alshabib2f74f2c2016-01-14 13:29:35 -0800524
Amit Ghosha6859982020-02-12 09:35:45 +0000525 // In the case where the C-tag is the same for all the subscribers,
526 // we add a metadata with the outport in the selector to make the flow unique
527 Criterion innerSelectorMeta = Criteria.matchMetadata(output.port().toLong());
528
Gamze Abakadadae722018-09-12 10:55:35 +0000529 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100530 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000531 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
Amit Ghosha6859982020-02-12 09:35:45 +0000532 Criteria.matchVlanId(VlanId.ANY), innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000533 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100534 // Required to differentiate the same match flows
535 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
536 // Metadata match criteria solves the conflict issue - but not used by the voltha
537 // Maybe - find a better way to solve the above problem
538 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
539 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Amit Ghosha6859982020-02-12 09:35:45 +0000540 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid,
541 innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000542 }
543 }
544
545 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
546 TrafficSelector outerSelector, TrafficSelector innerSelector) {
547
548 List<Pair<Instruction, Instruction>> vlanOps =
549 vlanOps(fwd,
550 L2ModificationInstruction.L2SubType.VLAN_POP);
551
552 if (vlanOps == null || vlanOps.isEmpty()) {
553 return;
554 }
555
556 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
557
558 TrafficTreatment innerTreatment;
559 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
560 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000561 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
562 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000563 } else {
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000564 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000565 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000566 }
567
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000568 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
569 fwd.treatment().allInstructions());
570
571 Instruction innerPbitSet = null;
572
573 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
574 innerPbitSet = setVlanPcps.get(0);
575 }
576
577 VlanId remarkInnerVlan = null;
578 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
579 if (vlanIdCriterion.isPresent()) {
580 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
581 }
582
583 Instruction modVlanId = null;
584 if (innerPbitSet != null) {
585 modVlanId = Instructions.modVlanId(remarkInnerVlan);
586 }
587
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000588 //match: in port (nni), s-tag
589 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800590 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700591 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800592 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800593 .makePermanent()
594 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000595 .withSelector(outerSelector)
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000596 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
597 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800598
Gamze Abakadadae722018-09-12 10:55:35 +0000599 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000600 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800601 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700602 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800603 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800604 .forTable(QQ_TABLE)
605 .makePermanent()
606 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000607 .withSelector(innerSelector)
608 .withTreatment(innerTreatment);
609 applyRules(fwd, inner, outer);
610 }
611
612 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
613 TrafficSelector outerSelector, TrafficSelector innerSelector) {
614
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000615 //match: in port (nni), s-tag
616 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000617 FlowRule.Builder outer = DefaultFlowRule.builder()
618 .fromApp(fwd.appId())
619 .forDevice(deviceId)
620 .makePermanent()
621 .withPriority(fwd.priority())
622 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000623 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
624 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000625
626 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000627 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000628 FlowRule.Builder inner = DefaultFlowRule.builder()
629 .fromApp(fwd.appId())
630 .forDevice(deviceId)
631 .forTable(QQ_TABLE)
632 .makePermanent()
633 .withPriority(fwd.priority())
634 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000635 .withTreatment(buildTreatment(fetchMeter(fwd),
636 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800637
638 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800639 }
640
641 private void installUpstreamRules(ForwardingObjective fwd) {
642 List<Pair<Instruction, Instruction>> vlanOps =
643 vlanOps(fwd,
644 L2ModificationInstruction.L2SubType.VLAN_PUSH);
645
Gamze Abakadadae722018-09-12 10:55:35 +0000646 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800647 return;
648 }
649
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000650 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800651
652 if (output == null) {
653 return;
654 }
655
alshabibfd430b62015-12-16 18:56:38 -0800656 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
657
Gamze Abakadadae722018-09-12 10:55:35 +0000658 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
659 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700660
Gamze Abakadadae722018-09-12 10:55:35 +0000661 if (anyValueVlanStatus) {
662 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
663 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100664 Pair<Instruction, Instruction> innerPair = outerPair;
665 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000666 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
667 }
668 }
669
670 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
671 Pair<Instruction, Instruction> innerPair,
672 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
673
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000674 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
675 fwd.treatment().allInstructions());
676
677 Instruction innerPbitSet = null;
678 Instruction outerPbitSet = null;
679
680 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
681 innerPbitSet = setVlanPcps.get(0);
682 outerPbitSet = setVlanPcps.get(1);
683 }
684
Gamze Abakadadae722018-09-12 10:55:35 +0000685 TrafficTreatment innerTreatment;
686 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000687 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000688 fetchWriteMetadata(fwd), innerPbitSet,
689 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700690 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000691 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000692 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700693 }
694
Gamze Abakadadae722018-09-12 10:55:35 +0000695 //match: in port, vlanId (0 or None)
696 //action:
697 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000698 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800699 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700700 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800701 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800702 .makePermanent()
703 .withPriority(fwd.priority())
704 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000705 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800706
707 PortCriterion inPort = (PortCriterion)
708 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
709
710 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
711 innerPair.getRight()).vlanId();
712
Gamze Abakadadae722018-09-12 10:55:35 +0000713 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000714 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800715 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700716 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800717 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800718 .forTable(QQ_TABLE)
719 .makePermanent()
720 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000721 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000722 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
723 outerPbitSet, output));
724
725 if (innerPbitSet != null) {
726 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
727 innerPbitSet).vlanPcp();
728 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
729 } else {
730 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
731 }
alshabibfd430b62015-12-16 18:56:38 -0800732
733 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000734 }
alshabibfd430b62015-12-16 18:56:38 -0800735
Gamze Abakadadae722018-09-12 10:55:35 +0000736 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
737 Pair<Instruction, Instruction> outerPair) {
738
739 log.debug("Installing upstream rules for any value vlan");
740
741 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000742 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000743 FlowRule.Builder inner = DefaultFlowRule.builder()
744 .fromApp(fwd.appId())
745 .forDevice(deviceId)
746 .makePermanent()
747 .withPriority(fwd.priority())
748 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000749 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
750 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000751
Gamze Abakadadae722018-09-12 10:55:35 +0000752 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000753 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000754 FlowRule.Builder outer = DefaultFlowRule.builder()
755 .fromApp(fwd.appId())
756 .forDevice(deviceId)
757 .forTable(QQ_TABLE)
758 .makePermanent()
759 .withPriority(fwd.priority())
760 .withSelector(fwd.selector())
Andrea Campanella6edac322020-01-29 14:41:42 +0100761 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000762 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000763
Andrea Campanella6edac322020-01-29 14:41:42 +0100764 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000765 }
766
767 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
768 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
769 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
770 boolean noneValueVlanStatus = false;
771 if (vlanMatchCriterion != null) {
772 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
773 }
774 return noneValueVlanStatus;
775 }
776
777 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
778 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
779 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
780 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
781 .findAny().orElse(null);
782
783 if (anyValueVlanCriterion == null) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100784 log.debug("Any value vlan match criteria is not found, criteria {}",
785 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000786 return false;
787 }
788
789 return true;
alshabibfd430b62015-12-16 18:56:38 -0800790 }
791
792 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
793 Instruction output = fwd.treatment().allInstructions().stream()
794 .filter(i -> i.type() == Instruction.Type.OUTPUT)
795 .findFirst().orElse(null);
796
797 if (output == null) {
798 log.error("OLT {} rule has no output", direction);
799 fail(fwd, ObjectiveError.BADPARAMS);
800 return null;
801 }
802 return output;
803 }
804
Gamze Abakadadae722018-09-12 10:55:35 +0000805 private Instruction fetchMeter(ForwardingObjective fwd) {
806 Instruction meter = fwd.treatment().metered();
807
808 if (meter == null) {
809 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
810 return null;
811 }
812
813 log.debug("Meter instruction is found.");
814 return meter;
815 }
816
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000817 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
818 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000819
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000820 if (writeMetadata == null) {
821 log.warn("Write metadata is not found for the forwarding obj");
822 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000823 return null;
824 }
825
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000826 log.debug("Write metadata is found {}", writeMetadata);
827 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000828 }
829
alshabibfd430b62015-12-16 18:56:38 -0800830 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
831 L2ModificationInstruction.L2SubType type) {
832
833 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
834 fwd.treatment().allInstructions(), type);
835
Gamze Abakadadae722018-09-12 10:55:35 +0000836 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800837 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000838 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800839 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
840 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000841 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800842 }
843 return vlanOps;
844 }
845
846
847 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800848 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800849
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000850 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800851 type,
852 instructions);
853 List<Instruction> vlanSets = findL2Instructions(
854 L2ModificationInstruction.L2SubType.VLAN_ID,
855 instructions);
856
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000857 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000858 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800859 }
860
861 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
862
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000863 for (int i = 0; i < vlanOperations.size(); i++) {
864 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800865 }
866 return pairs;
867 }
868
869 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
870 List<Instruction> actions) {
871 return actions.stream()
872 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
873 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
874 .collect(Collectors.toList());
875 }
876
Amit Ghoshf1f22752018-08-14 07:28:01 +0100877 private void provisionEthTypeBasedFilter(FilteringObjective filter,
878 EthTypeCriterion ethType,
879 Instructions.OutputInstruction output) {
alshabibfd430b62015-12-16 18:56:38 -0800880
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000881 Instruction meter = filter.meta().metered();
882 Instruction writeMetadata = filter.meta().writeMetadata();
883
Gamze Abakaf57ef602019-03-11 06:52:48 +0000884 Criterion vlanId = filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
885
886 TrafficSelector selector = buildSelector(filter.key(), ethType, vlanId);
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000887 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800888 buildAndApplyRule(filter, selector, treatment);
889
890 }
891
Jonathan Hart51539b82015-10-29 09:53:04 -0700892 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800893 IPProtocolCriterion ipProto,
894 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000895
896 Instruction meter = filter.meta().metered();
897 Instruction writeMetadata = filter.meta().writeMetadata();
898
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000899 // cTag
900 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
901 Criterion.Type.VLAN_VID);
902 Criterion cTagPriority = filterForCriterion(filter.conditions(), Criterion.Type.VLAN_PCP);
903
904 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId, cTagPriority);
Gamze Abaka7c070c82019-02-21 14:40:18 +0000905 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800906 buildAndApplyRule(filter, selector, treatment);
907 }
908
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000909 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
910 IPProtocolCriterion ipProto,
911 UdpPortCriterion udpSrcPort,
912 UdpPortCriterion udpDstPort,
913 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000914
915 Instruction meter = filter.meta().metered();
916 Instruction writeMetadata = filter.meta().writeMetadata();
917
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000918 VlanIdCriterion vlanId = (VlanIdCriterion)
919 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
920
921 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort, vlanId);
Gamze Abaka7c070c82019-02-21 14:40:18 +0000922 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000923 buildAndApplyRule(filter, selector, treatment);
924 }
Gamze Abakadadae722018-09-12 10:55:35 +0000925
alshabibfd430b62015-12-16 18:56:38 -0800926 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
927 TrafficTreatment treatment) {
928 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700929 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800930 .forDevice(deviceId)
931 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800932 .makePermanent()
933 .withSelector(selector)
934 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800935 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800936 .build();
937
938 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
939
940 switch (filter.type()) {
941 case PERMIT:
942 opsBuilder.add(rule);
943 break;
944 case DENY:
945 opsBuilder.remove(rule);
946 break;
947 default:
948 log.warn("Unknown filter type : {}", filter.type());
949 fail(filter, ObjectiveError.UNSUPPORTED);
950 }
951
952 applyFlowRules(opsBuilder, filter);
953 }
954
Gamze Abakadadae722018-09-12 10:55:35 +0000955 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100956 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
957 switch (fwd.op()) {
958 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +0000959 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
960 builder.add(fwdBuilder.build());
961 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100962 break;
963 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +0000964 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
965 builder.remove(fwdBuilder.build());
966 }
alshabibfd430b62015-12-16 18:56:38 -0800967 break;
968 case ADD_TO_EXISTING:
969 break;
970 case REMOVE_FROM_EXISTING:
971 break;
972 default:
973 log.warn("Unknown forwarding operation: {}", fwd.op());
974 }
975
976 applyFlowRules(builder, fwd);
977 }
978
979 private void applyFlowRules(FlowRuleOperations.Builder builder,
980 Objective objective) {
981 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
982 @Override
983 public void onSuccess(FlowRuleOperations ops) {
984 pass(objective);
985 }
986
987 @Override
988 public void onError(FlowRuleOperations ops) {
989 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
990 }
991 }));
992 }
993
994 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
995 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -0800996 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -0800997 .limit(1)
998 .findFirst().orElse(null);
999 }
1000
1001 private TrafficSelector buildSelector(Criterion... criteria) {
1002
alshabibfd430b62015-12-16 18:56:38 -08001003 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1004
Gamze Abakaf57ef602019-03-11 06:52:48 +00001005 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001006
1007 return sBuilder.build();
1008 }
1009
1010 private TrafficTreatment buildTreatment(Instruction... instructions) {
1011
alshabibfd430b62015-12-16 18:56:38 -08001012 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1013
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001014 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001015
1016 return tBuilder.build();
1017 }
1018
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001019 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1020
1021 return Instructions.writeMetadata(
1022 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1023 }
alshabibfd430b62015-12-16 18:56:38 -08001024
1025 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001026 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001027 }
1028
1029 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001030 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001031 }
1032
alshabib2cc73cb2015-06-30 20:26:56 -07001033
alshabibd61b77b2016-02-01 23:30:53 -08001034 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001035 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001036 public void event(GroupEvent event) {
Andrea Campanella5908b562020-05-06 16:09:10 +02001037 GroupKey key = event.subject().appCookie();
1038 NextObjective obj = pendingGroups.getIfPresent(key);
1039 if (obj == null) {
1040 log.debug("No pending group for {}, moving on", key);
1041 return;
1042 }
1043 log.trace("Event {} for group {}, handling pending" +
1044 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001045 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001046 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001047 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1048 pass(obj);
1049 pendingGroups.invalidate(key);
Andrea Campanella5908b562020-05-06 16:09:10 +02001050 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1051 flowObjectiveStore.removeNextGroup(obj.id());
1052 pass(obj);
1053 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001054 }
alshabib2cc73cb2015-06-30 20:26:56 -07001055 }
1056 }
1057
alshabibd61b77b2016-02-01 23:30:53 -08001058 private static class OLTPipelineGroup implements NextGroup {
1059
1060 private final GroupKey key;
1061
1062 public OLTPipelineGroup(GroupKey key) {
1063 this.key = key;
1064 }
1065
1066 public GroupKey key() {
1067 return key;
1068 }
1069
1070 @Override
1071 public byte[] data() {
1072 return appKryo.serialize(key);
1073 }
1074
1075 }
Saurav Das24431192016-03-07 19:13:00 -08001076
1077 @Override
1078 public List<String> getNextMappings(NextGroup nextGroup) {
1079 // TODO Implementation deferred to vendor
1080 return null;
1081 }
alshabib0ccde6d2015-05-30 18:22:36 -07001082}