blob: c405b758c8bfed5f1f7294692392b46893963bd7 [file] [log] [blame]
Andrea Campanella37f07e42021-02-16 11:24:39 +01001/*
2 * Copyright 2016-present Open Networking Foundation
3 *
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.opencord.olt.driver;
17
18import com.google.common.cache.Cache;
19import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.RemovalCause;
21import com.google.common.cache.RemovalNotification;
22import com.google.common.collect.ImmutableList;
23import com.google.common.collect.Lists;
24import org.apache.commons.lang3.tuple.ImmutablePair;
25import org.apache.commons.lang3.tuple.Pair;
26import org.onlab.osgi.ServiceDirectory;
27import org.onlab.packet.EthType;
28import org.onlab.packet.IPv4;
29import org.onlab.packet.IPv6;
30import org.onlab.packet.IpPrefix;
31import org.onlab.packet.VlanId;
32import org.onlab.util.AbstractAccumulator;
33import org.onlab.util.Accumulator;
34import org.onlab.util.KryoNamespace;
35import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +053037import org.onosproject.net.Annotations;
Andrea Campanella37f07e42021-02-16 11:24:39 +010038import org.onosproject.net.DeviceId;
39import org.onosproject.net.PortNumber;
40import org.onosproject.net.behaviour.NextGroup;
41import org.onosproject.net.behaviour.Pipeliner;
42import org.onosproject.net.behaviour.PipelinerContext;
43import org.onosproject.net.driver.AbstractHandlerBehaviour;
44import org.onosproject.net.driver.Driver;
45import org.onosproject.net.flow.DefaultFlowRule;
46import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
48import org.onosproject.net.flow.FlowRule;
49import org.onosproject.net.flow.FlowRuleOperations;
50import org.onosproject.net.flow.FlowRuleOperationsContext;
51import org.onosproject.net.flow.FlowRuleService;
52import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flow.TrafficTreatment;
54import org.onosproject.net.flow.criteria.Criteria;
55import org.onosproject.net.flow.criteria.Criterion;
56import org.onosproject.net.flow.criteria.EthTypeCriterion;
57import org.onosproject.net.flow.criteria.IPCriterion;
58import org.onosproject.net.flow.criteria.IPProtocolCriterion;
59import org.onosproject.net.flow.criteria.PortCriterion;
60import org.onosproject.net.flow.criteria.UdpPortCriterion;
61import org.onosproject.net.flow.criteria.VlanIdCriterion;
62import org.onosproject.net.flow.instructions.Instruction;
63import org.onosproject.net.flow.instructions.Instructions;
64import org.onosproject.net.flow.instructions.L2ModificationInstruction;
65import org.onosproject.net.flowobjective.FilteringObjective;
66import org.onosproject.net.flowobjective.FlowObjectiveStore;
67import org.onosproject.net.flowobjective.ForwardingObjective;
68import org.onosproject.net.flowobjective.NextObjective;
69import org.onosproject.net.flowobjective.Objective;
70import org.onosproject.net.flowobjective.ObjectiveError;
71import org.onosproject.net.group.DefaultGroupBucket;
72import org.onosproject.net.group.DefaultGroupDescription;
73import org.onosproject.net.group.DefaultGroupKey;
74import org.onosproject.net.group.Group;
75import org.onosproject.net.group.GroupBucket;
76import org.onosproject.net.group.GroupBuckets;
77import org.onosproject.net.group.GroupDescription;
78import org.onosproject.net.group.GroupEvent;
79import org.onosproject.net.group.GroupKey;
80import org.onosproject.net.group.GroupListener;
81import org.onosproject.net.group.GroupService;
82import org.onosproject.store.serializers.KryoNamespaces;
83import org.onosproject.store.service.StorageService;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +053084import org.opencord.olt.impl.fttb.FttbUtils;
Andrea Campanella37f07e42021-02-16 11:24:39 +010085import org.slf4j.Logger;
86
87import java.util.Arrays;
88import java.util.Collection;
89import java.util.Collections;
90import java.util.List;
91import java.util.Objects;
92import java.util.Optional;
93import java.util.concurrent.ScheduledExecutorService;
94import java.util.Timer;
95import java.util.concurrent.TimeUnit;
96import java.util.stream.Collectors;
97
98import static org.onosproject.core.CoreService.CORE_APP_NAME;
yasin saplib4b8ee12021-06-13 18:25:20 +000099import static org.opencord.olt.impl.OsgiPropertyConstants.DOWNSTREAM_OLT;
100import static org.opencord.olt.impl.OsgiPropertyConstants.DOWNSTREAM_ONU;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +0530101import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_FLOW_DIRECTION;
102import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_FLOW_DOWNSTREAM;
103import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_FLOW_UPSTREAM;
yasin saplib4b8ee12021-06-13 18:25:20 +0000104import static org.opencord.olt.impl.OsgiPropertyConstants.UPSTREAM_OLT;
105import static org.opencord.olt.impl.OsgiPropertyConstants.UPSTREAM_ONU;
Andrea Campanella37f07e42021-02-16 11:24:39 +0100106import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
107import static org.onlab.util.Tools.groupedThreads;
Harsh Awasthic1e4bf52022-02-09 14:14:14 +0530108import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_SERVICE_DPU_ANCP_TRAFFIC;
109import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_SERVICE_DPU_MGMT_TRAFFIC;
110import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_SERVICE_NAME;
111import static org.opencord.olt.impl.fttb.FttbUtils.FTTB_SERVICE_SUBSCRIBER_TRAFFIC;
Andrea Campanella37f07e42021-02-16 11:24:39 +0100112import static org.slf4j.LoggerFactory.getLogger;
113
114/**
115 * Pipeliner for OLT device.
116 */
117
118public class OltPipeline extends AbstractHandlerBehaviour implements Pipeliner {
119
120 private static final Integer QQ_TABLE = 1;
121 private static final int NO_ACTION_PRIORITY = 500;
122 private static final String DOWNSTREAM = "downstream";
123 private static final String UPSTREAM = "upstream";
124 private final Logger log = getLogger(getClass());
125
126 private ServiceDirectory serviceDirectory;
127 private FlowRuleService flowRuleService;
128 private GroupService groupService;
129 private CoreService coreService;
130 private StorageService storageService;
131
132 private DeviceId deviceId;
133 private ApplicationId appId;
134
135
136 protected FlowObjectiveStore flowObjectiveStore;
137
138 private Cache<GroupKey, NextObjective> pendingGroups;
139
140 protected static KryoNamespace appKryo = new KryoNamespace.Builder()
141 .register(KryoNamespaces.API)
142 .register(GroupKey.class)
143 .register(DefaultGroupKey.class)
144 .register(OltPipelineGroup.class)
145 .build("OltPipeline");
146
147 private static final Timer TIMER = new Timer("filterobj-batching");
148 private Accumulator<Pair<FilteringObjective, FlowRule>> accumulator;
149
150 // accumulator executor service
151 private ScheduledExecutorService accumulatorExecutorService
152 = newSingleThreadScheduledExecutor(groupedThreads("OltPipeliner", "acc-%d", log));
153
154 @Override
155 public void init(DeviceId deviceId, PipelinerContext context) {
156 log.debug("Initiate OLT pipeline");
157 this.serviceDirectory = context.directory();
158 this.deviceId = deviceId;
159
160 flowRuleService = serviceDirectory.get(FlowRuleService.class);
161 coreService = serviceDirectory.get(CoreService.class);
162 groupService = serviceDirectory.get(GroupService.class);
163 flowObjectiveStore = context.store();
164 storageService = serviceDirectory.get(StorageService.class);
165
166 appId = coreService.registerApplication(
167 "org.onosproject.driver.OLTPipeline");
168
169 // Init the accumulator, if enabled
170 if (isAccumulatorEnabled()) {
171 log.debug("Building accumulator with maxObjs {}, batchMs {}, idleMs {}",
172 context.accumulatorMaxObjectives(), context.accumulatorMaxBatchMillis(),
173 context.accumulatorMaxIdleMillis());
174 accumulator = new ObjectiveAccumulator(context.accumulatorMaxObjectives(),
175 context.accumulatorMaxBatchMillis(),
176 context.accumulatorMaxIdleMillis());
Andrea Campanella438e1ad2021-03-26 11:41:16 +0100177 } else {
178 log.debug("Olt Pipeliner accumulator is disabled, processing immediately");
Andrea Campanella37f07e42021-02-16 11:24:39 +0100179 }
180
181
182 pendingGroups = CacheBuilder.newBuilder()
183 .expireAfterWrite(20, TimeUnit.SECONDS)
184 .removalListener((RemovalNotification<GroupKey, NextObjective> notification) -> {
185 if (notification.getCause() == RemovalCause.EXPIRED) {
186 fail(notification.getValue(), ObjectiveError.GROUPINSTALLATIONFAILED);
187 }
188 }).build();
189
190 groupService.addListener(new InnerGroupListener());
191
192 }
193
194 public boolean isAccumulatorEnabled() {
195 Driver driver = super.data().driver();
196 // we cannot determine the property
197 if (driver == null) {
198 return false;
199 }
200 return Boolean.parseBoolean(driver.getProperty(ACCUMULATOR_ENABLED));
201 }
202
203 @Override
204 public void filter(FilteringObjective filter) {
205 Instructions.OutputInstruction output;
206
207 if (filter.meta() != null && !filter.meta().immediate().isEmpty()) {
208 output = (Instructions.OutputInstruction) filter.meta().immediate().stream()
209 .filter(t -> t.type().equals(Instruction.Type.OUTPUT))
210 .limit(1)
211 .findFirst().get();
212
213 if (output == null || !output.port().equals(PortNumber.CONTROLLER)) {
214 log.warn("OLT can only filter packet to controller");
215 fail(filter, ObjectiveError.UNSUPPORTED);
216 return;
217 }
218 } else {
219 fail(filter, ObjectiveError.BADPARAMS);
220 return;
221 }
222
223 if (filter.key().type() != Criterion.Type.IN_PORT) {
224 fail(filter, ObjectiveError.BADPARAMS);
225 return;
226 }
227
228 EthTypeCriterion ethType = (EthTypeCriterion)
229 filterForCriterion(filter.conditions(), Criterion.Type.ETH_TYPE);
230
231 if (ethType == null) {
232 fail(filter, ObjectiveError.BADPARAMS);
233 return;
234 }
235 Optional<Instruction> vlanId = filter.meta().immediate().stream()
236 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
237 && ((L2ModificationInstruction) t).subtype()
238 .equals(L2ModificationInstruction.L2SubType.VLAN_ID))
239 .limit(1)
240 .findFirst();
241
242 Optional<Instruction> vlanPcp = filter.meta().immediate().stream()
243 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
244 && ((L2ModificationInstruction) t).subtype()
245 .equals(L2ModificationInstruction.L2SubType.VLAN_PCP))
246 .limit(1)
247 .findFirst();
248
249 Optional<Instruction> vlanPush = filter.meta().immediate().stream()
250 .filter(t -> t.type().equals(Instruction.Type.L2MODIFICATION)
251 && ((L2ModificationInstruction) t).subtype()
252 .equals(L2ModificationInstruction.L2SubType.VLAN_PUSH))
253 .limit(1)
254 .findFirst();
255
256 if (ethType.ethType().equals(EthType.EtherType.EAPOL.ethType())) {
257
258 if (vlanId.isEmpty() || vlanPush.isEmpty()) {
259 log.warn("Missing EAPOL vlan or vlanPush");
260 fail(filter, ObjectiveError.BADPARAMS);
261 return;
262 }
263 provisionEthTypeBasedFilter(filter, ethType, output,
264 (L2ModificationInstruction) vlanId.get(),
265 (L2ModificationInstruction) vlanPush.get());
266 } else if (ethType.ethType().equals(EthType.EtherType.PPPoED.ethType())) {
267 provisionPPPoED(filter, ethType, vlanId.orElse(null), vlanPcp.orElse(null), output);
268 } else if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType())) {
269 provisionEthTypeBasedFilter(filter, ethType, output, null, null);
270 } else if (ethType.ethType().equals(EthType.EtherType.IPV4.ethType())) {
271 IPProtocolCriterion ipProto = (IPProtocolCriterion)
272 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
273 if (ipProto == null) {
274 log.warn("OLT can only filter IGMP and DHCP");
275 fail(filter, ObjectiveError.UNSUPPORTED);
276 return;
277 }
278 if (ipProto.protocol() == IPv4.PROTOCOL_IGMP) {
279 provisionIgmp(filter, ethType, ipProto, output,
280 vlanId.orElse(null),
281 vlanPcp.orElse(null));
282 } else if (ipProto.protocol() == IPv4.PROTOCOL_UDP) {
283 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
284 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
285
286 UdpPortCriterion udpDstPort = (UdpPortCriterion)
287 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
288
289 if ((udpSrcPort.udpPort().toInt() == 67 && udpDstPort.udpPort().toInt() == 68) ||
290 (udpSrcPort.udpPort().toInt() == 68 && udpDstPort.udpPort().toInt() == 67)) {
291 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
292 vlanPcp.orElse(null), output);
293 } else {
294 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
295 fail(filter, ObjectiveError.UNSUPPORTED);
296 }
297 } else {
298 log.warn("Currently supporting only IGMP and DHCP filters for IPv4 packets");
299 fail(filter, ObjectiveError.UNSUPPORTED);
300 }
301 } else if (ethType.ethType().equals(EthType.EtherType.IPV6.ethType())) {
302 IPProtocolCriterion ipProto = (IPProtocolCriterion)
303 filterForCriterion(filter.conditions(), Criterion.Type.IP_PROTO);
304 if (ipProto == null) {
305 log.warn("OLT can only filter DHCP");
306 fail(filter, ObjectiveError.UNSUPPORTED);
307 return;
308 }
309 if (ipProto.protocol() == IPv6.PROTOCOL_UDP) {
310 UdpPortCriterion udpSrcPort = (UdpPortCriterion)
311 filterForCriterion(filter.conditions(), Criterion.Type.UDP_SRC);
312
313 UdpPortCriterion udpDstPort = (UdpPortCriterion)
314 filterForCriterion(filter.conditions(), Criterion.Type.UDP_DST);
315
316 if ((udpSrcPort.udpPort().toInt() == 546 && udpDstPort.udpPort().toInt() == 547) ||
317 (udpSrcPort.udpPort().toInt() == 547 && udpDstPort.udpPort().toInt() == 546)) {
318 provisionDhcp(filter, ethType, ipProto, udpSrcPort, udpDstPort, vlanId.orElse(null),
319 vlanPcp.orElse(null), output);
320 } else {
321 log.warn("Filtering rule with unsupported UDP src {} or dst {} port", udpSrcPort, udpDstPort);
322 fail(filter, ObjectiveError.UNSUPPORTED);
323 }
324 } else {
325 log.warn("Currently supporting only DHCP filters for IPv6 packets");
326 fail(filter, ObjectiveError.UNSUPPORTED);
327 }
328 } else {
329 log.warn("\nOnly the following are Supported in OLT for filter ->\n"
330 + "ETH TYPE : EAPOL, LLDP and IPV4\n"
331 + "IPV4 TYPE: IGMP and UDP (for DHCP)"
332 + "IPV6 TYPE: UDP (for DHCP)");
333 fail(filter, ObjectiveError.UNSUPPORTED);
334 }
335
336 }
337
338
339 @Override
340 public void forward(ForwardingObjective fwd) {
341 log.debug("Installing forwarding objective {}", fwd);
342 if (checkForMulticast(fwd)) {
343 processMulticastRule(fwd);
344 return;
345 }
346
Harsh Awasthic1e4bf52022-02-09 14:14:14 +0530347 if (FttbUtils.isFttbRule(fwd)) {
348 log.debug("Processing FTTB rule : {}", fwd);
349 processFttbRules(fwd);
350 return;
351 }
352
Andrea Campanella37f07e42021-02-16 11:24:39 +0100353 TrafficTreatment treatment = fwd.treatment();
354
355 List<Instruction> instructions = treatment.allInstructions();
356
357 Optional<Instruction> vlanInstruction = instructions.stream()
358 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
359 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
360 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
361 ((L2ModificationInstruction) i).subtype() ==
362 L2ModificationInstruction.L2SubType.VLAN_POP)
363 .findAny();
364
365
366 if (!vlanInstruction.isPresent()) {
367 installNoModificationRules(fwd);
368 } else {
369 L2ModificationInstruction vlanIns =
370 (L2ModificationInstruction) vlanInstruction.get();
371 if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
372 installUpstreamRules(fwd);
373 } else if (vlanIns.subtype() == L2ModificationInstruction.L2SubType.VLAN_POP) {
374 installDownstreamRules(fwd);
375 } else {
376 log.error("Unknown OLT operation: {}", fwd);
377 fail(fwd, ObjectiveError.UNSUPPORTED);
378 return;
379 }
380 }
381
382 pass(fwd);
383
384 }
385
386
387 @Override
388 public void next(NextObjective nextObjective) {
389 if (nextObjective.type() != NextObjective.Type.BROADCAST) {
390 log.error("OLT only supports broadcast groups.");
391 fail(nextObjective, ObjectiveError.BADPARAMS);
392 return;
393 }
394
395 if (nextObjective.next().size() != 1 && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
396 log.error("OLT only supports singleton broadcast groups.");
397 fail(nextObjective, ObjectiveError.BADPARAMS);
398 return;
399 }
400
401 Optional<TrafficTreatment> treatmentOpt = nextObjective.next().stream().findFirst();
402 if (treatmentOpt.isEmpty() && !nextObjective.op().equals(Objective.Operation.REMOVE)) {
403 log.error("Next objective {} does not have a treatment", nextObjective);
404 fail(nextObjective, ObjectiveError.BADPARAMS);
405 return;
406 }
407
408 GroupKey key = new DefaultGroupKey(appKryo.serialize(nextObjective.id()));
409
410 pendingGroups.put(key, nextObjective);
411 log.trace("NextObjective Operation {}", nextObjective.op());
412 switch (nextObjective.op()) {
413 case ADD:
414 GroupDescription groupDesc =
415 new DefaultGroupDescription(deviceId,
416 GroupDescription.Type.ALL,
417 new GroupBuckets(
418 Collections.singletonList(
419 buildBucket(treatmentOpt.get()))),
420 key,
421 null,
422 nextObjective.appId());
423 groupService.addGroup(groupDesc);
424 break;
425 case REMOVE:
426 groupService.removeGroup(deviceId, key, nextObjective.appId());
427 break;
428 case ADD_TO_EXISTING:
429 groupService.addBucketsToGroup(deviceId, key,
430 new GroupBuckets(
431 Collections.singletonList(
432 buildBucket(treatmentOpt.get()))),
433 key, nextObjective.appId());
434 break;
435 case REMOVE_FROM_EXISTING:
436 groupService.removeBucketsFromGroup(deviceId, key,
437 new GroupBuckets(
438 Collections.singletonList(
439 buildBucket(treatmentOpt.get()))),
440 key, nextObjective.appId());
441 break;
442 default:
443 log.warn("Unknown next objective operation: {}", nextObjective.op());
444 }
445
446
447 }
448
Andrea Campanellaba1dab02021-12-01 17:16:05 -0800449 @Override
450 public void purgeAll(ApplicationId appId) {
451 log.warn("Purge All not implemented by OLT Pipeliner");
452 //TODO not used by OLT app, only by trellis
453 }
454
Andrea Campanella37f07e42021-02-16 11:24:39 +0100455 private GroupBucket buildBucket(TrafficTreatment treatment) {
456 return DefaultGroupBucket.createAllGroupBucket(treatment);
457 }
458
459 private void processMulticastRule(ForwardingObjective fwd) {
460 if (fwd.nextId() == null) {
461 log.error("Multicast objective does not have a next id");
462 fail(fwd, ObjectiveError.BADPARAMS);
463 }
464
465 GroupKey key = getGroupForNextObjective(fwd.nextId());
466
467 if (key == null) {
468 log.error("Group for forwarding objective missing: {}", fwd);
469 fail(fwd, ObjectiveError.GROUPMISSING);
470 }
471
472 Group group = groupService.getGroup(deviceId, key);
473 TrafficTreatment treatment =
474 buildTreatment(Instructions.createGroup(group.id()));
475
476 TrafficSelector.Builder selectorBuilder = buildIpv4SelectorForMulticast(fwd);
477
478 FlowRule rule = DefaultFlowRule.builder()
479 .fromApp(fwd.appId())
480 .forDevice(deviceId)
481 .forTable(0)
482 .makePermanent()
483 .withPriority(fwd.priority())
484 .withSelector(selectorBuilder.build())
485 .withTreatment(treatment)
486 .build();
487
488 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
489 switch (fwd.op()) {
490
491 case ADD:
492 builder.add(rule);
493 break;
494 case REMOVE:
495 builder.remove(rule);
496 break;
497 case ADD_TO_EXISTING:
498 case REMOVE_FROM_EXISTING:
499 break;
500 default:
501 log.warn("Unknown forwarding operation: {}", fwd.op());
502 }
503
504 applyFlowRules(ImmutableList.of(fwd), builder);
505
506
507 }
508
509 private TrafficSelector.Builder buildIpv4SelectorForMulticast(ForwardingObjective fwd) {
510 TrafficSelector.Builder builderToUpdate = DefaultTrafficSelector.builder();
511
512 Optional<Criterion> vlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.VLAN_VID);
513 if (vlanIdCriterion.isPresent()) {
514 VlanId assignedVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
515 builderToUpdate.matchVlanId(assignedVlan);
516 }
517
518 Optional<Criterion> innerVlanIdCriterion = readFromSelector(fwd.meta(), Criterion.Type.INNER_VLAN_VID);
519 if (innerVlanIdCriterion.isPresent()) {
520 VlanId assignedInnerVlan = ((VlanIdCriterion) innerVlanIdCriterion.get()).vlanId();
521 builderToUpdate.matchMetadata(assignedInnerVlan.toShort());
522 }
523
524 Optional<Criterion> ethTypeCriterion = readFromSelector(fwd.selector(), Criterion.Type.ETH_TYPE);
525 if (ethTypeCriterion.isPresent()) {
526 EthType ethType = ((EthTypeCriterion) ethTypeCriterion.get()).ethType();
527 builderToUpdate.matchEthType(ethType.toShort());
528 }
529
530 Optional<Criterion> ipv4DstCriterion = readFromSelector(fwd.selector(), Criterion.Type.IPV4_DST);
531 if (ipv4DstCriterion.isPresent()) {
532 IpPrefix ipv4Dst = ((IPCriterion) ipv4DstCriterion.get()).ip();
533 builderToUpdate.matchIPDst(ipv4Dst);
534 }
535
536 return builderToUpdate;
537 }
538
539 static Optional<Criterion> readFromSelector(TrafficSelector selector, Criterion.Type type) {
540 if (selector == null) {
541 return Optional.empty();
542 }
543 Criterion criterion = selector.getCriterion(type);
544 return (criterion == null)
545 ? Optional.empty() : Optional.of(criterion);
546 }
547
548 private boolean checkForMulticast(ForwardingObjective fwd) {
549
550 IPCriterion ip = (IPCriterion) filterForCriterion(fwd.selector().criteria(),
551 Criterion.Type.IPV4_DST);
552
553 if (ip == null) {
554 return false;
555 }
556
557 return ip.ip().isMulticast();
558
559 }
560
561 private GroupKey getGroupForNextObjective(Integer nextId) {
562 NextGroup next = flowObjectiveStore.getNextGroup(nextId);
563 return appKryo.deserialize(next.data());
564
565 }
566
567 private void installNoModificationRules(ForwardingObjective fwd) {
568 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
569 Instructions.MetadataInstruction writeMetadata = fetchWriteMetadata(fwd);
yasin saplib4b8ee12021-06-13 18:25:20 +0000570 Instructions.MeterInstruction meter = fwd.treatment().metered();
Andrea Campanella37f07e42021-02-16 11:24:39 +0100571
572 TrafficSelector selector = fwd.selector();
573
574 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
575 Criterion outerVlan = selector.getCriterion(Criterion.Type.VLAN_VID);
576 Criterion innerVlan = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
577
578 if (inport == null || output == null || innerVlan == null || outerVlan == null) {
579 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
580 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
581 log.error("Forwarding objective is underspecified: {}", fwd);
582 } else {
583 log.debug("Not installing unsupported core generated flow {}", fwd);
584 }
585 fail(fwd, ObjectiveError.BADPARAMS);
586 return;
587 }
588
589
590 FlowRule.Builder outer = DefaultFlowRule.builder()
591 .fromApp(fwd.appId())
592 .forDevice(deviceId)
593 .makePermanent()
594 .withPriority(fwd.priority())
595 .withSelector(buildSelector(inport, outerVlan))
596 .withTreatment(buildTreatment(output, writeMetadata, meter));
597
598 applyRules(fwd, outer);
599 }
600
601 private void installDownstreamRules(ForwardingObjective fwd) {
602 Instructions.OutputInstruction output = (Instructions.OutputInstruction) fetchOutput(fwd, DOWNSTREAM);
603
604 if (output == null) {
605 return;
606 }
607
608 TrafficSelector selector = fwd.selector();
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100609 Criterion outerVlanCriterion = selector.getCriterion(Criterion.Type.VLAN_VID);
Andrea Campanella37f07e42021-02-16 11:24:39 +0100610 Criterion outerPbit = selector.getCriterion(Criterion.Type.VLAN_PCP);
611 Criterion innerVlanCriterion = selector.getCriterion(Criterion.Type.INNER_VLAN_VID);
612 Criterion inport = selector.getCriterion(Criterion.Type.IN_PORT);
613 Criterion dstMac = selector.getCriterion(Criterion.Type.ETH_DST);
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100614 //TODO better check for innerVlan
615 if (outerVlanCriterion == null || inport == null) {
Andrea Campanella37f07e42021-02-16 11:24:39 +0100616 // Avoid logging a non-error from lldp, bbdp and eapol core flows.
617 if (!fwd.appId().name().equals(CORE_APP_NAME)) {
618 log.error("Forwarding objective is underspecified: {}", fwd);
619 } else {
620 log.debug("Not installing unsupported core generated flow {}", fwd);
621 }
622 fail(fwd, ObjectiveError.BADPARAMS);
623 return;
624 }
625
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100626 VlanId outerVlan = ((VlanIdCriterion) outerVlanCriterion).vlanId();
627 //Verify if this is needed.
628 Criterion outerVid = Criteria.matchVlanId(outerVlan);
629
Andrea Campanella37f07e42021-02-16 11:24:39 +0100630 VlanId innerVlan = ((VlanIdCriterion) innerVlanCriterion).vlanId();
631 Criterion innerVid = Criteria.matchVlanId(innerVlan);
632
633 // In the case where the C-tag is the same for all the subscribers,
634 // we add a metadata with the outport in the selector to make the flow unique
635 Criterion innerSelectorMeta = Criteria.matchMetadata(output.port().toLong());
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100636 if (outerVlan.toShort() == VlanId.ANY_VALUE) {
637 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
638 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlanCriterion, outerPbit, dstMac);
639 installDownstreamRulesForOuterAnyVlan(fwd, output, outerSelector, buildSelector(inport, innerVid,
640 innerSelectorMeta));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100641
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100642 } else if (innerVlan.toShort() == VlanId.ANY_VALUE) {
643 TrafficSelector outerSelector = buildSelector(inport, outerVlanCriterion, outerPbit, dstMac);
644
645 Criterion matchedVlanId = Criteria.matchVlanId(VlanId.ANY);
646 installDownstreamRulesForInnerAnyVlan(fwd, output, outerSelector,
647 buildSelector(inport,
648 matchedVlanId,
649 innerSelectorMeta));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100650 } else {
651 // Required to differentiate the same match flows
652 // Please note that S tag and S p bit values will be same for the same service - so conflict flows!
653 // Metadata match criteria solves the conflict issue - but not used by the voltha
654 // Maybe - find a better way to solve the above problem
655 Criterion metadata = Criteria.matchMetadata(innerVlan.toShort());
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100656 TrafficSelector outerSelector = buildSelector(inport, metadata, outerVlanCriterion, outerPbit, dstMac);
Andrea Campanella37f07e42021-02-16 11:24:39 +0100657 installDownstreamRulesForVlans(fwd, output, outerSelector, buildSelector(inport, innerVid,
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100658 innerSelectorMeta));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100659 }
660 }
661
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100662 private void installDownstreamRulesForOuterAnyVlan(ForwardingObjective fwd, Instruction output,
663 TrafficSelector outerSelector, TrafficSelector innerSelector) {
664
665 Instruction onuDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_ONU));
666 Instruction oltDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_OLT));
667
668 List<Pair<Instruction, Instruction>> vlanOps =
669 vlanOps(fwd,
670 L2ModificationInstruction.L2SubType.VLAN_POP);
671
672 if (vlanOps == null || vlanOps.isEmpty()) {
673 return;
674 }
675
676 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
677
678 TrafficTreatment innerTreatment;
679 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
680 if (VlanId.NONE.equals(setVlanId)) {
681 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), onuDsMeter,
682 writeMetadataIncludingOnlyTp(fwd), output));
683 } else {
684 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
685 onuDsMeter, writeMetadataIncludingOnlyTp(fwd), output));
686 }
687
688 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
689 fwd.treatment().allInstructions());
690
691 Instruction innerPbitSet = null;
692
693 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
694 innerPbitSet = setVlanPcps.get(0);
695 }
696
697 VlanId remarkInnerVlan = null;
698 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
699 if (vlanIdCriterion.isPresent()) {
700 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
701 }
702
703 Instruction modVlanId = null;
704 if (innerPbitSet != null) {
705 modVlanId = Instructions.modVlanId(remarkInnerVlan);
706 }
707
708 //match: in port (nni), s-tag
709 //action: pop vlan (s-tag), write metadata, go to table 1, meter
710 FlowRule.Builder outer = DefaultFlowRule.builder()
711 .fromApp(fwd.appId())
712 .forDevice(deviceId)
713 .makePermanent()
714 .withPriority(fwd.priority())
715 .withSelector(outerSelector)
716 .withTreatment(buildTreatment(oltDsMeter,
717 fetchWriteMetadata(fwd),
718 Instructions.transition(QQ_TABLE)));
719
720 //match: in port (nni), c-tag
721 //action: immediate: write metadata and pop, meter, output
722 FlowRule.Builder inner = DefaultFlowRule.builder()
723 .fromApp(fwd.appId())
724 .forDevice(deviceId)
725 .forTable(QQ_TABLE)
726 .makePermanent()
727 .withPriority(fwd.priority())
728 .withSelector(innerSelector)
729 .withTreatment(innerTreatment);
730 applyRules(fwd, inner, outer);
731 }
732
Andrea Campanella37f07e42021-02-16 11:24:39 +0100733 private void installDownstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
734 TrafficSelector outerSelector, TrafficSelector innerSelector) {
735
yasin saplib4b8ee12021-06-13 18:25:20 +0000736 Instruction onuDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_ONU));
737 Instruction oltDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_OLT));
738
Andrea Campanella37f07e42021-02-16 11:24:39 +0100739 List<Pair<Instruction, Instruction>> vlanOps =
740 vlanOps(fwd,
741 L2ModificationInstruction.L2SubType.VLAN_POP);
742
743 if (vlanOps == null || vlanOps.isEmpty()) {
744 return;
745 }
746
747 Pair<Instruction, Instruction> popAndRewrite = vlanOps.remove(0);
748
749 TrafficTreatment innerTreatment;
750 VlanId setVlanId = ((L2ModificationInstruction.ModVlanIdInstruction) popAndRewrite.getRight()).vlanId();
751 if (VlanId.NONE.equals(setVlanId)) {
yasin saplib4b8ee12021-06-13 18:25:20 +0000752 innerTreatment = (buildTreatment(popAndRewrite.getLeft(), onuDsMeter,
753 writeMetadataIncludingOnlyTp(fwd), output));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100754 } else {
755 innerTreatment = (buildTreatment(popAndRewrite.getRight(),
yasin saplib4b8ee12021-06-13 18:25:20 +0000756 onuDsMeter, writeMetadataIncludingOnlyTp(fwd), output));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100757 }
758
759 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
760 fwd.treatment().allInstructions());
761
762 Instruction innerPbitSet = null;
763
764 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
765 innerPbitSet = setVlanPcps.get(0);
766 }
767
768 VlanId remarkInnerVlan = null;
769 Optional<Criterion> vlanIdCriterion = readFromSelector(innerSelector, Criterion.Type.VLAN_VID);
770 if (vlanIdCriterion.isPresent()) {
771 remarkInnerVlan = ((VlanIdCriterion) vlanIdCriterion.get()).vlanId();
772 }
773
774 Instruction modVlanId = null;
775 if (innerPbitSet != null) {
776 modVlanId = Instructions.modVlanId(remarkInnerVlan);
777 }
778
779 //match: in port (nni), s-tag
780 //action: pop vlan (s-tag), write metadata, go to table 1, meter
781 FlowRule.Builder outer = DefaultFlowRule.builder()
782 .fromApp(fwd.appId())
783 .forDevice(deviceId)
784 .makePermanent()
785 .withPriority(fwd.priority())
786 .withSelector(outerSelector)
787 .withTreatment(buildTreatment(popAndRewrite.getLeft(), modVlanId,
yasin saplib4b8ee12021-06-13 18:25:20 +0000788 innerPbitSet, oltDsMeter,
Andrea Campanella37f07e42021-02-16 11:24:39 +0100789 fetchWriteMetadata(fwd),
790 Instructions.transition(QQ_TABLE)));
791
792 //match: in port (nni), c-tag
793 //action: immediate: write metadata and pop, meter, output
794 FlowRule.Builder inner = DefaultFlowRule.builder()
795 .fromApp(fwd.appId())
796 .forDevice(deviceId)
797 .forTable(QQ_TABLE)
798 .makePermanent()
799 .withPriority(fwd.priority())
800 .withSelector(innerSelector)
801 .withTreatment(innerTreatment);
802 applyRules(fwd, inner, outer);
803 }
804
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100805 private void installDownstreamRulesForInnerAnyVlan(ForwardingObjective fwd, Instruction output,
806 TrafficSelector outerSelector, TrafficSelector innerSelector) {
Andrea Campanella37f07e42021-02-16 11:24:39 +0100807
yasin saplib4b8ee12021-06-13 18:25:20 +0000808 Instruction onuDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_ONU));
809 Instruction oltDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_OLT));
810
Andrea Campanella37f07e42021-02-16 11:24:39 +0100811 //match: in port (nni), s-tag
812 //action: immediate: write metadata, pop vlan, meter and go to table 1
813 FlowRule.Builder outer = DefaultFlowRule.builder()
814 .fromApp(fwd.appId())
815 .forDevice(deviceId)
816 .makePermanent()
817 .withPriority(fwd.priority())
818 .withSelector(outerSelector)
yasin saplib4b8ee12021-06-13 18:25:20 +0000819 .withTreatment(buildTreatment(Instructions.popVlan(), oltDsMeter,
Andrea Campanella37f07e42021-02-16 11:24:39 +0100820 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE)));
821
822 //match: in port (nni) and s-tag
823 //action: immediate : write metadata, meter and output
824 FlowRule.Builder inner = DefaultFlowRule.builder()
825 .fromApp(fwd.appId())
826 .forDevice(deviceId)
827 .forTable(QQ_TABLE)
828 .makePermanent()
829 .withPriority(fwd.priority())
830 .withSelector(innerSelector)
yasin saplib4b8ee12021-06-13 18:25:20 +0000831 .withTreatment(buildTreatment(onuDsMeter, writeMetadataIncludingOnlyTp(fwd), output));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100832
833 applyRules(fwd, inner, outer);
834 }
835
836 private void installUpstreamRules(ForwardingObjective fwd) {
837 List<Pair<Instruction, Instruction>> vlanOps =
838 vlanOps(fwd,
839 L2ModificationInstruction.L2SubType.VLAN_PUSH);
Andrea Campanella37f07e42021-02-16 11:24:39 +0100840 if (vlanOps == null || vlanOps.isEmpty()) {
841 return;
842 }
843
844 Instruction output = fetchOutput(fwd, UPSTREAM);
845
846 if (output == null) {
847 return;
848 }
849
850 Pair<Instruction, Instruction> outerPair = vlanOps.remove(0);
851
852 boolean noneValueVlanStatus = checkNoneVlanCriteria(fwd);
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100853 //check if treatment is PUSH or POP
854 boolean popAndPush = checkIfIsPopAndPush(fwd);
Andrea Campanella37f07e42021-02-16 11:24:39 +0100855 boolean anyValueVlanStatus = checkAnyVlanMatchCriteria(fwd);
Andrea Campanella37f07e42021-02-16 11:24:39 +0100856 if (anyValueVlanStatus) {
857 installUpstreamRulesForAnyVlan(fwd, output, outerPair);
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100858 } else if (popAndPush) {
859 Pair<Instruction, Instruction> innerPair = outerPair;
860 outerPair = vlanOps.remove(0);
861 installUpstreamRulesForAnyOuterVlan(fwd, output, innerPair, outerPair, noneValueVlanStatus);
Andrea Campanella37f07e42021-02-16 11:24:39 +0100862 } else {
863 Pair<Instruction, Instruction> innerPair = outerPair;
864 outerPair = vlanOps.remove(0);
865 installUpstreamRulesForVlans(fwd, output, innerPair, outerPair, noneValueVlanStatus);
866 }
867 }
868
869 private void installUpstreamRulesForVlans(ForwardingObjective fwd, Instruction output,
870 Pair<Instruction, Instruction> innerPair,
871 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
872
yasin saplib4b8ee12021-06-13 18:25:20 +0000873 Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_ONU));
874 Instruction oltUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_OLT));
875
Andrea Campanella37f07e42021-02-16 11:24:39 +0100876 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
877 fwd.treatment().allInstructions());
878
879 Instruction innerPbitSet = null;
880 Instruction outerPbitSet = null;
881
882 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
883 innerPbitSet = setVlanPcps.get(0);
884 outerPbitSet = setVlanPcps.get(1);
885 }
886
887 TrafficTreatment innerTreatment;
888 if (noneValueVlanStatus) {
yasin saplib4b8ee12021-06-13 18:25:20 +0000889 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), onuUsMeter,
Harsh Awasthi498b5c62022-03-21 23:19:46 +0530890 writeMetadataExcludingCVlan(fwd), innerPbitSet,
Andrea Campanella37f07e42021-02-16 11:24:39 +0100891 Instructions.transition(QQ_TABLE));
892 } else {
Harsh Awasthi498b5c62022-03-21 23:19:46 +0530893 innerTreatment = buildTreatment(innerPair.getRight(), onuUsMeter, writeMetadataExcludingCVlan(fwd),
Andrea Campanella37f07e42021-02-16 11:24:39 +0100894 innerPbitSet, Instructions.transition(QQ_TABLE));
895 }
896
897 //match: in port, vlanId (0 or None)
898 //action:
899 //if vlanId None, push & set c-tag go to table 1
900 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
901 FlowRule.Builder inner = DefaultFlowRule.builder()
902 .fromApp(fwd.appId())
903 .forDevice(deviceId)
904 .makePermanent()
905 .withPriority(fwd.priority())
906 .withSelector(fwd.selector())
907 .withTreatment(innerTreatment);
908
909 PortCriterion inPort = (PortCriterion)
910 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
911
912 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
913 innerPair.getRight()).vlanId();
914
915 //match: in port, c-tag
916 //action: immediate: push s-tag, write metadata, meter and output
917 FlowRule.Builder outer = DefaultFlowRule.builder()
918 .fromApp(fwd.appId())
919 .forDevice(deviceId)
920 .forTable(QQ_TABLE)
921 .makePermanent()
922 .withPriority(fwd.priority())
923 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
yasin saplib4b8ee12021-06-13 18:25:20 +0000924 oltUsMeter, writeMetadataIncludingOnlyTp(fwd),
925 outerPbitSet, output));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100926
927 if (innerPbitSet != null) {
928 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
929 innerPbitSet).vlanPcp();
930 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
931 } else {
932 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
933 }
934
935 applyRules(fwd, inner, outer);
936 }
937
938 private void installUpstreamRulesForAnyVlan(ForwardingObjective fwd, Instruction output,
939 Pair<Instruction, Instruction> outerPair) {
940
941 log.debug("Installing upstream rules for any value vlan");
yasin saplib4b8ee12021-06-13 18:25:20 +0000942 Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_ONU));
943 Instruction oltUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_OLT));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100944
945 //match: in port and any-vlan (coming from OLT app.)
946 //action: write metadata, go to table 1 and meter
947 FlowRule.Builder inner = DefaultFlowRule.builder()
948 .fromApp(fwd.appId())
949 .forDevice(deviceId)
950 .makePermanent()
951 .withPriority(fwd.priority())
952 .withSelector(fwd.selector())
Harsh Awasthi498b5c62022-03-21 23:19:46 +0530953 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), onuUsMeter,
954 writeMetadataExcludingCVlan(fwd)));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100955
956 //match: in port and any-vlan (coming from OLT app.)
957 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
958 FlowRule.Builder outer = DefaultFlowRule.builder()
959 .fromApp(fwd.appId())
960 .forDevice(deviceId)
961 .forTable(QQ_TABLE)
962 .makePermanent()
963 .withPriority(fwd.priority())
964 .withSelector(fwd.selector())
965 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
yasin saplib4b8ee12021-06-13 18:25:20 +0000966 oltUsMeter, writeMetadataIncludingOnlyTp(fwd), output));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100967
968 applyRules(fwd, inner, outer);
969 }
970
971 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
972 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
973 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
974 boolean noneValueVlanStatus = false;
975 if (vlanMatchCriterion != null) {
976 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
977 }
978 return noneValueVlanStatus;
979 }
980
981 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
982 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
983 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
984 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
985 .findAny().orElse(null);
986
987 if (anyValueVlanCriterion == null) {
988 log.debug("Any value vlan match criteria is not found, criteria {}",
989 fwd.selector().criteria());
990 return false;
991 }
992
993 return true;
994 }
995
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100996 private boolean checkIfIsPopAndPush(ForwardingObjective fwd) {
997 TrafficTreatment treatment = fwd.treatment();
998 List<Instruction> instructions = treatment.allInstructions();
999 Optional<Instruction> vlanInstructionPush = instructions.stream()
1000 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
1001 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
1002 L2ModificationInstruction.L2SubType.VLAN_PUSH)
1003 .findAny();
1004 Optional<Instruction> vlanInstructionPop = instructions.stream()
1005 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
1006 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
1007 L2ModificationInstruction.L2SubType.VLAN_POP)
1008 .findAny();
1009 return vlanInstructionPush.isPresent() && vlanInstructionPop.isPresent();
1010 }
1011
Andrea Campanella37f07e42021-02-16 11:24:39 +01001012 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
1013 Instruction output = fwd.treatment().allInstructions().stream()
1014 .filter(i -> i.type() == Instruction.Type.OUTPUT)
1015 .findFirst().orElse(null);
1016
1017 if (output == null) {
1018 log.error("OLT {} rule has no output", direction);
1019 fail(fwd, ObjectiveError.BADPARAMS);
1020 return null;
1021 }
1022 return output;
1023 }
1024
yasin saplib4b8ee12021-06-13 18:25:20 +00001025 private Instruction fetchMeterById(ForwardingObjective fwd, String meterId) {
1026 Optional<Instructions.MeterInstruction> meter = fwd.treatment().meters().stream()
1027 .filter(meterInstruction -> meterInstruction.meterId().toString().equals(meterId)).findAny();
1028 if (meter.isEmpty()) {
1029 log.debug("Meter instruction is not found for the meterId: {} ", meterId);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001030 return null;
1031 }
yasin saplib4b8ee12021-06-13 18:25:20 +00001032 log.debug("Meter instruction is found for the meterId: {} ", meterId);
1033 return meter.get();
Andrea Campanella37f07e42021-02-16 11:24:39 +01001034 }
1035
1036 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
1037 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
1038
1039 if (writeMetadata == null) {
1040 log.warn("Write metadata is not found for the forwarding obj");
1041 fail(fwd, ObjectiveError.BADPARAMS);
1042 return null;
1043 }
1044
1045 log.debug("Write metadata is found {}", writeMetadata);
1046 return writeMetadata;
1047 }
1048
1049 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
1050 L2ModificationInstruction.L2SubType type) {
1051
1052 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
1053 fwd.treatment().allInstructions(), type);
1054
1055 if (vlanOps == null || vlanOps.isEmpty()) {
1056 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
1057 ? DOWNSTREAM : UPSTREAM;
1058 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
1059 fail(fwd, ObjectiveError.BADPARAMS);
1060 return ImmutableList.of();
1061 }
1062 return vlanOps;
1063 }
1064
1065
1066 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
1067 L2ModificationInstruction.L2SubType type) {
1068
1069 List<Instruction> vlanOperations = findL2Instructions(
1070 type,
1071 instructions);
1072 List<Instruction> vlanSets = findL2Instructions(
1073 L2ModificationInstruction.L2SubType.VLAN_ID,
1074 instructions);
1075
1076 if (vlanOperations.size() != vlanSets.size()) {
1077 return ImmutableList.of();
1078 }
1079
1080 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
1081
1082 for (int i = 0; i < vlanOperations.size(); i++) {
1083 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
1084 }
1085 return pairs;
1086 }
1087
1088 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
1089 List<Instruction> actions) {
1090 return actions.stream()
1091 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
1092 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
1093 .collect(Collectors.toList());
1094 }
1095
1096 private void provisionEthTypeBasedFilter(FilteringObjective filter,
1097 EthTypeCriterion ethType,
1098 Instructions.OutputInstruction output,
1099 L2ModificationInstruction vlanId,
1100 L2ModificationInstruction vlanPush) {
1101
1102 Instruction meter = filter.meta().metered();
1103 Instruction writeMetadata = filter.meta().writeMetadata();
1104
1105 TrafficSelector selector = buildSelector(filter.key(), ethType);
1106 TrafficTreatment treatment;
1107
1108 if (vlanPush == null || vlanId == null) {
1109 treatment = buildTreatment(output, meter, writeMetadata);
1110 } else {
1111 // we need to push the vlan because it came untagged (ATT)
1112 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
1113 }
1114
1115 buildAndApplyRule(filter, selector, treatment);
1116
1117 }
1118
1119 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
1120 IPProtocolCriterion ipProto,
1121 Instructions.OutputInstruction output,
1122 Instruction vlan, Instruction pcp) {
1123
1124 Instruction meter = filter.meta().metered();
1125 Instruction writeMetadata = filter.meta().writeMetadata();
1126
1127 // uniTagMatch
1128 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
1129 Criterion.Type.VLAN_VID);
1130
1131 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
1132 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
1133 buildAndApplyRule(filter, selector, treatment);
1134 }
1135
1136 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
1137 IPProtocolCriterion ipProto,
1138 UdpPortCriterion udpSrcPort,
1139 UdpPortCriterion udpDstPort,
1140 Instruction vlanIdInstruction,
1141 Instruction vlanPcpInstruction,
1142 Instructions.OutputInstruction output) {
1143
1144 Instruction meter = filter.meta().metered();
1145 Instruction writeMetadata = filter.meta().writeMetadata();
1146
1147 VlanIdCriterion matchVlanId = (VlanIdCriterion)
1148 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
1149
1150 TrafficSelector selector;
1151 TrafficTreatment treatment;
1152
1153 if (matchVlanId != null) {
1154 log.debug("Building selector with match VLAN, {}", matchVlanId);
1155 // in case of TT upstream the packet comes tagged and the vlan is swapped.
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301156 Criterion vlanPcp = filterForCriterion(filter.conditions(), Criterion.Type.VLAN_PCP);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001157 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301158 udpDstPort, matchVlanId, vlanPcp);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001159 treatment = buildTreatment(output, meter, writeMetadata,
1160 vlanIdInstruction, vlanPcpInstruction);
1161 } else {
1162 log.debug("Building selector with no VLAN");
1163 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
1164 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
1165 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
1166 }
1167 //In case of downstream there will be no match on the VLAN, which is null,
1168 // so it will just be output, meter, writeMetadata
1169
1170 buildAndApplyRule(filter, selector, treatment);
1171 }
1172
1173 private void provisionPPPoED(FilteringObjective filter, EthTypeCriterion ethType,
1174 Instruction vlanIdInstruction,
1175 Instruction vlanPcpInstruction,
1176 Instructions.OutputInstruction output) {
1177 Instruction meter = filter.meta().metered();
1178 Instruction writeMetadata = filter.meta().writeMetadata();
1179
1180 VlanIdCriterion matchVlanId = (VlanIdCriterion)
1181 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
1182
1183 TrafficSelector selector;
1184 TrafficTreatment treatment;
1185
1186 if (matchVlanId != null) {
1187 log.debug("Building pppoed selector with match VLAN {}.", matchVlanId);
1188 } else {
1189 log.debug("Building pppoed selector without match VLAN.");
1190 }
1191
1192 selector = buildSelector(filter.key(), ethType, matchVlanId);
1193 treatment = buildTreatment(output, meter, writeMetadata, vlanIdInstruction, vlanPcpInstruction);
1194 buildAndApplyRule(filter, selector, treatment);
1195 }
1196
1197 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
1198 TrafficTreatment treatment) {
1199 FlowRule rule = DefaultFlowRule.builder()
1200 .fromApp(filter.appId())
1201 .forDevice(deviceId)
1202 .forTable(0)
1203 .makePermanent()
1204 .withSelector(selector)
1205 .withTreatment(treatment)
1206 .withPriority(filter.priority())
1207 .build();
1208
1209 if (accumulator != null) {
1210 if (log.isDebugEnabled()) {
1211 log.debug("Adding pair to batch: {}", Pair.of(filter, rule));
1212 }
1213 accumulator.add(Pair.of(filter, rule));
1214 } else {
1215 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1216 switch (filter.type()) {
1217 case PERMIT:
1218 opsBuilder.add(rule);
1219 break;
1220 case DENY:
1221 opsBuilder.remove(rule);
1222 break;
1223 default:
1224 log.warn("Unknown filter type : {}", filter.type());
1225 fail(filter, ObjectiveError.UNSUPPORTED);
1226 }
1227 applyFlowRules(ImmutableList.of(filter), opsBuilder);
1228 }
1229 }
1230
1231 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
1232 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1233 switch (fwd.op()) {
1234 case ADD:
1235 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1236 builder.add(fwdBuilder.build());
1237 }
1238 break;
1239 case REMOVE:
1240 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1241 builder.remove(fwdBuilder.build());
1242 }
1243 break;
1244 case ADD_TO_EXISTING:
1245 break;
1246 case REMOVE_FROM_EXISTING:
1247 break;
1248 default:
1249 log.warn("Unknown forwarding operation: {}", fwd.op());
1250 }
1251
1252 applyFlowRules(ImmutableList.of(fwd), builder);
1253
1254
1255 }
1256
1257 private void applyFlowRules(List<Objective> objectives, FlowRuleOperations.Builder builder) {
1258 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1259 @Override
1260 public void onSuccess(FlowRuleOperations ops) {
1261 objectives.forEach(obj -> {
1262 pass(obj);
1263 });
1264 }
1265
1266 @Override
1267 public void onError(FlowRuleOperations ops) {
1268 objectives.forEach(obj -> {
1269 fail(obj, ObjectiveError.FLOWINSTALLATIONFAILED);
1270 });
1271
1272 }
1273 }));
1274 }
1275
1276 // Builds the batch using the accumulated flow rules
1277 private void sendFilters(List<Pair<FilteringObjective, FlowRule>> pairs) {
1278 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001279 if (log.isDebugEnabled()) {
1280 log.debug("Sending batch of {} filter-objs", pairs.size());
1281 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001282 List<Objective> filterObjs = Lists.newArrayList();
1283 // Iterates over all accumulated flow rules and then build an unique batch
1284 pairs.forEach(pair -> {
1285 FilteringObjective filter = pair.getLeft();
1286 FlowRule rule = pair.getRight();
1287 switch (filter.type()) {
1288 case PERMIT:
1289 flowOpsBuilder.add(rule);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001290 if (log.isTraceEnabled()) {
1291 log.trace("Applying add filter-obj {} to device: {}", filter.id(), deviceId);
1292 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001293 filterObjs.add(filter);
1294 break;
1295 case DENY:
1296 flowOpsBuilder.remove(rule);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001297 if (log.isTraceEnabled()) {
1298 log.trace("Deleting flow rule {} from device: {}", rule, deviceId);
1299 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001300 filterObjs.add(filter);
1301 break;
1302 default:
1303 fail(filter, ObjectiveError.UNKNOWN);
1304 log.warn("Unknown forwarding type {}", filter.type());
1305 }
1306 });
1307 if (log.isDebugEnabled()) {
1308 log.debug("Applying batch {}", flowOpsBuilder.build());
1309 }
1310 // Finally applies the operations
1311 applyFlowRules(filterObjs, flowOpsBuilder);
1312 }
1313
1314 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1315 return criteria.stream()
1316 .filter(c -> c.type().equals(type))
1317 .limit(1)
1318 .findFirst().orElse(null);
1319 }
1320
1321 private TrafficSelector buildSelector(Criterion... criteria) {
1322
1323 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1324
1325 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
1326
1327 return sBuilder.build();
1328 }
1329
1330 private TrafficTreatment buildTreatment(Instruction... instructions) {
1331
1332 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1333
1334 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
1335
1336 return tBuilder.build();
1337 }
1338
1339 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1340
1341 return Instructions.writeMetadata(
1342 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1343 }
1344
Harsh Awasthi498b5c62022-03-21 23:19:46 +05301345 /**
1346 * Creates and returns the metadata excluding cVlan.
1347 *
1348 * This function can be used for following scenario.
1349 *
1350 * The cvlan field in the metadata is used to know that the packet is double or single tagged.
1351 * For the ONU to know that the incoming packet at UNI is double tagged the innervlan is added in the cvlan field
1352 * of the metadata for the upstream table 0 flows.
1353 * As of now only FTTB workflows is using the double tagged at UNI. Other workflows, the cvlan should not be filled.
1354 * If the cvlan is filled in the metadata the onu adapter will consider double tagged
1355 * and configure rules accordingly.
1356 *
1357 * @param fwd ForwardingObjective
1358 * @return Write Metadata Instruction
1359 */
1360 private Instruction writeMetadataExcludingCVlan(ForwardingObjective fwd) {
1361
1362 return Instructions.writeMetadata(
1363 fetchWriteMetadata(fwd).metadata() & 0xFFFFFFFFFFFFL, 0L);
1364 }
1365
Andrea Campanella37f07e42021-02-16 11:24:39 +01001366 private void fail(Objective obj, ObjectiveError error) {
1367 obj.context().ifPresent(context -> context.onError(obj, error));
1368 }
1369
1370 private void pass(Objective obj) {
1371 obj.context().ifPresent(context -> context.onSuccess(obj));
1372 }
1373
1374
1375 private class InnerGroupListener implements GroupListener {
1376 @Override
1377 public void event(GroupEvent event) {
1378 GroupKey key = event.subject().appCookie();
1379 NextObjective obj = pendingGroups.getIfPresent(key);
1380 if (obj == null) {
Andrea Campanella438e1ad2021-03-26 11:41:16 +01001381 if (log.isTraceEnabled()) {
1382 log.trace("No pending group for {}, moving on", key);
1383 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001384 return;
1385 }
Andrea Campanella438e1ad2021-03-26 11:41:16 +01001386 log.debug("Event {} for group {}, handling pending" +
Andrea Campanella37f07e42021-02-16 11:24:39 +01001387 "NextGroup {}", event.type(), key, obj.id());
1388 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
1389 event.type() == GroupEvent.Type.GROUP_UPDATED) {
1390 flowObjectiveStore.putNextGroup(obj.id(), new OltPipelineGroup(key));
Andrea Campanella37f07e42021-02-16 11:24:39 +01001391 pendingGroups.invalidate(key);
Esin Karamand106e522021-03-15 14:08:48 +00001392 pass(obj);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001393 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1394 flowObjectiveStore.removeNextGroup(obj.id());
Andrea Campanella37f07e42021-02-16 11:24:39 +01001395 pendingGroups.invalidate(key);
Esin Karamand106e522021-03-15 14:08:48 +00001396 pass(obj);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001397 }
1398 }
1399 }
1400
1401 private static class OltPipelineGroup implements NextGroup {
1402
1403 private final GroupKey key;
1404
1405 public OltPipelineGroup(GroupKey key) {
1406 this.key = key;
1407 }
1408
1409 public GroupKey key() {
1410 return key;
1411 }
1412
1413 @Override
1414 public byte[] data() {
1415 return appKryo.serialize(key);
1416 }
1417
1418 }
1419
1420 @Override
1421 public List<String> getNextMappings(NextGroup nextGroup) {
1422 // TODO Implementation deferred to vendor
1423 return null;
1424 }
1425
1426 // Flow rules accumulator for reducing the number of transactions required to the devices.
1427 private final class ObjectiveAccumulator
1428 extends AbstractAccumulator<Pair<FilteringObjective, FlowRule>> {
1429
1430 ObjectiveAccumulator(int maxFilter, int maxBatchMS, int maxIdleMS) {
1431 super(TIMER, maxFilter, maxBatchMS, maxIdleMS);
1432 }
1433
1434 @Override
1435 public void processItems(List<Pair<FilteringObjective, FlowRule>> pairs) {
1436 // Triggers creation of a batch using the list of flowrules generated from objs.
1437 accumulatorExecutorService.execute(new FlowRulesBuilderTask(pairs));
1438 }
1439 }
1440
1441 // Task for building batch of flow rules in a separate thread.
1442 private final class FlowRulesBuilderTask implements Runnable {
1443 private final List<Pair<FilteringObjective, FlowRule>> pairs;
1444
1445 FlowRulesBuilderTask(List<Pair<FilteringObjective, FlowRule>> pairs) {
1446 this.pairs = pairs;
1447 }
1448
1449 @Override
1450 public void run() {
1451 try {
1452 sendFilters(pairs);
1453 } catch (Exception e) {
1454 log.warn("Unable to send objectives", e);
1455 }
1456 }
1457 }
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +01001458
1459 private void installUpstreamRulesForAnyOuterVlan(ForwardingObjective fwd, Instruction output,
1460 Pair<Instruction, Instruction> innerPair,
1461 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
1462
1463 Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_ONU));
1464 Instruction oltUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_OLT));
1465
1466 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
1467 fwd.treatment().allInstructions());
1468
1469 Instruction innerPbitSet = null;
1470 Instruction outerPbitSet = null;
1471
1472 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
1473 innerPbitSet = setVlanPcps.get(0);
1474 outerPbitSet = setVlanPcps.get(1);
1475 }
1476
1477 TrafficTreatment innerTreatment;
1478 if (noneValueVlanStatus) {
1479 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), onuUsMeter,
Harsh Awasthi498b5c62022-03-21 23:19:46 +05301480 writeMetadataExcludingCVlan(fwd), innerPbitSet,
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +01001481 Instructions.transition(QQ_TABLE));
1482 } else {
Harsh Awasthi498b5c62022-03-21 23:19:46 +05301483 innerTreatment = buildTreatment(innerPair.getRight(), onuUsMeter, writeMetadataExcludingCVlan(fwd),
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +01001484 innerPbitSet, Instructions.transition(QQ_TABLE));
1485 }
1486
1487 //match: in port, vlanId (0 or None)
1488 //action:
1489 //if vlanId None, push & set c-tag go to table 1
1490 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
1491 FlowRule.Builder inner = DefaultFlowRule.builder()
1492 .fromApp(fwd.appId())
1493 .forDevice(deviceId)
1494 .makePermanent()
1495 .withPriority(fwd.priority())
1496 .withSelector(fwd.selector())
1497 .withTreatment(innerTreatment);
1498
1499 PortCriterion inPort = (PortCriterion)
1500 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
1501
1502 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
1503 innerPair.getRight()).vlanId();
1504
1505 //match: in port, c-tag
1506 //action: immediate: push s-tag, write metadata, meter and output
1507 FlowRule.Builder outer = DefaultFlowRule.builder()
1508 .fromApp(fwd.appId())
1509 .forDevice(deviceId)
1510 .forTable(QQ_TABLE)
1511 .makePermanent()
1512 .withPriority(fwd.priority())
1513 .withTreatment(buildTreatment(oltUsMeter, writeMetadataIncludingOnlyTp(fwd),
1514 outerPbitSet, output));
1515
1516 if (innerPbitSet != null) {
1517 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
1518 innerPbitSet).vlanPcp();
1519 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
1520 } else {
1521 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
1522 }
1523
1524 applyRules(fwd, inner, outer);
1525 }
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301526
1527 private void processFttbRules(ForwardingObjective fwd) {
1528 Annotations annotations = fwd.annotations();
1529 String direction = annotations.value(FTTB_FLOW_DIRECTION);
1530 String serviceName = annotations.value(FTTB_SERVICE_NAME);
1531
1532 if (direction == null) {
1533 log.error("Flow direction not found for Fttb rule {} ", fwd);
1534 return;
1535 }
1536
1537 switch (direction) {
1538 case FTTB_FLOW_UPSTREAM:
1539 processUpstreamFttbRules(fwd, serviceName);
1540 break;
1541 case FTTB_FLOW_DOWNSTREAM:
1542 processDownstreamFttbRules(fwd, serviceName);
1543 break;
1544 default:
1545 log.error("Invalid flow direction {}, for {} ", direction, fwd);
1546 }
1547 }
1548
1549 private void processUpstreamFttbRules(ForwardingObjective fwd, String serviceName) {
1550 TrafficSelector selector = fwd.selector();
1551 TrafficTreatment treatment = fwd.treatment();
1552
1553 // Selectors
1554 Criterion inPortCriterion = selector.getCriterion(Criterion.Type.IN_PORT);
1555 Criterion cVlanVidCriterion = selector.getCriterion(Criterion.Type.VLAN_VID);
1556 Criterion cTagPriority = selector.getCriterion(Criterion.Type.VLAN_PCP);
1557 Criterion ethSrcCriterion = selector.getCriterion(Criterion.Type.ETH_SRC);
1558
1559 // Instructions
1560 L2ModificationInstruction.ModVlanIdInstruction sVlanSetVid = null;
1561 L2ModificationInstruction.ModVlanPcpInstruction sTagPrioritySet = null;
1562
1563 List<Instruction> instructions = treatment.allInstructions();
1564 List<Instruction> vlanIdL2Instructions = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_ID,
1565 instructions);
1566 List<Instruction> vlanPcpL2Instructions = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
1567 instructions);
1568
1569 if (!vlanIdL2Instructions.isEmpty()) {
1570 sVlanSetVid = (L2ModificationInstruction.ModVlanIdInstruction) vlanIdL2Instructions.get(0);
1571 }
1572
1573 if (!vlanPcpL2Instructions.isEmpty()) {
1574 sTagPrioritySet = (L2ModificationInstruction.ModVlanPcpInstruction) vlanPcpL2Instructions.get(0);
1575 }
1576
1577 Instruction output = fetchOutput(fwd, UPSTREAM);
1578 Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_ONU));
1579 Instruction oltUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_OLT));
1580
1581 TrafficSelector oltSelector, onuSelector;
1582 TrafficTreatment oltTreatment, onuTreatment;
1583
1584 switch (serviceName) {
1585 case FTTB_SERVICE_DPU_MGMT_TRAFFIC:
1586 case FTTB_SERVICE_DPU_ANCP_TRAFFIC:
1587 onuSelector = buildSelector(inPortCriterion, cVlanVidCriterion, cTagPriority);
1588 onuTreatment = buildTreatment(sVlanSetVid, sTagPrioritySet, onuUsMeter,
1589 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE));
1590
1591 oltSelector = buildSelector(inPortCriterion, ethSrcCriterion,
1592 Criteria.matchVlanId(sVlanSetVid.vlanId()));
1593 oltTreatment = buildTreatment(oltUsMeter, fetchWriteMetadata(fwd), output);
1594 break;
1595
1596 case FTTB_SERVICE_SUBSCRIBER_TRAFFIC:
1597 onuSelector = buildSelector(inPortCriterion, cVlanVidCriterion);
1598 onuTreatment = buildTreatment(onuUsMeter, fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE));
1599
1600 oltSelector = buildSelector(inPortCriterion, cVlanVidCriterion);
1601 oltTreatment = buildTreatment(sVlanSetVid, oltUsMeter, fetchWriteMetadata(fwd), output);
1602 break;
1603 default:
1604 log.error("Unknown service type for Fttb rule : {}", fwd);
1605 return;
1606 }
1607
1608 FlowRule.Builder onuBuilder = DefaultFlowRule.builder()
1609 .fromApp(fwd.appId())
1610 .forDevice(deviceId)
1611 .makePermanent()
1612 .withPriority(fwd.priority())
1613 .withSelector(onuSelector)
1614 .withTreatment(onuTreatment);
1615
1616 FlowRule.Builder oltBuilder = DefaultFlowRule.builder()
1617 .fromApp(fwd.appId())
1618 .forDevice(deviceId)
1619 .forTable(QQ_TABLE)
1620 .makePermanent()
1621 .withPriority(fwd.priority())
1622 .withSelector(oltSelector)
1623 .withTreatment(oltTreatment);
1624
1625 applyRules(fwd, onuBuilder, oltBuilder);
1626 }
1627
1628 private void processDownstreamFttbRules(ForwardingObjective fwd, String serviceName) {
1629 TrafficSelector selector = fwd.selector();
1630 TrafficTreatment treatment = fwd.treatment();
1631
1632 // Selectors
1633 Criterion inPortCriterion = selector.getCriterion(Criterion.Type.IN_PORT);
1634 Criterion sVlanVidCriterion = selector.getCriterion(Criterion.Type.VLAN_VID);
1635 Criterion sTagPriority = selector.getCriterion(Criterion.Type.VLAN_PCP);
1636 Criterion ethDstCriterion = selector.getCriterion(Criterion.Type.ETH_DST);
1637 Criterion metadataSelector = selector.getCriterion(Criterion.Type.METADATA);
1638
1639 // Instructions
1640 L2ModificationInstruction.ModVlanIdInstruction cVlanSetVid = null;
1641 L2ModificationInstruction.ModVlanPcpInstruction cTagPrioritySet = null;
1642
1643 List<Instruction> instructions = treatment.allInstructions();
1644 List<Instruction> vlanIdL2Instructions = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_ID,
1645 instructions);
1646 List<Instruction> vlanPcpL2Instructions = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
1647 instructions);
1648
1649 if (!vlanIdL2Instructions.isEmpty()) {
1650 cVlanSetVid = (L2ModificationInstruction.ModVlanIdInstruction) vlanIdL2Instructions.get(0);
1651 }
1652
1653 if (!vlanPcpL2Instructions.isEmpty()) {
1654 cTagPrioritySet = (L2ModificationInstruction.ModVlanPcpInstruction) vlanPcpL2Instructions.get(0);
1655 }
1656
1657 Instruction output = fetchOutput(fwd, DOWNSTREAM);
1658 Instruction oltDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_OLT));
1659 Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_ONU));
1660
1661 TrafficSelector oltSelector, onuSelector;
1662 TrafficTreatment oltTreatment, onuTreatment;
1663
1664 switch (serviceName) {
1665 case FTTB_SERVICE_DPU_MGMT_TRAFFIC:
1666 case FTTB_SERVICE_DPU_ANCP_TRAFFIC:
1667 oltSelector = buildSelector(inPortCriterion, ethDstCriterion,
1668 sVlanVidCriterion);
1669 oltTreatment = buildTreatment(oltDsMeter, fetchWriteMetadata(fwd),
1670 Instructions.transition(QQ_TABLE));
1671
1672 onuSelector = buildSelector(inPortCriterion, sVlanVidCriterion, sTagPriority, ethDstCriterion);
1673 onuTreatment = buildTreatment(cVlanSetVid, cTagPrioritySet, onuUsMeter,
1674 fetchWriteMetadata(fwd), output);
1675 break;
1676
1677 case FTTB_SERVICE_SUBSCRIBER_TRAFFIC:
1678 oltSelector = buildSelector(inPortCriterion, sVlanVidCriterion);
1679 oltTreatment = buildTreatment(cVlanSetVid, oltDsMeter, fetchWriteMetadata(fwd),
1680 Instructions.transition(QQ_TABLE));
1681
1682 onuSelector = buildSelector(inPortCriterion, Criteria.matchVlanId(cVlanSetVid.vlanId()),
1683 metadataSelector);
1684 onuTreatment = buildTreatment(onuUsMeter, fetchWriteMetadata(fwd), output);
1685 break;
1686
1687 default:
1688 log.error("Unknown service type for Fttb rule : {}", fwd);
1689 return;
1690 }
1691
1692 FlowRule.Builder oltBuilder = DefaultFlowRule.builder()
1693 .fromApp(fwd.appId())
1694 .forDevice(deviceId)
1695 .makePermanent()
1696 .withPriority(fwd.priority())
1697 .withSelector(oltSelector)
1698 .withTreatment(oltTreatment);
1699
1700 FlowRule.Builder onuBuilder = DefaultFlowRule.builder()
1701 .fromApp(fwd.appId())
1702 .forDevice(deviceId)
1703 .forTable(QQ_TABLE)
1704 .makePermanent()
1705 .withPriority(fwd.priority())
1706 .withSelector(onuSelector)
1707 .withTreatment(onuTreatment);
1708
1709 applyRules(fwd, onuBuilder, oltBuilder);
1710 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001711}