blob: 52ccce4981d032ffd5f1d96923c9d16fb3f54471 [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);
67 PortNumber nniPortNumber = PortNumber.portNumber(65535);
68
69 UniTagInformation.Builder tagInfoBuilder = new UniTagInformation.Builder();
70 UniTagInformation uniTagInfo = tagInfoBuilder.setUniTagMatch(VlanId.vlanId((short) 35))
71 .setPonCTag(VlanId.vlanId((short) 33))
72 .setPonSTag(VlanId.vlanId((short) 7))
73 .setDsPonCTagPriority(0)
74 .setUsPonSTagPriority(0)
75 .setTechnologyProfileId(64)
76 .setDownstreamBandwidthProfile(dsBpId)
77 .setUpstreamBandwidthProfile(usBpId)
Saurav Dasf62cea82020-08-26 17:43:04 -070078 .setIsDhcpRequired(true)
79 .setIsIgmpRequired(true)
80 .build();
81
82 UniTagInformation.Builder tagInfoBuilder2 = new UniTagInformation.Builder();
83 UniTagInformation uniTagInfoNoDhcpNoIgmp = tagInfoBuilder2
84 .setUniTagMatch(VlanId.vlanId((short) 35))
85 .setPonCTag(VlanId.vlanId((short) 33))
86 .setPonSTag(VlanId.vlanId((short) 7))
87 .setDsPonCTagPriority(0)
88 .setUsPonSTagPriority(0)
89 .setTechnologyProfileId(64)
90 .setDownstreamBandwidthProfile(dsBpId)
91 .setUpstreamBandwidthProfile(usBpId)
Andrea Campanellacbbb7952019-11-25 06:38:41 +000092 .build();
93
94 @Before
95 public void setUp() {
96 oltFlowService = new OltFlowService();
97 oltFlowService.oltMeterService = new MockOltMeterService();
98 oltFlowService.flowObjectiveService = new MockOltFlowObjectiveService();
99 oltFlowService.mastershipService = new MockMastershipService();
100 oltFlowService.sadisService = new MockSadisService();
101 oltFlowService.bpService = oltFlowService.sadisService.getBandwidthProfileService();
102 oltFlowService.appId = appId;
103 }
104
105 @Test
106 public void testDhcpFiltering() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700107 oltFlowService.flowObjectiveService.clearQueue();
108 // ensure upstream dhcp traps can be added and removed
109 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
110 usMeterId, uniTagInfo,
111 true, true);
112 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 1;
113 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
114 usMeterId, uniTagInfo,
115 false, true);
116 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
117 // ensure upstream flows are not added if uniTagInfo is missing dhcp requirement
118 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
119 usMeterId, uniTagInfoNoDhcpNoIgmp,
120 true, true);
121 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
122
123 // ensure downstream traps don't succeed without global config for nni ports
124 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
125 null, null,
126 true, false);
127 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
128 null, null,
129 false, false);
130 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
131 // do global config for nni ports and now it should succeed
132 oltFlowService.enableDhcpOnNni = true;
133 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
134 null, null,
135 true, false);
136 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
137 null, null,
138 false, false);
139 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 4;
140
141 // turn on DHCPv6 and we should get 2 flows
142 oltFlowService.enableDhcpV6 = true;
143 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
144 usMeterId, uniTagInfo,
145 true, true);
146 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 6;
147
148 // turn off DHCPv4 and it's only v6
149 oltFlowService.enableDhcpV4 = false;
150 oltFlowService.processDhcpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
151 usMeterId, uniTagInfo,
152 true, true);
153 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 7;
154
155 // cleanup
156 oltFlowService.flowObjectiveService.clearQueue();
157 oltFlowService.enableDhcpV4 = true;
158 oltFlowService.enableDhcpV6 = false;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000159 }
160
161 @Test
162 public void testIgmpFiltering() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700163 oltFlowService.flowObjectiveService.clearQueue();
164
165 // ensure igmp flows can be added and removed
166 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
167 usMeterId, uniTagInfo,
168 true, true);
169 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 1;
170 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, uniPortNumber, usMeterId,
171 uniTagInfo,
172 false, true);
173 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
174
175 // ensure igmp flow is not added if uniTag has no igmp requirement
176 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, uniPortNumber,
177 usMeterId, uniTagInfoNoDhcpNoIgmp,
178 true, true);
179 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
180
181 //ensure igmp flow on NNI fails without global setting
182 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
183 null, null,
184 true, false);
185 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 2;
186
187 // igmp trap on NNI should succeed with global config
188 oltFlowService.enableIgmpOnNni = true;
189 oltFlowService.processIgmpFilteringObjectives(DEVICE_ID_1, nniPortNumber,
190 null, null,
191 true, false);
192 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives().size() == 3;
193 // cleanup
194 oltFlowService.flowObjectiveService.clearQueue();
195
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000196 }
197
198 @Test
199 public void testEapolFiltering() {
200 addBandwidthProfile(uniTagInfo.getUpstreamBandwidthProfile());
201 oltFlowService.enableEapol = true;
202
203 //will install
204 oltFlowService.processEapolFilteringObjectives(DEVICE_ID_1, uniPortNumber,
205 uniTagInfo.getUpstreamBandwidthProfile(), new CompletableFuture<>(),
206 uniTagInfo.getUniTagMatch(), true);
207
208 //bp profile doesn't exist
209 oltFlowService.processEapolFilteringObjectives(DEVICE_ID_1, uniPortNumber,
210 uniTagInfo.getDownstreamBandwidthProfile(), new CompletableFuture<>(),
211 uniTagInfo.getUniTagMatch(), true);
212 }
213
214 @Test
215 public void testLldpFiltering() {
216 oltFlowService.processLldpFilteringObjective(DEVICE_ID_1, nniPortNumber, true);
217 oltFlowService.processLldpFilteringObjective(DEVICE_ID_1, nniPortNumber, false);
218 }
219
220 @Test
221 public void testNniFiltering() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700222 oltFlowService.flowObjectiveService.clearQueue();
223 oltFlowService.enableDhcpOnNni = true;
224 oltFlowService.enableIgmpOnNni = true;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000225 oltFlowService.processNniFilteringObjectives(DEVICE_ID_1, nniPortNumber, true);
Saurav Dasf62cea82020-08-26 17:43:04 -0700226 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives()
227 .size() == 3;
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000228 oltFlowService.processNniFilteringObjectives(DEVICE_ID_1, nniPortNumber, false);
Saurav Dasf62cea82020-08-26 17:43:04 -0700229 assert oltFlowService.flowObjectiveService.getPendingFlowObjectives()
230 .size() == 6;
231 oltFlowService.flowObjectiveService.clearQueue();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000232 }
233
234 @Test
235 public void testUpBuilder() {
236 ForwardingObjective objective =
237 oltFlowService.createUpBuilder(nniPortNumber, uniPortNumber, usMeterId, uniTagInfo).add();
238 checkObjective(objective, true);
239 }
240
241 @Test
242 public void testDownBuilder() {
243 ForwardingObjective objective =
244 oltFlowService.createDownBuilder(nniPortNumber, uniPortNumber, dsMeterId, uniTagInfo).remove();
245 checkObjective(objective, false);
246 }
247
248 private void checkObjective(ForwardingObjective fwd, boolean upstream) {
249 TrafficTreatment treatment = fwd.treatment();
250
251 //check instructions
252 Set<Instructions.MeterInstruction> meters = treatment.meters();
253 assert !meters.isEmpty();
254
255 Instructions.MetadataInstruction writeMetadata = treatment.writeMetadata();
256 assert writeMetadata != null;
257
258 List<Instruction> immediateInstructions = treatment.immediate();
259 Optional<Instruction> vlanInstruction = immediateInstructions.stream()
260 .filter(i -> i.type() == Instruction.Type.L2MODIFICATION)
261 .filter(i -> ((L2ModificationInstruction) i).subtype() ==
262 L2ModificationInstruction.L2SubType.VLAN_PUSH ||
263 ((L2ModificationInstruction) i).subtype() ==
264 L2ModificationInstruction.L2SubType.VLAN_POP)
265 .findAny();
266
267 assert vlanInstruction.isPresent();
268
269 //check match criteria
270 TrafficSelector selector = fwd.selector();
271 assert selector.getCriterion(Criterion.Type.IN_PORT) != null;
272 assert selector.getCriterion(Criterion.Type.VLAN_VID) != null;
273
274 if (!upstream) {
275 assert selector.getCriterion(Criterion.Type.METADATA) != null;
276 }
277 }
278
279 private class MockOltMeterService implements org.opencord.olt.internalapi.AccessDeviceMeterService {
280 @Override
281 public ImmutableMap<String, Collection<MeterKey>> getBpMeterMappings() {
282 return null;
283 }
284
285 @Override
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000286 public MeterId getMeterIdFromBpMapping(DeviceId deviceId, String bandwidthProfile) {
287 return null;
288 }
289
290
291 @Override
292 public ImmutableSet<MeterKey> getProgMeters() {
293 return null;
294 }
295
296 @Override
297 public MeterId createMeter(DeviceId deviceId, BandwidthProfileInformation bpInfo,
298 CompletableFuture<Object> meterFuture) {
299 return usMeterId;
300 }
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800301
302 @Override
Andrea Campanella600d2e22020-06-22 11:00:31 +0200303 public void addToPendingMeters(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200304
305 }
306
307 @Override
Andrea Campanella600d2e22020-06-22 11:00:31 +0200308 public void removeFromPendingMeters(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
309
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200310 }
311
312 @Override
Andrea Campanella600d2e22020-06-22 11:00:31 +0200313 public boolean isMeterPending(DeviceId deviceId, BandwidthProfileInformation bwpInfo) {
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200314 return false;
315 }
316
Andrea Campanella600d2e22020-06-22 11:00:31 +0200317
Andrea Campanella3ce4d282020-06-09 13:46:58 +0200318 @Override
Jonathan Hart4f178fa2020-02-03 10:46:01 -0800319 public void clearMeters(DeviceId deviceId) {
320 }
Andrea Campanella600d2e22020-06-22 11:00:31 +0200321
322 @Override
323 public void clearDeviceState(DeviceId deviceId) {
324
325 }
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000326 }
327
328 private class MockOltFlowObjectiveService implements org.onosproject.net.flowobjective.FlowObjectiveService {
Saurav Dasf62cea82020-08-26 17:43:04 -0700329 List<String> flowObjectives = new ArrayList<>();
330
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000331 @Override
332 public void filter(DeviceId deviceId, FilteringObjective filteringObjective) {
Saurav Dasf62cea82020-08-26 17:43:04 -0700333 flowObjectives.add(filteringObjective.toString());
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000334 EthTypeCriterion ethType = (EthTypeCriterion)
335 filterForCriterion(filteringObjective.conditions(), Criterion.Type.ETH_TYPE);
336
337 Instructions.MeterInstruction meter = filteringObjective.meta().metered();
338 Instruction writeMetadata = filteringObjective.meta().writeMetadata();
339 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion)
340 filterForCriterion(filteringObjective.conditions(), Criterion.Type.VLAN_VID);
341 PortCriterion portCriterion = (PortCriterion) filteringObjective.key();
342
343
344 if (ethType.ethType().equals(EthType.EtherType.LLDP.ethType()) ||
345 portCriterion.port().equals(nniPortNumber)) {
346 assert meter == null;
347 assert writeMetadata == null;
348 assert vlanIdCriterion == null;
349 } else {
350 assert meter.meterId().equals(usMeterId) || meter.meterId().equals(dsMeterId);
351 assert writeMetadata != null;
Andrea Campanella0e34f562020-06-11 10:47:10 +0200352 assert vlanIdCriterion == null || vlanIdCriterion.vlanId() == uniTagInfo.getUniTagMatch();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000353 }
354
355 }
356
357 @Override
358 public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) {
359
360 }
361
362 @Override
363 public void next(DeviceId deviceId, NextObjective nextObjective) {
364
365 }
366
367 @Override
368 public int allocateNextId() {
369 return 0;
370 }
371
372 @Override
373 public void initPolicy(String s) {
374
375 }
376
377 @Override
378 public void apply(DeviceId deviceId, Objective objective) {
379
380 }
381
382 @Override
383 public Map<Pair<Integer, DeviceId>, List<String>> getNextMappingsChain() {
384 return null;
385 }
386
387 @Override
388 public List<String> getNextMappings() {
389 return null;
390 }
391
392 @Override
393 public List<String> getPendingFlowObjectives() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700394 return ImmutableList.copyOf(flowObjectives);
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000395 }
396
397 @Override
398 public ListMultimap<FilteringObjQueueKey, Objective> getFilteringObjQueue() {
399 return null;
400 }
401
402 @Override
403 public ListMultimap<ForwardingObjQueueKey, Objective> getForwardingObjQueue() {
404 return null;
405 }
406
407 @Override
408 public ListMultimap<NextObjQueueKey, Objective> getNextObjQueue() {
409 return null;
410 }
411
412 @Override
413 public Map<FilteringObjQueueKey, Objective> getFilteringObjQueueHead() {
414 return null;
415 }
416
417 @Override
418 public Map<ForwardingObjQueueKey, Objective> getForwardingObjQueueHead() {
419 return null;
420 }
421
422 @Override
423 public Map<NextObjQueueKey, Objective> getNextObjQueueHead() {
424 return null;
425 }
426
427 @Override
428 public void clearQueue() {
Saurav Dasf62cea82020-08-26 17:43:04 -0700429 flowObjectives.clear();
Andrea Campanellacbbb7952019-11-25 06:38:41 +0000430 }
431
432 private Criterion filterForCriterion(Collection<Criterion> criteria, Criterion.Type type) {
433 return criteria.stream()
434 .filter(c -> c.type().equals(type))
435 .limit(1)
436 .findFirst().orElse(null);
437 }
438 }
439
440 private class MockMastershipService implements org.onosproject.mastership.MastershipService {
441 @Override
442 public MastershipRole getLocalRole(DeviceId deviceId) {
443 return null;
444 }
445
446 @Override
447 public boolean isLocalMaster(DeviceId deviceId) {
448 return true;
449 }
450
451 @Override
452 public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) {
453 return null;
454 }
455
456 @Override
457 public CompletableFuture<Void> relinquishMastership(DeviceId deviceId) {
458 return null;
459 }
460
461 @Override
462 public NodeId getMasterFor(DeviceId deviceId) {
463 return null;
464 }
465
466 @Override
467 public RoleInfo getNodesFor(DeviceId deviceId) {
468 return null;
469 }
470
471 @Override
472 public MastershipInfo getMastershipFor(DeviceId deviceId) {
473 return null;
474 }
475
476 @Override
477 public Set<DeviceId> getDevicesOf(NodeId nodeId) {
478 return null;
479 }
480
481 @Override
482 public void addListener(MastershipListener mastershipListener) {
483
484 }
485
486 @Override
487 public void removeListener(MastershipListener mastershipListener) {
488
489 }
490 }
491}