blob: 033945e7027410064d9849ada34b27630b0dfd9a [file] [log] [blame]
Andrea Campanellacbbb7952019-11-25 06:38:41 +00001/*
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.impl;
17
Saurav Dasf62cea82020-08-26 17:43:04 -070018import java.util.ArrayList;
19import java.util.Collection;
20import java.util.List;
21import java.util.Map;
22import java.util.Optional;
23import java.util.Set;
24import java.util.concurrent.CompletableFuture;
25
Andrea Campanellacbbb7952019-11-25 06:38:41 +000026import org.apache.commons.lang3.tuple.Pair;
27import org.junit.Before;
28import org.junit.Test;
29import org.onlab.packet.EthType;
30import org.onlab.packet.VlanId;
31import org.onosproject.cluster.NodeId;
32import org.onosproject.cluster.RoleInfo;
33import org.onosproject.mastership.MastershipInfo;
34import org.onosproject.mastership.MastershipListener;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.MastershipRole;
37import org.onosproject.net.PortNumber;
38import org.onosproject.net.flow.TrafficSelector;
39import org.onosproject.net.flow.TrafficTreatment;
40import org.onosproject.net.flow.criteria.Criterion;
41import org.onosproject.net.flow.criteria.EthTypeCriterion;
42import org.onosproject.net.flow.criteria.PortCriterion;
43import org.onosproject.net.flow.criteria.VlanIdCriterion;
44import org.onosproject.net.flow.instructions.Instruction;
45import org.onosproject.net.flow.instructions.Instructions;
46import org.onosproject.net.flow.instructions.L2ModificationInstruction;
47import org.onosproject.net.flowobjective.FilteringObjQueueKey;
48import org.onosproject.net.flowobjective.FilteringObjective;
49import org.onosproject.net.flowobjective.ForwardingObjQueueKey;
50import org.onosproject.net.flowobjective.ForwardingObjective;
51import org.onosproject.net.flowobjective.NextObjQueueKey;
52import org.onosproject.net.flowobjective.NextObjective;
53import org.onosproject.net.flowobjective.Objective;
54import org.onosproject.net.meter.MeterId;
55import org.onosproject.net.meter.MeterKey;
56import org.opencord.sadis.BandwidthProfileInformation;
57import org.opencord.sadis.UniTagInformation;
58
Saurav Dasf62cea82020-08-26 17:43:04 -070059import com.google.common.collect.ImmutableList;
60import com.google.common.collect.ImmutableMap;
61import com.google.common.collect.ImmutableSet;
62import com.google.common.collect.ListMultimap;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000063
64public class OltFlowTest extends TestBase {
65 private OltFlowService oltFlowService;
Andrea Campanellacbbb7952019-11-25 06:38:41 +000066 PortNumber uniPortNumber = PortNumber.portNumber(1);
Andrea Campanella3a96ce82021-02-09 12:32:42 +010067 PortNumber uniPortNumber2 = PortNumber.portNumber(2);
Andrea Campanellacbbb7952019-11-25 06:38:41 +000068 PortNumber nniPortNumber = PortNumber.portNumber(65535);
69
70 UniTagInformation.Builder tagInfoBuilder = new UniTagInformation.Builder();
71 UniTagInformation uniTagInfo = tagInfoBuilder.setUniTagMatch(VlanId.vlanId((short) 35))
72 .setPonCTag(VlanId.vlanId((short) 33))
73 .setPonSTag(VlanId.vlanId((short) 7))
74 .setDsPonCTagPriority(0)
75 .setUsPonSTagPriority(0)
76 .setTechnologyProfileId(64)
77 .setDownstreamBandwidthProfile(dsBpId)
78 .setUpstreamBandwidthProfile(usBpId)
Saurav Dasf62cea82020-08-26 17:43:04 -070079 .setIsDhcpRequired(true)
80 .setIsIgmpRequired(true)
81 .build();
82
Andrea Campanella3a96ce82021-02-09 12:32:42 +010083 UniTagInformation.Builder tagInfoBuilderNoPcp = new UniTagInformation.Builder();
84 UniTagInformation uniTagInfoNoPcp = tagInfoBuilderNoPcp.setUniTagMatch(VlanId.vlanId((short) 35))
85 .setPonCTag(VlanId.vlanId((short) 34))
86 .setPonSTag(VlanId.vlanId((short) 7))
87 .setDsPonCTagPriority(-1)
88 .setUsPonSTagPriority(-1)
89 .setUsPonCTagPriority(-1)
90 .setDsPonSTagPriority(-1)
91 .setTechnologyProfileId(64)
92 .setDownstreamBandwidthProfile(dsBpId)
93 .setUpstreamBandwidthProfile(usBpId)
94 .setIsDhcpRequired(true)
95 .setIsIgmpRequired(true)
96 .build();
97
Saurav Dasf62cea82020-08-26 17:43:04 -070098 UniTagInformation.Builder tagInfoBuilder2 = new UniTagInformation.Builder();
99 UniTagInformation uniTagInfoNoDhcpNoIgmp = tagInfoBuilder2
100 .setUniTagMatch(VlanId.vlanId((short) 35))
101 .setPonCTag(VlanId.vlanId((short) 33))
102 .setPonSTag(VlanId.vlanId((short) 7))
103 .setDsPonCTagPriority(0)
104 .setUsPonSTagPriority(0)
105 .setTechnologyProfileId(64)
106 .setDownstreamBandwidthProfile(dsBpId)
107 .setUpstreamBandwidthProfile(usBpId)
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000108 .build();
109
110 @Before
111 public void setUp() {
112 oltFlowService = new OltFlowService();
113 oltFlowService.oltMeterService = new MockOltMeterService();
114 oltFlowService.flowObjectiveService = new MockOltFlowObjectiveService();
115 oltFlowService.mastershipService = new MockMastershipService();
116 oltFlowService.sadisService = new MockSadisService();
117 oltFlowService.bpService = oltFlowService.sadisService.getBandwidthProfileService();
118 oltFlowService.appId = appId;
119 }
120
121 @Test
122 public void testDhcpFiltering() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700123 oltFlowService.flowObjectiveService.clearQueue();
124 // ensure upstream dhcp traps can be added and removed
125 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
126 usMeterId, uniTagInfo,
127 true, true);
128 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 1;
129 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
130 usMeterId, uniTagInfo,
131 false, true);
132 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100133
134 // Ensure upstream flow has no pcp unless properly specified.
135 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber2,
136 usMeterId, uniTagInfoNoPcp,
137 true, true);
138 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 3;
139
Saurav Dasf62cea82020-08-26 17:43:04 -0700140 // ensure upstream flows are not added if uniTagInfo is missing dhcp requirement
141 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
142 usMeterId, uniTagInfoNoDhcpNoIgmp,
143 true, true);
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100144 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 3;
Saurav Dasf62cea82020-08-26 17:43:04 -0700145
146 // ensure downstream traps don't succeed without global config for nni ports
147 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
148 null, null,
149 true, false);
150 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
151 null, null,
152 false, false);
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100153 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 3;
Saurav Dasf62cea82020-08-26 17:43:04 -0700154 // do global config for nni ports and now it should succeed
155 oltFlowService.enableDhcpOnNni = true;
156 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
157 null, null,
158 true, false);
159 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
160 null, null,
161 false, false);
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100162 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 5;
Saurav Dasf62cea82020-08-26 17:43:04 -0700163
164 // turn on DHCPv6 and we should get 2 flows
165 oltFlowService.enableDhcpV6 = true;
166 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
167 usMeterId, uniTagInfo,
168 true, true);
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100169 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 7;
Saurav Dasf62cea82020-08-26 17:43:04 -0700170
171 // turn off DHCPv4 and it's only v6
172 oltFlowService.enableDhcpV4 = false;
173 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
174 usMeterId, uniTagInfo,
175 true, true);
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100176 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 8;
Saurav Dasf62cea82020-08-26 17:43:04 -0700177
178 // cleanup
179 oltFlowService.flowObjectiveService.clearQueue();
180 oltFlowService.enableDhcpV4 = true;
181 oltFlowService.enableDhcpV6 = false;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000182 }
183
184 @Test
185 public void testIgmpFiltering() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700186 oltFlowService.flowObjectiveService.clearQueue();
187
188 // ensure igmp flows can be added and removed
189 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
190 usMeterId, uniTagInfo,
191 true, true);
192 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 1;
193 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, uniPortNumber, usMeterId,
194 uniTagInfo,
195 false, true);
196 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
197
198 // ensure igmp flow is not added if uniTag has no igmp requirement
199 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
200 usMeterId, uniTagInfoNoDhcpNoIgmp,
201 true, true);
202 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
203
204 //ensure igmp flow on NNI fails without global setting
205 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
206 null, null,
207 true, false);
208 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
209
210 // igmp trap on NNI should succeed with global config
211 oltFlowService.enableIgmpOnNni = true;
212 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
213 null, null,
214 true, false);
215 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 3;
216 // cleanup
217 oltFlowService.flowObjectiveService.clearQueue();
218
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000219 }
220
221 @Test
222 public void testEapolFiltering() {
223 addBandwidthProfile(uniTagInfo.getUpstreamBandwidthProfile());
224 oltFlowService.enableEapol = true;
225
226 //will install
227 oltFlowService.processEapolFilteringObjectives(DEVICE_ID_1, uniPortNumber,
228 uniTagInfo.getUpstreamBandwidthProfile(), new CompletableFuture<>(),
229 uniTagInfo.getUniTagMatch(), true);
230
231 //bp profile doesn't exist
232 oltFlowService.processEapolFilteringObjectives(DEVICE_ID_1, uniPortNumber,
233 uniTagInfo.getDownstreamBandwidthProfile(), new CompletableFuture<>(),
234 uniTagInfo.getUniTagMatch(), true);
235 }
236
237 @Test
238 public void testLldpFiltering() {
239 oltFlowService.processLldpFilteringObjective(DEVICE_ID_1, nniPortNumber, true);
240 oltFlowService.processLldpFilteringObjective(DEVICE_ID_1, nniPortNumber, false);
241 }
242
243 @Test
244 public void testNniFiltering() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700245 oltFlowService.flowObjectiveService.clearQueue();
246 oltFlowService.enableDhcpOnNni = true;
247 oltFlowService.enableIgmpOnNni = true;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000248 oltFlowService.processNniFilteringObjectives(DEVICE_ID_1, nniPortNumber, true);
Saurav Dasf62cea82020-08-26 17:43:04 -0700249 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives()
250 .size() == 3;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000251 oltFlowService.processNniFilteringObjectives(DEVICE_ID_1, nniPortNumber, false);
Saurav Dasf62cea82020-08-26 17:43:04 -0700252 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives()
253 .size() == 6;
254 oltFlowService.flowObjectiveService.clearQueue();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000255 }
256
257 @Test
258 public void testUpBuilder() {
259 ForwardingObjective objective =
260 oltFlowService.createUpBuilder(nniPortNumber, uniPortNumber, usMeterId, uniTagInfo).add();
261 checkObjective(objective, true);
262 }
263
264 @Test
265 public void testDownBuilder() {
266 ForwardingObjective objective =
267 oltFlowService.createDownBuilder(nniPortNumber, uniPortNumber, dsMeterId, uniTagInfo).remove();
268 checkObjective(objective, false);
269 }
270
271 private void checkObjective(ForwardingObjective fwd, boolean upstream) {
272 TrafficTreatment treatment = fwd.treatment();
273
274 //check instructions
275 Set<Instructions.MeterInstruction> meters = treatment.meters();
276 assert !meters.isEmpty();
277
278 Instructions.MetadataInstruction writeMetadata = treatment.writeMetadata();
279 assert writeMetadata != null;
280
281 List<Instruction> immediateInstructions = treatment.immediate();
282 Optional<Instruction> vlanInstruction = immediateInstructions.stream()
283 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
284 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
285 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
286 ((L2ModificationInstruction) i).subtype() ==
287 L2ModificationInstruction.L2SubType.VLAN_POP)
288 .findAny();
289
290 assert vlanInstruction.isPresent();
291
292 //check match criteria
293 TrafficSelector selector = fwd.selector();
294 assert selector.getCriterion(Criterion.Type.IN_PORT) != null;
295 assert selector.getCriterion(Criterion.Type.VLAN_VID) != null;
296
297 if (!upstream) {
298 assert selector.getCriterion(Criterion.Type.METADATA) != null;
299 }
300 }
301
302 private class MockOltMeterService implements org.opencord.olt.internalapi.AccessDeviceMeterService {
303 @Override
304 public ImmutableMap<String, Collection<MeterKey>> getBpMeterMappings() {
305 return null;
306 }
307
308 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000309 public MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
310 return null;
311 }
312
313
314 @Override
315 public ImmutableSet<MeterKey> getProgMeters() {
316 return null;
317 }
318
319 @Override
320 public MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
321 CompletableFuture<Object> meterFuture) {
322 return usMeterId;
323 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800324
325 @Override
Andrea Campanella600d2e22020-06-22 11:00:31 +0200326 public void removeFromPendingMeters(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
327
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200328 }
329
330 @Override
Andrea Campanellad1e26642020-10-23 12:08:32 +0200331 public boolean checkAndAddPendingMeter(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200332 return false;
333 }
334
Andrea Campanella600d2e22020-06-22 11:00:31 +0200335
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200336 @Override
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800337 public void clearMeters(DeviceId deviceId) {
338 }
Andrea Campanella600d2e22020-06-22 11:00:31 +0200339
340 @Override
341 public void clearDeviceState(DeviceId deviceId) {
342
343 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000344 }
345
346 private class MockOltFlowObjectiveService implements org.onosproject.net.flowobjective.FlowObjectiveService {
Saurav Dasf62cea82020-08-26 17:43:04 -0700347 List<String> flowObjectives = new ArrayList<>();
348
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000349 @Override
350 public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700351 flowObjectives.add(filteringObjective.toString());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000352 EthTypeCriterion ethType = (EthTypeCriterion)
353 filterForCriterion(filteringObjective.conditions(), Criterion.Type.ETH_TYPE);
354
355 Instructions.MeterInstruction meter = filteringObjective.meta().metered();
356 Instruction writeMetadata = filteringObjective.meta().writeMetadata();
357 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion)
358 filterForCriterion(filteringObjective.conditions(), Criterion.Type.VLAN_VID);
359 PortCriterion portCriterion = (PortCriterion) filteringObjective.key();
360
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100361 filteringObjective.meta().allInstructions().forEach(instruction -> {
362 if (instruction.type().equals(Instruction.Type.L2MODIFICATION)) {
363 L2ModificationInstruction l2Instruction = (L2ModificationInstruction) instruction;
364 if (l2Instruction.subtype().equals(L2ModificationInstruction.L2SubType.VLAN_PCP)) {
365 //this, given the uniTagInfo we provide, should not be present
366 assert false;
367 }
368 }
369 });
370
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000371
372 if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType()) ||
373 portCriterion.port().equals(nniPortNumber)) {
374 assert meter == null;
375 assert writeMetadata == null;
376 assert vlanIdCriterion == null;
377 } else {
378 assert meter.meterId().equals(usMeterId) || meter.meterId().equals(dsMeterId);
379 assert writeMetadata != null;
Andrea Campanella3a96ce82021-02-09 12:32:42 +0100380 assert vlanIdCriterion == null || vlanIdCriterion.vlanId() == uniTagInfo.getUniTagMatch()
381 || vlanIdCriterion.vlanId() == uniTagInfoNoPcp.getUniTagMatch();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000382 }
383
384 }
385
386 @Override
387 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
388
389 }
390
391 @Override
392 public void next(DeviceId deviceId, NextObjective nextObjective) {
393
394 }
395
396 @Override
397 public int allocateNextId() {
398 return 0;
399 }
400
401 @Override
402 public void initPolicy(String s) {
403
404 }
405
406 @Override
407 public void apply(DeviceId deviceId, Objective objective) {
408
409 }
410
411 @Override
412 public Map<Pair<Integer, DeviceId>, List<String>> getNextMappingsChain() {
413 return null;
414 }
415
416 @Override
417 public List<String> getNextMappings() {
418 return null;
419 }
420
421 @Override
422 public List<String> getPendingFlowObjectives() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700423 return ImmutableList.copyOf(flowObjectives);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000424 }
425
426 @Override
427 public ListMultimap<FilteringObjQueueKey, Objective> getFilteringObjQueue() {
428 return null;
429 }
430
431 @Override
432 public ListMultimap<ForwardingObjQueueKey, Objective> getForwardingObjQueue() {
433 return null;
434 }
435
436 @Override
437 public ListMultimap<NextObjQueueKey, Objective> getNextObjQueue() {
438 return null;
439 }
440
441 @Override
442 public Map<FilteringObjQueueKey, Objective> getFilteringObjQueueHead() {
443 return null;
444 }
445
446 @Override
447 public Map<ForwardingObjQueueKey, Objective> getForwardingObjQueueHead() {
448 return null;
449 }
450
451 @Override
452 public Map<NextObjQueueKey, Objective> getNextObjQueueHead() {
453 return null;
454 }
455
456 @Override
457 public void clearQueue() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700458 flowObjectives.clear();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000459 }
460
461 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
462 return criteria.stream()
463 .filter(c -> c.type().equals(type))
464 .limit(1)
465 .findFirst().orElse(null);
466 }
467 }
468
469 private class MockMastershipService implements org.onosproject.mastership.MastershipService {
470 @Override
471 public MastershipRole getLocalRole(DeviceId deviceId) {
472 return null;
473 }
474
475 @Override
476 public boolean isLocalMaster(DeviceId deviceId) {
477 return true;
478 }
479
480 @Override
481 public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) {
482 return null;
483 }
484
485 @Override
486 public CompletableFuture<Void> relinquishMastership(DeviceId deviceId) {
487 return null;
488 }
489
490 @Override
491 public NodeId getMasterFor(DeviceId deviceId) {
492 return null;
493 }
494
495 @Override
496 public RoleInfo getNodesFor(DeviceId deviceId) {
497 return null;
498 }
499
500 @Override
501 public MastershipInfo getMastershipFor(DeviceId deviceId) {
502 return null;
503 }
504
505 @Override
506 public Set<DeviceId> getDevicesOf(NodeId nodeId) {
507 return null;
508 }
509
510 @Override
511 public void addListener(MastershipListener mastershipListener) {
512
513 }
514
515 @Override
516 public void removeListener(MastershipListener mastershipListener) {
517
518 }
519 }
520}