blob: 493680ba71de573deb595143e2e18a5720128594 [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,
Andrea Campanella37f07e42021-02-16 11:24:39 +0100890 fetchWriteMetadata(fwd), innerPbitSet,
891 Instructions.transition(QQ_TABLE));
892 } else {
yasin saplib4b8ee12021-06-13 18:25:20 +0000893 innerTreatment = buildTreatment(innerPair.getRight(), onuUsMeter, fetchWriteMetadata(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())
yasin saplib4b8ee12021-06-13 18:25:20 +0000953 .withTreatment(buildTreatment(Instructions.transition(QQ_TABLE), onuUsMeter, fetchWriteMetadata(fwd)));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100954
955 //match: in port and any-vlan (coming from OLT app.)
956 //action: immediate: push:QinQ, vlanId (s-tag), write metadata, meter and output
957 FlowRule.Builder outer = DefaultFlowRule.builder()
958 .fromApp(fwd.appId())
959 .forDevice(deviceId)
960 .forTable(QQ_TABLE)
961 .makePermanent()
962 .withPriority(fwd.priority())
963 .withSelector(fwd.selector())
964 .withTreatment(buildTreatment(outerPair.getLeft(), outerPair.getRight(),
yasin saplib4b8ee12021-06-13 18:25:20 +0000965 oltUsMeter, writeMetadataIncludingOnlyTp(fwd), output));
Andrea Campanella37f07e42021-02-16 11:24:39 +0100966
967 applyRules(fwd, inner, outer);
968 }
969
970 private boolean checkNoneVlanCriteria(ForwardingObjective fwd) {
971 // Add the VLAN_PUSH treatment if we're matching on VlanId.NONE
972 Criterion vlanMatchCriterion = filterForCriterion(fwd.selector().criteria(), Criterion.Type.VLAN_VID);
973 boolean noneValueVlanStatus = false;
974 if (vlanMatchCriterion != null) {
975 noneValueVlanStatus = ((VlanIdCriterion) vlanMatchCriterion).vlanId().equals(VlanId.NONE);
976 }
977 return noneValueVlanStatus;
978 }
979
980 private boolean checkAnyVlanMatchCriteria(ForwardingObjective fwd) {
981 Criterion anyValueVlanCriterion = fwd.selector().criteria().stream()
982 .filter(c -> c.type().equals(Criterion.Type.VLAN_VID))
983 .filter(vc -> ((VlanIdCriterion) vc).vlanId().toShort() == VlanId.ANY_VALUE)
984 .findAny().orElse(null);
985
986 if (anyValueVlanCriterion == null) {
987 log.debug("Any value vlan match criteria is not found, criteria {}",
988 fwd.selector().criteria());
989 return false;
990 }
991
992 return true;
993 }
994
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +0100995 private boolean checkIfIsPopAndPush(ForwardingObjective fwd) {
996 TrafficTreatment treatment = fwd.treatment();
997 List<Instruction> instructions = treatment.allInstructions();
998 Optional<Instruction> vlanInstructionPush = instructions.stream()
999 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
1000 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
1001 L2ModificationInstruction.L2SubType.VLAN_PUSH)
1002 .findAny();
1003 Optional<Instruction> vlanInstructionPop = instructions.stream()
1004 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
1005 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
1006 L2ModificationInstruction.L2SubType.VLAN_POP)
1007 .findAny();
1008 return vlanInstructionPush.isPresent() && vlanInstructionPop.isPresent();
1009 }
1010
Andrea Campanella37f07e42021-02-16 11:24:39 +01001011 private Instruction fetchOutput(ForwardingObjective fwd, String direction) {
1012 Instruction output = fwd.treatment().allInstructions().stream()
1013 .filter(i -> i.type() == Instruction.Type.OUTPUT)
1014 .findFirst().orElse(null);
1015
1016 if (output == null) {
1017 log.error("OLT {} rule has no output", direction);
1018 fail(fwd, ObjectiveError.BADPARAMS);
1019 return null;
1020 }
1021 return output;
1022 }
1023
yasin saplib4b8ee12021-06-13 18:25:20 +00001024 private Instruction fetchMeterById(ForwardingObjective fwd, String meterId) {
1025 Optional<Instructions.MeterInstruction> meter = fwd.treatment().meters().stream()
1026 .filter(meterInstruction -> meterInstruction.meterId().toString().equals(meterId)).findAny();
1027 if (meter.isEmpty()) {
1028 log.debug("Meter instruction is not found for the meterId: {} ", meterId);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001029 return null;
1030 }
yasin saplib4b8ee12021-06-13 18:25:20 +00001031 log.debug("Meter instruction is found for the meterId: {} ", meterId);
1032 return meter.get();
Andrea Campanella37f07e42021-02-16 11:24:39 +01001033 }
1034
1035 private Instructions.MetadataInstruction fetchWriteMetadata(ForwardingObjective fwd) {
1036 Instructions.MetadataInstruction writeMetadata = fwd.treatment().writeMetadata();
1037
1038 if (writeMetadata == null) {
1039 log.warn("Write metadata is not found for the forwarding obj");
1040 fail(fwd, ObjectiveError.BADPARAMS);
1041 return null;
1042 }
1043
1044 log.debug("Write metadata is found {}", writeMetadata);
1045 return writeMetadata;
1046 }
1047
1048 private List<Pair<Instruction, Instruction>> vlanOps(ForwardingObjective fwd,
1049 L2ModificationInstruction.L2SubType type) {
1050
1051 List<Pair<Instruction, Instruction>> vlanOps = findVlanOps(
1052 fwd.treatment().allInstructions(), type);
1053
1054 if (vlanOps == null || vlanOps.isEmpty()) {
1055 String direction = type == L2ModificationInstruction.L2SubType.VLAN_POP
1056 ? DOWNSTREAM : UPSTREAM;
1057 log.error("Missing vlan operations in {} forwarding: {}", direction, fwd);
1058 fail(fwd, ObjectiveError.BADPARAMS);
1059 return ImmutableList.of();
1060 }
1061 return vlanOps;
1062 }
1063
1064
1065 private List<Pair<Instruction, Instruction>> findVlanOps(List<Instruction> instructions,
1066 L2ModificationInstruction.L2SubType type) {
1067
1068 List<Instruction> vlanOperations = findL2Instructions(
1069 type,
1070 instructions);
1071 List<Instruction> vlanSets = findL2Instructions(
1072 L2ModificationInstruction.L2SubType.VLAN_ID,
1073 instructions);
1074
1075 if (vlanOperations.size() != vlanSets.size()) {
1076 return ImmutableList.of();
1077 }
1078
1079 List<Pair<Instruction, Instruction>> pairs = Lists.newArrayList();
1080
1081 for (int i = 0; i < vlanOperations.size(); i++) {
1082 pairs.add(new ImmutablePair<>(vlanOperations.get(i), vlanSets.get(i)));
1083 }
1084 return pairs;
1085 }
1086
1087 private List<Instruction> findL2Instructions(L2ModificationInstruction.L2SubType subType,
1088 List<Instruction> actions) {
1089 return actions.stream()
1090 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
1091 .filter(i -> ((L2ModificationInstruction) i).subtype() == subType)
1092 .collect(Collectors.toList());
1093 }
1094
1095 private void provisionEthTypeBasedFilter(FilteringObjective filter,
1096 EthTypeCriterion ethType,
1097 Instructions.OutputInstruction output,
1098 L2ModificationInstruction vlanId,
1099 L2ModificationInstruction vlanPush) {
1100
1101 Instruction meter = filter.meta().metered();
1102 Instruction writeMetadata = filter.meta().writeMetadata();
1103
1104 TrafficSelector selector = buildSelector(filter.key(), ethType);
1105 TrafficTreatment treatment;
1106
1107 if (vlanPush == null || vlanId == null) {
1108 treatment = buildTreatment(output, meter, writeMetadata);
1109 } else {
1110 // we need to push the vlan because it came untagged (ATT)
1111 treatment = buildTreatment(output, meter, vlanPush, vlanId, writeMetadata);
1112 }
1113
1114 buildAndApplyRule(filter, selector, treatment);
1115
1116 }
1117
1118 private void provisionIgmp(FilteringObjective filter, EthTypeCriterion ethType,
1119 IPProtocolCriterion ipProto,
1120 Instructions.OutputInstruction output,
1121 Instruction vlan, Instruction pcp) {
1122
1123 Instruction meter = filter.meta().metered();
1124 Instruction writeMetadata = filter.meta().writeMetadata();
1125
1126 // uniTagMatch
1127 VlanIdCriterion vlanId = (VlanIdCriterion) filterForCriterion(filter.conditions(),
1128 Criterion.Type.VLAN_VID);
1129
1130 TrafficSelector selector = buildSelector(filter.key(), ethType, ipProto, vlanId);
1131 TrafficTreatment treatment = buildTreatment(output, vlan, pcp, meter, writeMetadata);
1132 buildAndApplyRule(filter, selector, treatment);
1133 }
1134
1135 private void provisionDhcp(FilteringObjective filter, EthTypeCriterion ethType,
1136 IPProtocolCriterion ipProto,
1137 UdpPortCriterion udpSrcPort,
1138 UdpPortCriterion udpDstPort,
1139 Instruction vlanIdInstruction,
1140 Instruction vlanPcpInstruction,
1141 Instructions.OutputInstruction output) {
1142
1143 Instruction meter = filter.meta().metered();
1144 Instruction writeMetadata = filter.meta().writeMetadata();
1145
1146 VlanIdCriterion matchVlanId = (VlanIdCriterion)
1147 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
1148
1149 TrafficSelector selector;
1150 TrafficTreatment treatment;
1151
1152 if (matchVlanId != null) {
1153 log.debug("Building selector with match VLAN, {}", matchVlanId);
1154 // in case of TT upstream the packet comes tagged and the vlan is swapped.
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301155 Criterion vlanPcp = filterForCriterion(filter.conditions(), Criterion.Type.VLAN_PCP);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001156 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort,
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301157 udpDstPort, matchVlanId, vlanPcp);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001158 treatment = buildTreatment(output, meter, writeMetadata,
1159 vlanIdInstruction, vlanPcpInstruction);
1160 } else {
1161 log.debug("Building selector with no VLAN");
1162 // in case of ATT upstream the packet comes in untagged and we need to push the vlan
1163 selector = buildSelector(filter.key(), ethType, ipProto, udpSrcPort, udpDstPort);
1164 treatment = buildTreatment(output, meter, vlanIdInstruction, writeMetadata);
1165 }
1166 //In case of downstream there will be no match on the VLAN, which is null,
1167 // so it will just be output, meter, writeMetadata
1168
1169 buildAndApplyRule(filter, selector, treatment);
1170 }
1171
1172 private void provisionPPPoED(FilteringObjective filter, EthTypeCriterion ethType,
1173 Instruction vlanIdInstruction,
1174 Instruction vlanPcpInstruction,
1175 Instructions.OutputInstruction output) {
1176 Instruction meter = filter.meta().metered();
1177 Instruction writeMetadata = filter.meta().writeMetadata();
1178
1179 VlanIdCriterion matchVlanId = (VlanIdCriterion)
1180 filterForCriterion(filter.conditions(), Criterion.Type.VLAN_VID);
1181
1182 TrafficSelector selector;
1183 TrafficTreatment treatment;
1184
1185 if (matchVlanId != null) {
1186 log.debug("Building pppoed selector with match VLAN {}.", matchVlanId);
1187 } else {
1188 log.debug("Building pppoed selector without match VLAN.");
1189 }
1190
1191 selector = buildSelector(filter.key(), ethType, matchVlanId);
1192 treatment = buildTreatment(output, meter, writeMetadata, vlanIdInstruction, vlanPcpInstruction);
1193 buildAndApplyRule(filter, selector, treatment);
1194 }
1195
1196 private void buildAndApplyRule(FilteringObjective filter, TrafficSelector selector,
1197 TrafficTreatment treatment) {
1198 FlowRule rule = DefaultFlowRule.builder()
1199 .fromApp(filter.appId())
1200 .forDevice(deviceId)
1201 .forTable(0)
1202 .makePermanent()
1203 .withSelector(selector)
1204 .withTreatment(treatment)
1205 .withPriority(filter.priority())
1206 .build();
1207
1208 if (accumulator != null) {
1209 if (log.isDebugEnabled()) {
1210 log.debug("Adding pair to batch: {}", Pair.of(filter, rule));
1211 }
1212 accumulator.add(Pair.of(filter, rule));
1213 } else {
1214 FlowRuleOperations.Builder opsBuilder = FlowRuleOperations.builder();
1215 switch (filter.type()) {
1216 case PERMIT:
1217 opsBuilder.add(rule);
1218 break;
1219 case DENY:
1220 opsBuilder.remove(rule);
1221 break;
1222 default:
1223 log.warn("Unknown filter type : {}", filter.type());
1224 fail(filter, ObjectiveError.UNSUPPORTED);
1225 }
1226 applyFlowRules(ImmutableList.of(filter), opsBuilder);
1227 }
1228 }
1229
1230 private void applyRules(ForwardingObjective fwd, FlowRule.Builder... fwdBuilders) {
1231 FlowRuleOperations.Builder builder = FlowRuleOperations.builder();
1232 switch (fwd.op()) {
1233 case ADD:
1234 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1235 builder.add(fwdBuilder.build());
1236 }
1237 break;
1238 case REMOVE:
1239 for (FlowRule.Builder fwdBuilder : fwdBuilders) {
1240 builder.remove(fwdBuilder.build());
1241 }
1242 break;
1243 case ADD_TO_EXISTING:
1244 break;
1245 case REMOVE_FROM_EXISTING:
1246 break;
1247 default:
1248 log.warn("Unknown forwarding operation: {}", fwd.op());
1249 }
1250
1251 applyFlowRules(ImmutableList.of(fwd), builder);
1252
1253
1254 }
1255
1256 private void applyFlowRules(List<Objective> objectives, FlowRuleOperations.Builder builder) {
1257 flowRuleService.apply(builder.build(new FlowRuleOperationsContext() {
1258 @Override
1259 public void onSuccess(FlowRuleOperations ops) {
1260 objectives.forEach(obj -> {
1261 pass(obj);
1262 });
1263 }
1264
1265 @Override
1266 public void onError(FlowRuleOperations ops) {
1267 objectives.forEach(obj -> {
1268 fail(obj, ObjectiveError.FLOWINSTALLATIONFAILED);
1269 });
1270
1271 }
1272 }));
1273 }
1274
1275 // Builds the batch using the accumulated flow rules
1276 private void sendFilters(List<Pair<FilteringObjective, FlowRule>> pairs) {
1277 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001278 if (log.isDebugEnabled()) {
1279 log.debug("Sending batch of {} filter-objs", pairs.size());
1280 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001281 List<Objective> filterObjs = Lists.newArrayList();
1282 // Iterates over all accumulated flow rules and then build an unique batch
1283 pairs.forEach(pair -> {
1284 FilteringObjective filter = pair.getLeft();
1285 FlowRule rule = pair.getRight();
1286 switch (filter.type()) {
1287 case PERMIT:
1288 flowOpsBuilder.add(rule);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001289 if (log.isTraceEnabled()) {
1290 log.trace("Applying add filter-obj {} to device: {}", filter.id(), deviceId);
1291 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001292 filterObjs.add(filter);
1293 break;
1294 case DENY:
1295 flowOpsBuilder.remove(rule);
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001296 if (log.isTraceEnabled()) {
1297 log.trace("Deleting flow rule {} from device: {}", rule, deviceId);
1298 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001299 filterObjs.add(filter);
1300 break;
1301 default:
1302 fail(filter, ObjectiveError.UNKNOWN);
1303 log.warn("Unknown forwarding type {}", filter.type());
1304 }
1305 });
1306 if (log.isDebugEnabled()) {
1307 log.debug("Applying batch {}", flowOpsBuilder.build());
1308 }
1309 // Finally applies the operations
1310 applyFlowRules(filterObjs, flowOpsBuilder);
1311 }
1312
1313 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
1314 return criteria.stream()
1315 .filter(c -> c.type().equals(type))
1316 .limit(1)
1317 .findFirst().orElse(null);
1318 }
1319
1320 private TrafficSelector buildSelector(Criterion... criteria) {
1321
1322 TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
1323
1324 Arrays.stream(criteria).filter(Objects::nonNull).forEach(sBuilder::add);
1325
1326 return sBuilder.build();
1327 }
1328
1329 private TrafficTreatment buildTreatment(Instruction... instructions) {
1330
1331 TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
1332
1333 Arrays.stream(instructions).filter(Objects::nonNull).forEach(tBuilder::add);
1334
1335 return tBuilder.build();
1336 }
1337
1338 private Instruction writeMetadataIncludingOnlyTp(ForwardingObjective fwd) {
1339
1340 return Instructions.writeMetadata(
1341 fetchWriteMetadata(fwd).metadata() & 0xFFFF00000000L, 0L);
1342 }
1343
1344 private void fail(Objective obj, ObjectiveError error) {
1345 obj.context().ifPresent(context -> context.onError(obj, error));
1346 }
1347
1348 private void pass(Objective obj) {
1349 obj.context().ifPresent(context -> context.onSuccess(obj));
1350 }
1351
1352
1353 private class InnerGroupListener implements GroupListener {
1354 @Override
1355 public void event(GroupEvent event) {
1356 GroupKey key = event.subject().appCookie();
1357 NextObjective obj = pendingGroups.getIfPresent(key);
1358 if (obj == null) {
Andrea Campanella438e1ad2021-03-26 11:41:16 +01001359 if (log.isTraceEnabled()) {
1360 log.trace("No pending group for {}, moving on", key);
1361 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001362 return;
1363 }
Andrea Campanella438e1ad2021-03-26 11:41:16 +01001364 log.debug("Event {} for group {}, handling pending" +
Andrea Campanella37f07e42021-02-16 11:24:39 +01001365 "NextGroup {}", event.type(), key, obj.id());
1366 if (event.type() == GroupEvent.Type.GROUP_ADDED ||
1367 event.type() == GroupEvent.Type.GROUP_UPDATED) {
1368 flowObjectiveStore.putNextGroup(obj.id(), new OltPipelineGroup(key));
Andrea Campanella37f07e42021-02-16 11:24:39 +01001369 pendingGroups.invalidate(key);
Esin Karamand106e522021-03-15 14:08:48 +00001370 pass(obj);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001371 } else if (event.type() == GroupEvent.Type.GROUP_REMOVED) {
1372 flowObjectiveStore.removeNextGroup(obj.id());
Andrea Campanella37f07e42021-02-16 11:24:39 +01001373 pendingGroups.invalidate(key);
Esin Karamand106e522021-03-15 14:08:48 +00001374 pass(obj);
Andrea Campanella37f07e42021-02-16 11:24:39 +01001375 }
1376 }
1377 }
1378
1379 private static class OltPipelineGroup implements NextGroup {
1380
1381 private final GroupKey key;
1382
1383 public OltPipelineGroup(GroupKey key) {
1384 this.key = key;
1385 }
1386
1387 public GroupKey key() {
1388 return key;
1389 }
1390
1391 @Override
1392 public byte[] data() {
1393 return appKryo.serialize(key);
1394 }
1395
1396 }
1397
1398 @Override
1399 public List<String> getNextMappings(NextGroup nextGroup) {
1400 // TODO Implementation deferred to vendor
1401 return null;
1402 }
1403
1404 // Flow rules accumulator for reducing the number of transactions required to the devices.
1405 private final class ObjectiveAccumulator
1406 extends AbstractAccumulator<Pair<FilteringObjective, FlowRule>> {
1407
1408 ObjectiveAccumulator(int maxFilter, int maxBatchMS, int maxIdleMS) {
1409 super(TIMER, maxFilter, maxBatchMS, maxIdleMS);
1410 }
1411
1412 @Override
1413 public void processItems(List<Pair<FilteringObjective, FlowRule>> pairs) {
1414 // Triggers creation of a batch using the list of flowrules generated from objs.
1415 accumulatorExecutorService.execute(new FlowRulesBuilderTask(pairs));
1416 }
1417 }
1418
1419 // Task for building batch of flow rules in a separate thread.
1420 private final class FlowRulesBuilderTask implements Runnable {
1421 private final List<Pair<FilteringObjective, FlowRule>> pairs;
1422
1423 FlowRulesBuilderTask(List<Pair<FilteringObjective, FlowRule>> pairs) {
1424 this.pairs = pairs;
1425 }
1426
1427 @Override
1428 public void run() {
1429 try {
1430 sendFilters(pairs);
1431 } catch (Exception e) {
1432 log.warn("Unable to send objectives", e);
1433 }
1434 }
1435 }
Maria Carmela Cascino067ee4d2021-11-02 13:14:43 +01001436
1437 private void installUpstreamRulesForAnyOuterVlan(ForwardingObjective fwd, Instruction output,
1438 Pair<Instruction, Instruction> innerPair,
1439 Pair<Instruction, Instruction> outerPair, Boolean noneValueVlanStatus) {
1440
1441 Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_ONU));
1442 Instruction oltUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_OLT));
1443
1444 List<Instruction> setVlanPcps = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
1445 fwd.treatment().allInstructions());
1446
1447 Instruction innerPbitSet = null;
1448 Instruction outerPbitSet = null;
1449
1450 if (setVlanPcps != null && !setVlanPcps.isEmpty()) {
1451 innerPbitSet = setVlanPcps.get(0);
1452 outerPbitSet = setVlanPcps.get(1);
1453 }
1454
1455 TrafficTreatment innerTreatment;
1456 if (noneValueVlanStatus) {
1457 innerTreatment = buildTreatment(innerPair.getLeft(), innerPair.getRight(), onuUsMeter,
1458 fetchWriteMetadata(fwd), innerPbitSet,
1459 Instructions.transition(QQ_TABLE));
1460 } else {
1461 innerTreatment = buildTreatment(innerPair.getRight(), onuUsMeter, fetchWriteMetadata(fwd),
1462 innerPbitSet, Instructions.transition(QQ_TABLE));
1463 }
1464
1465 //match: in port, vlanId (0 or None)
1466 //action:
1467 //if vlanId None, push & set c-tag go to table 1
1468 //if vlanId 0 or any specific vlan, set c-tag, write metadata, meter and go to table 1
1469 FlowRule.Builder inner = DefaultFlowRule.builder()
1470 .fromApp(fwd.appId())
1471 .forDevice(deviceId)
1472 .makePermanent()
1473 .withPriority(fwd.priority())
1474 .withSelector(fwd.selector())
1475 .withTreatment(innerTreatment);
1476
1477 PortCriterion inPort = (PortCriterion)
1478 fwd.selector().getCriterion(Criterion.Type.IN_PORT);
1479
1480 VlanId cVlanId = ((L2ModificationInstruction.ModVlanIdInstruction)
1481 innerPair.getRight()).vlanId();
1482
1483 //match: in port, c-tag
1484 //action: immediate: push s-tag, write metadata, meter and output
1485 FlowRule.Builder outer = DefaultFlowRule.builder()
1486 .fromApp(fwd.appId())
1487 .forDevice(deviceId)
1488 .forTable(QQ_TABLE)
1489 .makePermanent()
1490 .withPriority(fwd.priority())
1491 .withTreatment(buildTreatment(oltUsMeter, writeMetadataIncludingOnlyTp(fwd),
1492 outerPbitSet, output));
1493
1494 if (innerPbitSet != null) {
1495 byte innerPbit = ((L2ModificationInstruction.ModVlanPcpInstruction)
1496 innerPbitSet).vlanPcp();
1497 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId), Criteria.matchVlanPcp(innerPbit)));
1498 } else {
1499 outer.withSelector(buildSelector(inPort, Criteria.matchVlanId(cVlanId)));
1500 }
1501
1502 applyRules(fwd, inner, outer);
1503 }
Harsh Awasthic1e4bf52022-02-09 14:14:14 +05301504
1505 private void processFttbRules(ForwardingObjective fwd) {
1506 Annotations annotations = fwd.annotations();
1507 String direction = annotations.value(FTTB_FLOW_DIRECTION);
1508 String serviceName = annotations.value(FTTB_SERVICE_NAME);
1509
1510 if (direction == null) {
1511 log.error("Flow direction not found for Fttb rule {} ", fwd);
1512 return;
1513 }
1514
1515 switch (direction) {
1516 case FTTB_FLOW_UPSTREAM:
1517 processUpstreamFttbRules(fwd, serviceName);
1518 break;
1519 case FTTB_FLOW_DOWNSTREAM:
1520 processDownstreamFttbRules(fwd, serviceName);
1521 break;
1522 default:
1523 log.error("Invalid flow direction {}, for {} ", direction, fwd);
1524 }
1525 }
1526
1527 private void processUpstreamFttbRules(ForwardingObjective fwd, String serviceName) {
1528 TrafficSelector selector = fwd.selector();
1529 TrafficTreatment treatment = fwd.treatment();
1530
1531 // Selectors
1532 Criterion inPortCriterion = selector.getCriterion(Criterion.Type.IN_PORT);
1533 Criterion cVlanVidCriterion = selector.getCriterion(Criterion.Type.VLAN_VID);
1534 Criterion cTagPriority = selector.getCriterion(Criterion.Type.VLAN_PCP);
1535 Criterion ethSrcCriterion = selector.getCriterion(Criterion.Type.ETH_SRC);
1536
1537 // Instructions
1538 L2ModificationInstruction.ModVlanIdInstruction sVlanSetVid = null;
1539 L2ModificationInstruction.ModVlanPcpInstruction sTagPrioritySet = null;
1540
1541 List<Instruction> instructions = treatment.allInstructions();
1542 List<Instruction> vlanIdL2Instructions = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_ID,
1543 instructions);
1544 List<Instruction> vlanPcpL2Instructions = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
1545 instructions);
1546
1547 if (!vlanIdL2Instructions.isEmpty()) {
1548 sVlanSetVid = (L2ModificationInstruction.ModVlanIdInstruction) vlanIdL2Instructions.get(0);
1549 }
1550
1551 if (!vlanPcpL2Instructions.isEmpty()) {
1552 sTagPrioritySet = (L2ModificationInstruction.ModVlanPcpInstruction) vlanPcpL2Instructions.get(0);
1553 }
1554
1555 Instruction output = fetchOutput(fwd, UPSTREAM);
1556 Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_ONU));
1557 Instruction oltUsMeter = fetchMeterById(fwd, fwd.annotations().value(UPSTREAM_OLT));
1558
1559 TrafficSelector oltSelector, onuSelector;
1560 TrafficTreatment oltTreatment, onuTreatment;
1561
1562 switch (serviceName) {
1563 case FTTB_SERVICE_DPU_MGMT_TRAFFIC:
1564 case FTTB_SERVICE_DPU_ANCP_TRAFFIC:
1565 onuSelector = buildSelector(inPortCriterion, cVlanVidCriterion, cTagPriority);
1566 onuTreatment = buildTreatment(sVlanSetVid, sTagPrioritySet, onuUsMeter,
1567 fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE));
1568
1569 oltSelector = buildSelector(inPortCriterion, ethSrcCriterion,
1570 Criteria.matchVlanId(sVlanSetVid.vlanId()));
1571 oltTreatment = buildTreatment(oltUsMeter, fetchWriteMetadata(fwd), output);
1572 break;
1573
1574 case FTTB_SERVICE_SUBSCRIBER_TRAFFIC:
1575 onuSelector = buildSelector(inPortCriterion, cVlanVidCriterion);
1576 onuTreatment = buildTreatment(onuUsMeter, fetchWriteMetadata(fwd), Instructions.transition(QQ_TABLE));
1577
1578 oltSelector = buildSelector(inPortCriterion, cVlanVidCriterion);
1579 oltTreatment = buildTreatment(sVlanSetVid, oltUsMeter, fetchWriteMetadata(fwd), output);
1580 break;
1581 default:
1582 log.error("Unknown service type for Fttb rule : {}", fwd);
1583 return;
1584 }
1585
1586 FlowRule.Builder onuBuilder = DefaultFlowRule.builder()
1587 .fromApp(fwd.appId())
1588 .forDevice(deviceId)
1589 .makePermanent()
1590 .withPriority(fwd.priority())
1591 .withSelector(onuSelector)
1592 .withTreatment(onuTreatment);
1593
1594 FlowRule.Builder oltBuilder = DefaultFlowRule.builder()
1595 .fromApp(fwd.appId())
1596 .forDevice(deviceId)
1597 .forTable(QQ_TABLE)
1598 .makePermanent()
1599 .withPriority(fwd.priority())
1600 .withSelector(oltSelector)
1601 .withTreatment(oltTreatment);
1602
1603 applyRules(fwd, onuBuilder, oltBuilder);
1604 }
1605
1606 private void processDownstreamFttbRules(ForwardingObjective fwd, String serviceName) {
1607 TrafficSelector selector = fwd.selector();
1608 TrafficTreatment treatment = fwd.treatment();
1609
1610 // Selectors
1611 Criterion inPortCriterion = selector.getCriterion(Criterion.Type.IN_PORT);
1612 Criterion sVlanVidCriterion = selector.getCriterion(Criterion.Type.VLAN_VID);
1613 Criterion sTagPriority = selector.getCriterion(Criterion.Type.VLAN_PCP);
1614 Criterion ethDstCriterion = selector.getCriterion(Criterion.Type.ETH_DST);
1615 Criterion metadataSelector = selector.getCriterion(Criterion.Type.METADATA);
1616
1617 // Instructions
1618 L2ModificationInstruction.ModVlanIdInstruction cVlanSetVid = null;
1619 L2ModificationInstruction.ModVlanPcpInstruction cTagPrioritySet = null;
1620
1621 List<Instruction> instructions = treatment.allInstructions();
1622 List<Instruction> vlanIdL2Instructions = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_ID,
1623 instructions);
1624 List<Instruction> vlanPcpL2Instructions = findL2Instructions(L2ModificationInstruction.L2SubType.VLAN_PCP,
1625 instructions);
1626
1627 if (!vlanIdL2Instructions.isEmpty()) {
1628 cVlanSetVid = (L2ModificationInstruction.ModVlanIdInstruction) vlanIdL2Instructions.get(0);
1629 }
1630
1631 if (!vlanPcpL2Instructions.isEmpty()) {
1632 cTagPrioritySet = (L2ModificationInstruction.ModVlanPcpInstruction) vlanPcpL2Instructions.get(0);
1633 }
1634
1635 Instruction output = fetchOutput(fwd, DOWNSTREAM);
1636 Instruction oltDsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_OLT));
1637 Instruction onuUsMeter = fetchMeterById(fwd, fwd.annotations().value(DOWNSTREAM_ONU));
1638
1639 TrafficSelector oltSelector, onuSelector;
1640 TrafficTreatment oltTreatment, onuTreatment;
1641
1642 switch (serviceName) {
1643 case FTTB_SERVICE_DPU_MGMT_TRAFFIC:
1644 case FTTB_SERVICE_DPU_ANCP_TRAFFIC:
1645 oltSelector = buildSelector(inPortCriterion, ethDstCriterion,
1646 sVlanVidCriterion);
1647 oltTreatment = buildTreatment(oltDsMeter, fetchWriteMetadata(fwd),
1648 Instructions.transition(QQ_TABLE));
1649
1650 onuSelector = buildSelector(inPortCriterion, sVlanVidCriterion, sTagPriority, ethDstCriterion);
1651 onuTreatment = buildTreatment(cVlanSetVid, cTagPrioritySet, onuUsMeter,
1652 fetchWriteMetadata(fwd), output);
1653 break;
1654
1655 case FTTB_SERVICE_SUBSCRIBER_TRAFFIC:
1656 oltSelector = buildSelector(inPortCriterion, sVlanVidCriterion);
1657 oltTreatment = buildTreatment(cVlanSetVid, oltDsMeter, fetchWriteMetadata(fwd),
1658 Instructions.transition(QQ_TABLE));
1659
1660 onuSelector = buildSelector(inPortCriterion, Criteria.matchVlanId(cVlanSetVid.vlanId()),
1661 metadataSelector);
1662 onuTreatment = buildTreatment(onuUsMeter, fetchWriteMetadata(fwd), output);
1663 break;
1664
1665 default:
1666 log.error("Unknown service type for Fttb rule : {}", fwd);
1667 return;
1668 }
1669
1670 FlowRule.Builder oltBuilder = DefaultFlowRule.builder()
1671 .fromApp(fwd.appId())
1672 .forDevice(deviceId)
1673 .makePermanent()
1674 .withPriority(fwd.priority())
1675 .withSelector(oltSelector)
1676 .withTreatment(oltTreatment);
1677
1678 FlowRule.Builder onuBuilder = DefaultFlowRule.builder()
1679 .fromApp(fwd.appId())
1680 .forDevice(deviceId)
1681 .forTable(QQ_TABLE)
1682 .makePermanent()
1683 .withPriority(fwd.priority())
1684 .withSelector(onuSelector)
1685 .withTreatment(onuTreatment);
1686
1687 applyRules(fwd, onuBuilder, oltBuilder);
1688 }
Andrea Campanella37f07e42021-02-16 11:24:39 +01001689}