blob: 62e438ad13e93ab7180e6712eff62ff1e60b73c5 [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
Andrea Campanella969e8af2020-07-09 11:39:08 +020091import static org.onosproject.core.CoreService.CORE_APP_NAME;
alshabib0ccde6d2015-05-30 18:22:36 -070092import static org.slf4j.LoggerFactory.getLogger;
93
94/**
Jonathan Hart64da69d2015-07-15 15:10:28 -070095 * Pipeliner for OLT device.
alshabib0ccde6d2015-05-30 18:22:36 -070096 */
alshabibfd430b62015-12-16 18:56:38 -080097
Jonathan Hartb92cc512015-11-16 23:05:21 -080098public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
alshabib0ccde6d2015-05-30 18:22:36 -070099
alshabibfd430b62015-12-16 18:56:38 -0800100 private static final Integer QQ_TABLE = 1;
Gamze Abakadadae722018-09-12 10:55:35 +0000101 private static final int NO_ACTION_PRIORITY = 500;
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000102 private static final String DOWNSTREAM = "downstream";
103 private static final String UPSTREAM = "upstream";
alshabib0ccde6d2015-05-30 18:22:36 -0700104 private final Logger log = getLogger(getClass());
105
106 private ServiceDirectory serviceDirectory;
107 private FlowRuleService flowRuleService;
alshabibd61b77b2016-02-01 23:30:53 -0800108 private GroupService groupService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700109 private CoreService coreService;
alshabib5ccbe3f2016-03-02 22:36:02 -0800110 private StorageService storageService;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700111
alshabibd61b77b2016-02-01 23:30:53 -0800112 private DeviceId deviceId;
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700113 private ApplicationId appId;
alshabib83364472016-03-25 09:59:55 -0700114
alshabib0ccde6d2015-05-30 18:22:36 -0700115
alshabibd61b77b2016-02-01 23:30:53 -0800116 protected FlowObjectiveStore flowObjectiveStore;
117
118 private Cache<GroupKey, NextObjective> pendingGroups;
119
120 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
121 .register(KryoNamespaces.API)
122 .register(GroupKey.class)
123 .register(DefaultGroupKey.class)
124 .register(OLTPipelineGroup.class)
Charles Chaneefdedf2016-05-23 16:45:45 -0700125 .build("OltPipeline");
alshabib2cc73cb2015-06-30 20:26:56 -0700126
alshabib0ccde6d2015-05-30 18:22:36 -0700127 @Override
128 public void init(DeviceId deviceId, PipelinerContext context) {
alshabibfd430b62015-12-16 18:56:38 -0800129 log.debug("Initiate OLT pipeline");
alshabib0ccde6d2015-05-30 18:22:36 -0700130 this.serviceDirectory = context.directory();
131 this.deviceId = deviceId;
alshabibd61b77b2016-02-01 23:30:53 -0800132
alshabib0ccde6d2015-05-30 18:22:36 -0700133 flowRuleService = serviceDirectory.get(FlowRuleService.class);
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700134 coreService = serviceDirectory.get(CoreService.class);
alshabibd61b77b2016-02-01 23:30:53 -0800135 groupService = serviceDirectory.get(GroupService.class);
136 flowObjectiveStore = context.store();
alshabib5ccbe3f2016-03-02 22:36:02 -0800137 storageService = serviceDirectory.get(StorageService.class);
138
Jonathan Hartdfc3b862015-07-01 14:49:56 -0700139 appId = coreService.registerApplication(
140 "org.onosproject.driver.OLTPipeline");
141
alshabibd61b77b2016-02-01 23:30:53 -0800142
143 pendingGroups = CacheBuilder.newBuilder()
144 .expireAfterWrite(20, TimeUnit.SECONDS)
145 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
146 if (notification.getCause() == RemovalCause.EXPIRED) {
147 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
148 }
149 }).build();
150
151 groupService.addListener(new InnerGroupListener());
152
alshabibb32cefe2015-06-08 18:15:05 -0700153 }
154
alshabib0ccde6d2015-05-30 18:22:36 -0700155 @Override
156 public void filter(FilteringObjective filter) {
alshabibfd430b62015-12-16 18:56:38 -0800157 Instructions.OutputInstruction output;
alshabib0ccde6d2015-05-30 18:22:36 -0700158
alshabibfd430b62015-12-16 18:56:38 -0800159 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
160 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
161 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
162 .limit(1)
163 .findFirst().get();
alshabib0ccde6d2015-05-30 18:22:36 -0700164
alshabibbb424232016-01-15 12:20:25 -0800165 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
dvaddire8e6b89a2017-08-31 21:54:03 +0530166 log.warn("OLT can only filter packet to controller");
alshabibfd430b62015-12-16 18:56:38 -0800167 fail(filter, ObjectiveError.UNSUPPORTED);
168 return;
alshabib0ccde6d2015-05-30 18:22:36 -0700169 }
alshabibfd430b62015-12-16 18:56:38 -0800170 } else {
171 fail(filter, ObjectiveError.BADPARAMS);
alshabib0ccde6d2015-05-30 18:22:36 -0700172 return;
173 }
174
alshabibfd430b62015-12-16 18:56:38 -0800175 if (filter.key().type() != Criterion.Type.IN_PORT) {
176 fail(filter, ObjectiveError.BADPARAMS);
177 return;
178 }
179
180 EthTypeCriterion ethType = (EthTypeCriterion)
181 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
182
183 if (ethType == null) {
184 fail(filter, ObjectiveError.BADPARAMS);
185 return;
186 }
187
alshabibbb424232016-01-15 12:20:25 -0800188 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100189 provisionEthTypeBasedFilter(filter, ethType, output);
190 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType())) {
191 provisionEthTypeBasedFilter(filter, ethType, output);
192
alshabibbb424232016-01-15 12:20:25 -0800193 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
alshabibfd430b62015-12-16 18:56:38 -0800194 IPProtocolCriterion ipProto = (IPProtocolCriterion)
195 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
dvaddire8e6b89a2017-08-31 21:54:03 +0530196 if (ipProto == null) {
197 log.warn("OLT can only filter IGMP and DHCP");
198 fail(filter, ObjectiveError.UNSUPPORTED);
199 return;
200 }
alshabibfd430b62015-12-16 18:56:38 -0800201 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
Jonathan Hart51539b82015-10-29 09:53:04 -0700202 provisionIgmp(filter, ethType, ipProto, output);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000203 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
204 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
205 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
206
207 UdpPortCriterion udpDstPort = (UdpPortCriterion)
208 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
209
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700210 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
211 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
212 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, output);
213 } else {
214 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000215 fail(filter, ObjectiveError.UNSUPPORTED);
216 }
alshabibbb424232016-01-15 12:20:25 -0800217 } else {
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700218 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
219 fail(filter, ObjectiveError.UNSUPPORTED);
220 }
221 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
222 IPProtocolCriterion ipProto = (IPProtocolCriterion)
223 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
224 if (ipProto == null) {
225 log.warn("OLT can only filter DHCP");
226 fail(filter, ObjectiveError.UNSUPPORTED);
227 return;
228 }
229 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
230 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
231 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
232
233 UdpPortCriterion udpDstPort = (UdpPortCriterion)
234 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
235
236 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
237 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
238 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, output);
239 } else {
240 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
241 fail(filter, ObjectiveError.UNSUPPORTED);
242 }
243 } else {
244 log.warn("Currently supporting only DHCP filters for IPv6 packets");
alshabibbb424232016-01-15 12:20:25 -0800245 fail(filter, ObjectiveError.UNSUPPORTED);
alshabibfd430b62015-12-16 18:56:38 -0800246 }
247 } else {
dvaddire8e6b89a2017-08-31 21:54:03 +0530248 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
Amit Ghoshf1f22752018-08-14 07:28:01 +0100249 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
Matteo Scandolo9f4f0072018-11-02 16:09:39 -0700250 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
251 + "IPV6 TYPE: UDP (for DHCP)");
alshabibfd430b62015-12-16 18:56:38 -0800252 fail(filter, ObjectiveError.UNSUPPORTED);
253 }
254
255 }
256
257
258 @Override
259 public void forward(ForwardingObjective fwd) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100260 log.debug("Installing forwarding objective {}", fwd);
alshabibd61b77b2016-02-01 23:30:53 -0800261 if (checkForMulticast(fwd)) {
262 processMulticastRule(fwd);
263 return;
264 }
265
alshabib0ccde6d2015-05-30 18:22:36 -0700266 TrafficTreatment treatment = fwd.treatment();
alshabib0ccde6d2015-05-30 18:22:36 -0700267
alshabibfd430b62015-12-16 18:56:38 -0800268 List<Instruction> instructions = treatment.allInstructions();
alshabib0ccde6d2015-05-30 18:22:36 -0700269
Gamze Abakadadae722018-09-12 10:55:35 +0000270 Optional<Instruction> vlanInstruction = instructions.stream()
alshabibfd430b62015-12-16 18:56:38 -0800271 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
272 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
273 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
274 ((L2ModificationInstruction) i).subtype() ==
275 L2ModificationInstruction.L2SubType.VLAN_POP)
276 .findAny();
277
Gamze Abakadadae722018-09-12 10:55:35 +0000278
279 if (!vlanInstruction.isPresent()) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100280 installNoModificationRules(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700281 } else {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100282 L2ModificationInstruction vlanIns =
Gamze Abakadadae722018-09-12 10:55:35 +0000283 (L2ModificationInstruction) vlanInstruction.get();
Amit Ghoshf1f22752018-08-14 07:28:01 +0100284 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
285 installUpstreamRules(fwd);
286 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
287 installDownstreamRules(fwd);
288 } else {
289 log.error("Unknown OLT operation: {}", fwd);
290 fail(fwd, ObjectiveError.UNSUPPORTED);
291 return;
292 }
alshabib0ccde6d2015-05-30 18:22:36 -0700293 }
294
alshabibfd430b62015-12-16 18:56:38 -0800295 pass(fwd);
alshabib0ccde6d2015-05-30 18:22:36 -0700296
alshabib0ccde6d2015-05-30 18:22:36 -0700297 }
298
alshabibd61b77b2016-02-01 23:30:53 -0800299
alshabib0ccde6d2015-05-30 18:22:36 -0700300 @Override
301 public void next(NextObjective nextObjective) {
alshabibd61b77b2016-02-01 23:30:53 -0800302 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
303 log.error("OLT only supports broadcast groups.");
304 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200305 return;
alshabibd61b77b2016-02-01 23:30:53 -0800306 }
307
Andrea Campanella5908b562020-05-06 16:09:10 +0200308 if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
alshabibd61b77b2016-02-01 23:30:53 -0800309 log.error("OLT only supports singleton broadcast groups.");
310 fail(nextObjective, ObjectiveError.BADPARAMS);
Andrea Campanella5908b562020-05-06 16:09:10 +0200311 return;
alshabibd61b77b2016-02-01 23:30:53 -0800312 }
313
Andrea Campanella5908b562020-05-06 16:09:10 +0200314 Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
315 if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
316 log.error("Next objective {} does not have a treatment", nextObjective);
317 fail(nextObjective, ObjectiveError.BADPARAMS);
318 return;
319 }
alshabibd61b77b2016-02-01 23:30:53 -0800320
alshabibd61b77b2016-02-01 23:30:53 -0800321 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
322
alshabibd61b77b2016-02-01 23:30:53 -0800323 pendingGroups.put(key, nextObjective);
Andrea Campanella5908b562020-05-06 16:09:10 +0200324 log.trace("NextObjective Operation {}", nextObjective.op());
alshabibd61b77b2016-02-01 23:30:53 -0800325 switch (nextObjective.op()) {
326 case ADD:
alshabib1aa58142016-02-17 15:37:56 -0800327 GroupDescription groupDesc =
328 new DefaultGroupDescription(deviceId,
329 GroupDescription.Type.ALL,
Andrea Campanella5908b562020-05-06 16:09:10 +0200330 new GroupBuckets(
331 Collections.singletonList(
332 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800333 key,
334 null,
335 nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800336 groupService.addGroup(groupDesc);
337 break;
338 case REMOVE:
339 groupService.removeGroup(deviceId, key, nextObjective.appId());
340 break;
341 case ADD_TO_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800342 groupService.addBucketsToGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200343 new GroupBuckets(
344 Collections.singletonList(
345 buildBucket(treatmentOpt.get()))),
alshabib1aa58142016-02-17 15:37:56 -0800346 key, nextObjective.appId());
347 break;
alshabibd61b77b2016-02-01 23:30:53 -0800348 case REMOVE_FROM_EXISTING:
alshabib1aa58142016-02-17 15:37:56 -0800349 groupService.removeBucketsFromGroup(deviceId, key,
Andrea Campanella5908b562020-05-06 16:09:10 +0200350 new GroupBuckets(
351 Collections.singletonList(
352 buildBucket(treatmentOpt.get()))),
alshabib56efe432016-02-25 17:57:24 -0500353 key, nextObjective.appId());
alshabibd61b77b2016-02-01 23:30:53 -0800354 break;
355 default:
356 log.warn("Unknown next objective operation: {}", nextObjective.op());
357 }
358
359
360 }
361
Andrea Campanella5908b562020-05-06 16:09:10 +0200362 private GroupBucket buildBucket(TrafficTreatment treatment) {
363 return DefaultGroupBucket.createAllGroupBucket(treatment);
364 }
365
alshabibd61b77b2016-02-01 23:30:53 -0800366 private void processMulticastRule(ForwardingObjective fwd) {
367 if (fwd.nextId() == null) {
368 log.error("Multicast objective does not have a next id");
369 fail(fwd, ObjectiveError.BADPARAMS);
370 }
371
alshabib1aa58142016-02-17 15:37:56 -0800372 GroupKey key = getGroupForNextObjective(fwd.nextId());
alshabibd61b77b2016-02-01 23:30:53 -0800373
alshabib1aa58142016-02-17 15:37:56 -0800374 if (key == null) {
alshabibd61b77b2016-02-01 23:30:53 -0800375 log.error("Group for forwarding objective missing: {}", fwd);
376 fail(fwd, ObjectiveError.GROUPMISSING);
377 }
378
alshabib1aa58142016-02-17 15:37:56 -0800379 Group group = groupService.getGroup(deviceId, key);
alshabibd61b77b2016-02-01 23:30:53 -0800380 TrafficTreatment treatment =
381 buildTreatment(Instructions.createGroup(group.id()));
382
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000383 TrafficSelector.Builder selectorBuilder = buildIpv4SelectorForMulticast(fwd);
384
alshabibd61b77b2016-02-01 23:30:53 -0800385 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700386 .fromApp(fwd.appId())
alshabibd61b77b2016-02-01 23:30:53 -0800387 .forDevice(deviceId)
388 .forTable(0)
alshabibd61b77b2016-02-01 23:30:53 -0800389 .makePermanent()
390 .withPriority(fwd.priority())
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000391 .withSelector(selectorBuilder.build())
alshabibd61b77b2016-02-01 23:30:53 -0800392 .withTreatment(treatment)
393 .build();
394
395 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
396 switch (fwd.op()) {
397
398 case ADD:
399 builder.add(rule);
400 break;
401 case REMOVE:
402 builder.remove(rule);
403 break;
404 case ADD_TO_EXISTING:
405 case REMOVE_FROM_EXISTING:
406 break;
407 default:
408 log.warn("Unknown forwarding operation: {}", fwd.op());
409 }
410
411 applyFlowRules(builder, fwd);
412
413 }
414
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000415 private TrafficSelector.Builder buildIpv4SelectorForMulticast(ForwardingObjective fwd) {
416 TrafficSelector.Builder builderToUpdate = DefaultTrafficSelector.builder();
417
418 Optional<Criterion> vlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.VLAN_VID);
419 if (vlanIdCriterion.isPresent()) {
420 VlanId assignedVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
421 builderToUpdate.matchVlanId(assignedVlan);
422 }
423
Esin Karamanec25a0a2020-03-18 14:29:29 +0000424 Optional<Criterion> innerVlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.INNER_VLAN_VID);
425 if (innerVlanIdCriterion.isPresent()) {
426 VlanId assignedInnerVlan = ((VlanIdCriterion) innerVlanIdCriterion.get()).vlanId();
427 builderToUpdate.matchMetadata(assignedInnerVlan.toShort());
428 }
429
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000430 Optional<Criterion> ethTypeCriterion = readFromSelector(fwd.selector(), Criterion.Type.ETH_TYPE);
431 if (ethTypeCriterion.isPresent()) {
432 EthType ethType = ((EthTypeCriterion) ethTypeCriterion.get()).ethType();
433 builderToUpdate.matchEthType(ethType.toShort());
434 }
435
436 Optional<Criterion> ipv4DstCriterion = readFromSelector(fwd.selector(), Criterion.Type.IPV4_DST);
437 if (ipv4DstCriterion.isPresent()) {
438 IpPrefix ipv4Dst = ((IPCriterion) ipv4DstCriterion.get()).ip();
439 builderToUpdate.matchIPDst(ipv4Dst);
440 }
441
442 return builderToUpdate;
443 }
444
445 static Optional<Criterion> readFromSelector(TrafficSelector selector, Criterion.Type type) {
446 if (selector == null) {
447 return Optional.empty();
448 }
449 Criterion criterion = selector.getCriterion(type);
450 return (criterion == null)
451 ? Optional.empty() : Optional.of(criterion);
452 }
453
alshabibd61b77b2016-02-01 23:30:53 -0800454 private boolean checkForMulticast(ForwardingObjective fwd) {
455
alshabib1aa58142016-02-17 15:37:56 -0800456 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
alshabib56efe432016-02-25 17:57:24 -0500457 Criterion.Type.IPV4_DST);
alshabibd61b77b2016-02-01 23:30:53 -0800458
alshabib1aa58142016-02-17 15:37:56 -0800459 if (ip == null) {
460 return false;
461 }
462
Charles Chanaedabfd2016-02-26 09:31:48 -0800463 return ip.ip().isMulticast();
alshabibd61b77b2016-02-01 23:30:53 -0800464
465 }
466
alshabib1aa58142016-02-17 15:37:56 -0800467 private GroupKey getGroupForNextObjective(Integer nextId) {
alshabibd61b77b2016-02-01 23:30:53 -0800468 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
alshabib1aa58142016-02-17 15:37:56 -0800469 return appKryo.deserialize(next.data());
alshabibd61b77b2016-02-01 23:30:53 -0800470
alshabib0ccde6d2015-05-30 18:22:36 -0700471 }
472
Amit Ghoshf1f22752018-08-14 07:28:01 +0100473 private void installNoModificationRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000474 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
Gamze Abakaa34469f2019-04-19 08:30:16 +0000475 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
476 Instructions.MeterInstruction meter = (Instructions.MeterInstruction) fetchMeter(fwd);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100477
478 TrafficSelector selector = fwd.selector();
479
480 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
481 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
482 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
Amit Ghoshf1f22752018-08-14 07:28:01 +0100483
484 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
Andrea Campanella969e8af2020-07-09 11:39:08 +0200485 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
486 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
487 log.error("Forwarding objective is underspecified: {}", fwd);
488 } else {
489 log.debug("Not installing unsupported core generated flow {}", fwd);
490 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100491 fail(fwd, ObjectiveError.BADPARAMS);
492 return;
493 }
494
Amit Ghoshf1f22752018-08-14 07:28:01 +0100495
496 FlowRule.Builder outer = DefaultFlowRule.builder()
497 .fromApp(fwd.appId())
498 .forDevice(deviceId)
499 .makePermanent()
500 .withPriority(fwd.priority())
Gamze Abakaa34469f2019-04-19 08:30:16 +0000501 .withSelector(buildSelector(inport, outerVlan))
502 .withTreatment(buildTreatment(output, writeMetadata, meter));
Amit Ghoshf1f22752018-08-14 07:28:01 +0100503
504 applyRules(fwd, outer);
505 }
506
alshabibfd430b62015-12-16 18:56:38 -0800507 private void installDownstreamRules(ForwardingObjective fwd) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000508 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800509
510 if (output == null) {
511 return;
512 }
513
alshabibfa0dc662016-01-13 11:23:53 -0800514 TrafficSelector selector = fwd.selector();
515
516 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000517 Criterion outerPbit = selector.getCriterion(Criterion.Type.VLAN_PCP);
Gamze Abakadadae722018-09-12 10:55:35 +0000518 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
alshabibfa0dc662016-01-13 11:23:53 -0800519 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000520 Criterion dstMac = selector.getCriterion(Criterion.Type.ETH_DST);
cboling651c6872018-10-05 11:09:22 -0500521
Gamze Abakadadae722018-09-12 10:55:35 +0000522 if (outerVlan == null || innerVlanCriterion == null || inport == null) {
Andrea Campanella969e8af2020-07-09 11:39:08 +0200523 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
524 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
525 log.error("Forwarding objective is underspecified: {}", fwd);
526 } else {
527 log.debug("Not installing unsupported core generated flow {}", fwd);
528 }
alshabibfa0dc662016-01-13 11:23:53 -0800529 fail(fwd, ObjectiveError.BADPARAMS);
530 return;
531 }
532
Gamze Abakadadae722018-09-12 10:55:35 +0000533 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
534 Criterion innerVid = Criteria.matchVlanId(innerVlan);
alshabib2f74f2c2016-01-14 13:29:35 -0800535
Amit Ghosha6859982020-02-12 09:35:45 +0000536 // In the case where the C-tag is the same for all the subscribers,
537 // we add a metadata with the outport in the selector to make the flow unique
538 Criterion innerSelectorMeta = Criteria.matchMetadata(output.port().toLong());
539
Gamze Abakadadae722018-09-12 10:55:35 +0000540 if (innerVlan.toShort() == VlanId.ANY_VALUE) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100541 TrafficSelector outerSelector = buildSelector(inport, outerVlan, outerPbit, dstMac);
Gamze Abakadadae722018-09-12 10:55:35 +0000542 installDownstreamRulesForAnyVlan(fwd, output, outerSelector, buildSelector(inport,
Amit Ghosha6859982020-02-12 09:35:45 +0000543 Criteria.matchVlanId(VlanId.ANY), innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000544 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100545 // Required to differentiate the same match flows
546 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
547 // Metadata match criteria solves the conflict issue - but not used by the voltha
548 // Maybe - find a better way to solve the above problem
549 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
550 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlan, outerPbit, dstMac);
Amit Ghosha6859982020-02-12 09:35:45 +0000551 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid,
552 innerSelectorMeta));
Gamze Abakadadae722018-09-12 10:55:35 +0000553 }
554 }
555
556 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
557 TrafficSelector outerSelector, TrafficSelector innerSelector) {
558
559 List<Pair<Instruction, Instruction>> vlanOps =
560 vlanOps(fwd,
561 L2ModificationInstruction.L2SubType.VLAN_POP);
562
563 if (vlanOps == null || vlanOps.isEmpty()) {
564 return;
565 }
566
567 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
568
569 TrafficTreatment innerTreatment;
570 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
571 if (VlanId.NONE.equals(setVlanId)) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000572 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), fetchMeter(fwd),
573 writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000574 } else {
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000575 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000576 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000577 }
578
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000579 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
580 fwd.treatment().allInstructions());
581
582 Instruction innerPbitSet = null;
583
584 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
585 innerPbitSet = setVlanPcps.get(0);
586 }
587
588 VlanId remarkInnerVlan = null;
589 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
590 if (vlanIdCriterion.isPresent()) {
591 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
592 }
593
594 Instruction modVlanId = null;
595 if (innerPbitSet != null) {
596 modVlanId = Instructions.modVlanId(remarkInnerVlan);
597 }
598
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000599 //match: in port (nni), s-tag
600 //action: pop vlan (s-tag), write metadata, go to table 1, meter
alshabibfa0dc662016-01-13 11:23:53 -0800601 FlowRule.Builder outer = 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 .makePermanent()
605 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000606 .withSelector(outerSelector)
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000607 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
608 innerPbitSet, fetchMeter(fwd), fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
alshabibfd430b62015-12-16 18:56:38 -0800609
Gamze Abakadadae722018-09-12 10:55:35 +0000610 //match: in port (nni), c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000611 //action: immediate: write metadata and pop, meter, output
alshabibfa0dc662016-01-13 11:23:53 -0800612 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700613 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800614 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800615 .forTable(QQ_TABLE)
616 .makePermanent()
617 .withPriority(fwd.priority())
Gamze Abakadadae722018-09-12 10:55:35 +0000618 .withSelector(innerSelector)
619 .withTreatment(innerTreatment);
620 applyRules(fwd, inner, outer);
621 }
622
623 private void installDownstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
624 TrafficSelector outerSelector, TrafficSelector innerSelector) {
625
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000626 //match: in port (nni), s-tag
627 //action: immediate: write metadata, pop vlan, meter and go to table 1
Gamze Abakadadae722018-09-12 10:55:35 +0000628 FlowRule.Builder outer = DefaultFlowRule.builder()
629 .fromApp(fwd.appId())
630 .forDevice(deviceId)
631 .makePermanent()
632 .withPriority(fwd.priority())
633 .withSelector(outerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000634 .withTreatment(buildTreatment(Instructions.popVlan(), fetchMeter(fwd),
635 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
Gamze Abakadadae722018-09-12 10:55:35 +0000636
637 //match: in port (nni) and s-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000638 //action: immediate : write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000639 FlowRule.Builder inner = DefaultFlowRule.builder()
640 .fromApp(fwd.appId())
641 .forDevice(deviceId)
642 .forTable(QQ_TABLE)
643 .makePermanent()
644 .withPriority(fwd.priority())
645 .withSelector(innerSelector)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000646 .withTreatment(buildTreatment(fetchMeter(fwd),
647 writeMetadataIncludingOnlyTp(fwd), output));
alshabibfd430b62015-12-16 18:56:38 -0800648
649 applyRules(fwd, inner, outer);
alshabibfd430b62015-12-16 18:56:38 -0800650 }
651
652 private void installUpstreamRules(ForwardingObjective fwd) {
653 List<Pair<Instruction, Instruction>> vlanOps =
654 vlanOps(fwd,
655 L2ModificationInstruction.L2SubType.VLAN_PUSH);
656
Gamze Abakadadae722018-09-12 10:55:35 +0000657 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800658 return;
659 }
660
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000661 Instruction output = fetchOutput(fwd, UPSTREAM);
alshabibfd430b62015-12-16 18:56:38 -0800662
663 if (output == null) {
664 return;
665 }
666
alshabibfd430b62015-12-16 18:56:38 -0800667 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
668
Gamze Abakadadae722018-09-12 10:55:35 +0000669 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
670 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700671
Gamze Abakadadae722018-09-12 10:55:35 +0000672 if (anyValueVlanStatus) {
673 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
674 } else {
Andrea Campanella6edac322020-01-29 14:41:42 +0100675 Pair<Instruction, Instruction> innerPair = outerPair;
676 outerPair = vlanOps.remove(0);
Gamze Abakadadae722018-09-12 10:55:35 +0000677 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
678 }
679 }
680
681 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
682 Pair<Instruction, Instruction> innerPair,
683 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
684
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000685 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
686 fwd.treatment().allInstructions());
687
688 Instruction innerPbitSet = null;
689 Instruction outerPbitSet = null;
690
691 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
692 innerPbitSet = setVlanPcps.get(0);
693 outerPbitSet = setVlanPcps.get(1);
694 }
695
Gamze Abakadadae722018-09-12 10:55:35 +0000696 TrafficTreatment innerTreatment;
697 if (noneValueVlanStatus) {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000698 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), fetchMeter(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000699 fetchWriteMetadata(fwd), innerPbitSet,
700 Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700701 } else {
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000702 innerTreatment = buildTreatment(innerPair.getRight(), fetchMeter(fwd), fetchWriteMetadata(fwd),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000703 innerPbitSet, Instructions.transition(QQ_TABLE));
Jonathan Hart3dc474c2018-08-15 18:15:45 -0700704 }
705
Gamze Abakadadae722018-09-12 10:55:35 +0000706 //match: in port, vlanId (0 or None)
707 //action:
708 //if vlanId None, push & set c-tag go to table 1
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000709 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
alshabibfd430b62015-12-16 18:56:38 -0800710 FlowRule.Builder inner = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700711 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800712 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800713 .makePermanent()
714 .withPriority(fwd.priority())
715 .withSelector(fwd.selector())
Gamze Abakadadae722018-09-12 10:55:35 +0000716 .withTreatment(innerTreatment);
alshabibfd430b62015-12-16 18:56:38 -0800717
718 PortCriterion inPort = (PortCriterion)
719 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
720
721 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
722 innerPair.getRight()).vlanId();
723
Gamze Abakadadae722018-09-12 10:55:35 +0000724 //match: in port, c-tag
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000725 //action: immediate: push s-tag, write metadata, meter and output
alshabibfd430b62015-12-16 18:56:38 -0800726 FlowRule.Builder outer = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700727 .fromApp(fwd.appId())
alshabibfd430b62015-12-16 18:56:38 -0800728 .forDevice(deviceId)
alshabibfd430b62015-12-16 18:56:38 -0800729 .forTable(QQ_TABLE)
730 .makePermanent()
731 .withPriority(fwd.priority())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000732 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000733 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd),
734 outerPbitSet, output));
735
736 if (innerPbitSet != null) {
737 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
738 innerPbitSet).vlanPcp();
739 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
740 } else {
741 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
742 }
alshabibfd430b62015-12-16 18:56:38 -0800743
744 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000745 }
alshabibfd430b62015-12-16 18:56:38 -0800746
Gamze Abakadadae722018-09-12 10:55:35 +0000747 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
748 Pair<Instruction, Instruction> outerPair) {
749
750 log.debug("Installing upstream rules for any value vlan");
751
752 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000753 //action: write metadata, go to table 1 and meter
Gamze Abakadadae722018-09-12 10:55:35 +0000754 FlowRule.Builder inner = DefaultFlowRule.builder()
755 .fromApp(fwd.appId())
756 .forDevice(deviceId)
757 .makePermanent()
758 .withPriority(fwd.priority())
759 .withSelector(fwd.selector())
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000760 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), fetchMeter(fwd),
761 fetchWriteMetadata(fwd)));
Gamze Abakadadae722018-09-12 10:55:35 +0000762
Gamze Abakadadae722018-09-12 10:55:35 +0000763 //match: in port and any-vlan (coming from OLT app.)
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000764 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
Gamze Abakadadae722018-09-12 10:55:35 +0000765 FlowRule.Builder outer = DefaultFlowRule.builder()
766 .fromApp(fwd.appId())
767 .forDevice(deviceId)
768 .forTable(QQ_TABLE)
769 .makePermanent()
770 .withPriority(fwd.priority())
771 .withSelector(fwd.selector())
Andrea Campanella6edac322020-01-29 14:41:42 +0100772 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000773 fetchMeter(fwd), writeMetadataIncludingOnlyTp(fwd), output));
Gamze Abakadadae722018-09-12 10:55:35 +0000774
Andrea Campanella6edac322020-01-29 14:41:42 +0100775 applyRules(fwd, inner, outer);
Gamze Abakadadae722018-09-12 10:55:35 +0000776 }
777
778 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
779 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
780 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
781 boolean noneValueVlanStatus = false;
782 if (vlanMatchCriterion != null) {
783 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
784 }
785 return noneValueVlanStatus;
786 }
787
788 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
789 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
790 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
791 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
792 .findAny().orElse(null);
793
794 if (anyValueVlanCriterion == null) {
Andrea Campanella6edac322020-01-29 14:41:42 +0100795 log.debug("Any value vlan match criteria is not found, criteria {}",
796 fwd.selector().criteria());
Gamze Abakadadae722018-09-12 10:55:35 +0000797 return false;
798 }
799
800 return true;
alshabibfd430b62015-12-16 18:56:38 -0800801 }
802
803 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
804 Instruction output = fwd.treatment().allInstructions().stream()
805 .filter(i -> i.type() == Instruction.Type.OUTPUT)
806 .findFirst().orElse(null);
807
808 if (output == null) {
809 log.error("OLT {} rule has no output", direction);
810 fail(fwd, ObjectiveError.BADPARAMS);
811 return null;
812 }
813 return output;
814 }
815
Gamze Abakadadae722018-09-12 10:55:35 +0000816 private Instruction fetchMeter(ForwardingObjective fwd) {
817 Instruction meter = fwd.treatment().metered();
818
819 if (meter == null) {
820 log.debug("Meter instruction is not found for the forwarding objective {}", fwd);
821 return null;
822 }
823
824 log.debug("Meter instruction is found.");
825 return meter;
826 }
827
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000828 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
829 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
Gamze Abakadadae722018-09-12 10:55:35 +0000830
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000831 if (writeMetadata == null) {
832 log.warn("Write metadata is not found for the forwarding obj");
833 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000834 return null;
835 }
836
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000837 log.debug("Write metadata is found {}", writeMetadata);
838 return writeMetadata;
Gamze Abakadadae722018-09-12 10:55:35 +0000839 }
840
alshabibfd430b62015-12-16 18:56:38 -0800841 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
842 L2ModificationInstruction.L2SubType type) {
843
844 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
845 fwd.treatment().allInstructions(), type);
846
Gamze Abakadadae722018-09-12 10:55:35 +0000847 if (vlanOps == null || vlanOps.isEmpty()) {
alshabibfd430b62015-12-16 18:56:38 -0800848 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000849 ? DOWNSTREAM : UPSTREAM;
alshabibfd430b62015-12-16 18:56:38 -0800850 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
851 fail(fwd, ObjectiveError.BADPARAMS);
Gamze Abakadadae722018-09-12 10:55:35 +0000852 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800853 }
854 return vlanOps;
855 }
856
857
858 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
alshabibd61b77b2016-02-01 23:30:53 -0800859 L2ModificationInstruction.L2SubType type) {
alshabibfd430b62015-12-16 18:56:38 -0800860
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000861 List<Instruction> vlanOperations = findL2Instructions(
alshabibfd430b62015-12-16 18:56:38 -0800862 type,
863 instructions);
864 List<Instruction> vlanSets = findL2Instructions(
865 L2ModificationInstruction.L2SubType.VLAN_ID,
866 instructions);
867
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000868 if (vlanOperations.size() != vlanSets.size()) {
Gamze Abakadadae722018-09-12 10:55:35 +0000869 return ImmutableList.of();
alshabibfd430b62015-12-16 18:56:38 -0800870 }
871
872 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
873
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000874 for (int i = 0; i < vlanOperations.size(); i++) {
875 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
alshabibfd430b62015-12-16 18:56:38 -0800876 }
877 return pairs;
878 }
879
880 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
881 List<Instruction> actions) {
882 return actions.stream()
883 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
884 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
885 .collect(Collectors.toList());
886 }
887
Amit Ghoshf1f22752018-08-14 07:28:01 +0100888 private void provisionEthTypeBasedFilter(FilteringObjective filter,
889 EthTypeCriterion ethType,
890 Instructions.OutputInstruction output) {
alshabibfd430b62015-12-16 18:56:38 -0800891
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000892 Instruction meter = filter.meta().metered();
893 Instruction writeMetadata = filter.meta().writeMetadata();
894
Gamze Abakaf57ef602019-03-11 06:52:48 +0000895 Criterion vlanId = filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
896
897 TrafficSelector selector = buildSelector(filter.key(), ethType, vlanId);
Gamze Abaka6c8a71b2018-12-24 13:17:12 +0000898 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800899 buildAndApplyRule(filter, selector, treatment);
900
901 }
902
Jonathan Hart51539b82015-10-29 09:53:04 -0700903 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
alshabibfd430b62015-12-16 18:56:38 -0800904 IPProtocolCriterion ipProto,
905 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000906
907 Instruction meter = filter.meta().metered();
908 Instruction writeMetadata = filter.meta().writeMetadata();
909
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000910 // cTag
911 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
912 Criterion.Type.VLAN_VID);
913 Criterion cTagPriority = filterForCriterion(filter.conditions(), Criterion.Type.VLAN_PCP);
914
915 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId, cTagPriority);
Gamze Abaka7c070c82019-02-21 14:40:18 +0000916 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
alshabibfd430b62015-12-16 18:56:38 -0800917 buildAndApplyRule(filter, selector, treatment);
918 }
919
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000920 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
921 IPProtocolCriterion ipProto,
922 UdpPortCriterion udpSrcPort,
923 UdpPortCriterion udpDstPort,
924 Instructions.OutputInstruction output) {
Gamze Abaka7c070c82019-02-21 14:40:18 +0000925
926 Instruction meter = filter.meta().metered();
927 Instruction writeMetadata = filter.meta().writeMetadata();
928
Gamze Abakafe9d54f2019-12-02 06:42:39 +0000929 VlanIdCriterion vlanId = (VlanIdCriterion)
930 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
931
932 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort, vlanId);
Gamze Abaka7c070c82019-02-21 14:40:18 +0000933 TrafficTreatment treatment = buildTreatment(output, meter, writeMetadata);
Amit Ghoshcbaf8672016-12-23 21:36:19 +0000934 buildAndApplyRule(filter, selector, treatment);
935 }
Gamze Abakadadae722018-09-12 10:55:35 +0000936
alshabibfd430b62015-12-16 18:56:38 -0800937 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
938 TrafficTreatment treatment) {
939 FlowRule rule = DefaultFlowRule.builder()
alshabib83364472016-03-25 09:59:55 -0700940 .fromApp(filter.appId())
alshabibfd430b62015-12-16 18:56:38 -0800941 .forDevice(deviceId)
942 .forTable(0)
alshabibfd430b62015-12-16 18:56:38 -0800943 .makePermanent()
944 .withSelector(selector)
945 .withTreatment(treatment)
alshabibbb424232016-01-15 12:20:25 -0800946 .withPriority(filter.priority())
alshabibfd430b62015-12-16 18:56:38 -0800947 .build();
948
949 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
950
951 switch (filter.type()) {
952 case PERMIT:
953 opsBuilder.add(rule);
954 break;
955 case DENY:
956 opsBuilder.remove(rule);
957 break;
958 default:
959 log.warn("Unknown filter type : {}", filter.type());
960 fail(filter, ObjectiveError.UNSUPPORTED);
961 }
962
963 applyFlowRules(opsBuilder, filter);
964 }
965
Gamze Abakadadae722018-09-12 10:55:35 +0000966 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
Amit Ghoshf1f22752018-08-14 07:28:01 +0100967 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
968 switch (fwd.op()) {
969 case ADD:
Gamze Abakadadae722018-09-12 10:55:35 +0000970 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
971 builder.add(fwdBuilder.build());
972 }
Amit Ghoshf1f22752018-08-14 07:28:01 +0100973 break;
974 case REMOVE:
Gamze Abakadadae722018-09-12 10:55:35 +0000975 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
976 builder.remove(fwdBuilder.build());
977 }
alshabibfd430b62015-12-16 18:56:38 -0800978 break;
979 case ADD_TO_EXISTING:
980 break;
981 case REMOVE_FROM_EXISTING:
982 break;
983 default:
984 log.warn("Unknown forwarding operation: {}", fwd.op());
985 }
986
987 applyFlowRules(builder, fwd);
988 }
989
990 private void applyFlowRules(FlowRuleOperations.Builder builder,
991 Objective objective) {
992 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
993 @Override
994 public void onSuccess(FlowRuleOperations ops) {
995 pass(objective);
996 }
997
998 @Override
999 public void onError(FlowRuleOperations ops) {
1000 fail(objective, ObjectiveError.FLOWINSTALLATIONFAILED);
1001 }
1002 }));
1003 }
1004
1005 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1006 return criteria.stream()
alshabibbb424232016-01-15 12:20:25 -08001007 .filter(c -> c.type().equals(type))
alshabibfd430b62015-12-16 18:56:38 -08001008 .limit(1)
1009 .findFirst().orElse(null);
1010 }
1011
1012 private TrafficSelector buildSelector(Criterion... criteria) {
1013
alshabibfd430b62015-12-16 18:56:38 -08001014 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1015
Gamze Abakaf57ef602019-03-11 06:52:48 +00001016 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001017
1018 return sBuilder.build();
1019 }
1020
1021 private TrafficTreatment buildTreatment(Instruction... instructions) {
1022
alshabibfd430b62015-12-16 18:56:38 -08001023 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1024
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001025 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
alshabibfd430b62015-12-16 18:56:38 -08001026
1027 return tBuilder.build();
1028 }
1029
Gamze Abaka6c8a71b2018-12-24 13:17:12 +00001030 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1031
1032 return Instructions.writeMetadata(
1033 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1034 }
alshabibfd430b62015-12-16 18:56:38 -08001035
1036 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001037 obj.context().ifPresent(context -> context.onError(obj, error));
alshabibfd430b62015-12-16 18:56:38 -08001038 }
1039
1040 private void pass(Objective obj) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -08001041 obj.context().ifPresent(context -> context.onSuccess(obj));
alshabibfd430b62015-12-16 18:56:38 -08001042 }
1043
alshabib2cc73cb2015-06-30 20:26:56 -07001044
alshabibd61b77b2016-02-01 23:30:53 -08001045 private class InnerGroupListener implements GroupListener {
alshabib2cc73cb2015-06-30 20:26:56 -07001046 @Override
alshabibd61b77b2016-02-01 23:30:53 -08001047 public void event(GroupEvent event) {
Andrea Campanella5908b562020-05-06 16:09:10 +02001048 GroupKey key = event.subject().appCookie();
1049 NextObjective obj = pendingGroups.getIfPresent(key);
1050 if (obj == null) {
1051 log.debug("No pending group for {}, moving on", key);
1052 return;
1053 }
1054 log.trace("Event {} for group {}, handling pending" +
1055 "NextGroup {}", event.type(), key, obj.id());
ke hanf5086672016-08-12 11:09:17 +08001056 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
Gamze Abakadadae722018-09-12 10:55:35 +00001057 event.type() == GroupEvent.Type.GROUP_UPDATED) {
alshabibd61b77b2016-02-01 23:30:53 -08001058 flowObjectiveStore.putNextGroup(obj.id(), new OLTPipelineGroup(key));
1059 pass(obj);
1060 pendingGroups.invalidate(key);
Andrea Campanella5908b562020-05-06 16:09:10 +02001061 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1062 flowObjectiveStore.removeNextGroup(obj.id());
1063 pass(obj);
1064 pendingGroups.invalidate(key);
alshabibd61b77b2016-02-01 23:30:53 -08001065 }
alshabib2cc73cb2015-06-30 20:26:56 -07001066 }
1067 }
1068
alshabibd61b77b2016-02-01 23:30:53 -08001069 private static class OLTPipelineGroup implements NextGroup {
1070
1071 private final GroupKey key;
1072
1073 public OLTPipelineGroup(GroupKey key) {
1074 this.key = key;
1075 }
1076
1077 public GroupKey key() {
1078 return key;
1079 }
1080
1081 @Override
1082 public byte[] data() {
1083 return appKryo.serialize(key);
1084 }
1085
1086 }
Saurav Das24431192016-03-07 19:13:00 -08001087
1088 @Override
1089 public List<String> getNextMappings(NextGroup nextGroup) {
1090 // TODO Implementation deferred to vendor
1091 return null;
1092 }
alshabib0ccde6d2015-05-30 18:22:36 -07001093}