blob: c9bad5f4ec52a315b6a4208d7adb2d6e51af1f14 [file] [log] [blame]
Matteo Scandoloaa2adde2021-09-13 12:45:32 -07001/*
2 * Copyright 2021-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 */
16
17package org.opencord.olt.impl;
18
19import org.junit.After;
20import org.junit.Assert;
21import org.junit.Before;
22import org.junit.Test;
23import org.mockito.Mockito;
24import org.onlab.packet.ChassisId;
25import org.onlab.packet.EthType;
26import org.onlab.packet.IPv4;
27import org.onlab.packet.IPv6;
28import org.onlab.packet.MacAddress;
29import org.onlab.packet.TpPort;
30import org.onlab.packet.VlanId;
31import org.onosproject.cfg.ComponentConfigAdapter;
32import org.onosproject.core.ApplicationId;
33import org.onosproject.core.CoreServiceAdapter;
34import org.onosproject.core.DefaultApplicationId;
35import org.onosproject.net.ConnectPoint;
36import org.onosproject.net.DefaultAnnotations;
37import org.onosproject.net.DefaultDevice;
38import org.onosproject.net.DefaultHost;
39import org.onosproject.net.DefaultPort;
40import org.onosproject.net.Device;
41import org.onosproject.net.DeviceId;
42import org.onosproject.net.Host;
43import org.onosproject.net.HostId;
44import org.onosproject.net.HostLocation;
45import org.onosproject.net.Port;
46import org.onosproject.net.PortNumber;
47import org.onosproject.net.flow.DefaultFlowRule;
48import org.onosproject.net.flow.DefaultTrafficTreatment;
49import org.onosproject.net.flow.FlowRule;
50import org.onosproject.net.flow.FlowRuleEvent;
51import org.onosproject.net.flow.FlowRuleService;
52import org.onosproject.net.flow.criteria.Criteria;
53import org.onosproject.net.flowobjective.DefaultFilteringObjective;
54import org.onosproject.net.flowobjective.FilteringObjective;
55import org.onosproject.net.flowobjective.FlowObjectiveService;
56import org.onosproject.net.host.HostService;
57import org.onosproject.net.meter.MeterId;
58import org.onosproject.net.provider.ProviderId;
59import org.onosproject.store.service.TestStorageService;
60import org.opencord.sadis.BaseInformationService;
61import org.opencord.sadis.SadisService;
62import org.opencord.sadis.SubscriberAndDeviceInformation;
63import org.opencord.sadis.UniTagInformation;
64
65import java.util.Arrays;
66import java.util.HashSet;
67import java.util.LinkedList;
68import java.util.List;
69import java.util.Set;
70
71import static org.mockito.Matchers.any;
72import static org.mockito.Matchers.argThat;
73import static org.mockito.Matchers.eq;
74import static org.mockito.Mockito.doReturn;
75import static org.mockito.Mockito.never;
76import static org.mockito.Mockito.spy;
77import static org.mockito.Mockito.times;
78import static org.mockito.Mockito.verify;
79import static org.onosproject.net.AnnotationKeys.PORT_NAME;
80import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.NONE;
81import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.ADDED;
82import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.PENDING_ADD;
83import static org.opencord.olt.impl.OltFlowService.OltFlowsStatus.REMOVED;
84import static org.opencord.olt.impl.OsgiPropertyConstants.DEFAULT_BP_ID_DEFAULT;
85
86public class OltFlowServiceTest extends OltTestHelpers {
87
88 private OltFlowService oltFlowService;
89 OltFlowService.InternalFlowListener internalFlowListener;
90 private final ApplicationId testAppId = new DefaultApplicationId(1, "org.opencord.olt.test");
91 private final short eapolDefaultVlan = 4091;
92
93 private final DeviceId deviceId = DeviceId.deviceId("test-device");
94 private final Device testDevice = new DefaultDevice(ProviderId.NONE, deviceId, Device.Type.OLT,
95 "testManufacturer", "1.0", "1.0", "SN", new ChassisId(1));
96 Port nniPort = new OltPort(testDevice, true, PortNumber.portNumber(1048576),
97 DefaultAnnotations.builder().set(PORT_NAME, "nni-1").build());
98 Port nniPortDisabled = new OltPort(testDevice, false, PortNumber.portNumber(1048576),
99 DefaultAnnotations.builder().set(PORT_NAME, "nni-1").build());
100 Port uniUpdateEnabled = new OltPort(testDevice, true, PortNumber.portNumber(16),
101 DefaultAnnotations.builder().set(PORT_NAME, "uni-1").build());
102
103 @Before
104 public void setUp() {
105 oltFlowService = new OltFlowService();
106 oltFlowService.cfgService = new ComponentConfigAdapter();
107 oltFlowService.sadisService = Mockito.mock(SadisService.class);
108 oltFlowService.coreService = Mockito.spy(new CoreServiceAdapter());
109 oltFlowService.oltMeterService = Mockito.mock(OltMeterService.class);
110 oltFlowService.flowObjectiveService = Mockito.mock(FlowObjectiveService.class);
111 oltFlowService.hostService = Mockito.mock(HostService.class);
112 oltFlowService.flowRuleService = Mockito.mock(FlowRuleService.class);
113 oltFlowService.storageService = new TestStorageService();
114 oltFlowService.oltDeviceService = Mockito.mock(OltDeviceService.class);
115 oltFlowService.appId = testAppId;
116
117 doReturn(Mockito.mock(BaseInformationService.class))
118 .when(oltFlowService.sadisService).getSubscriberInfoService();
119 doReturn(testAppId).when(oltFlowService.coreService).registerApplication("org.opencord.olt");
120 oltFlowService.activate(null);
121 oltFlowService.bindSadisService(oltFlowService.sadisService);
122
123 internalFlowListener = spy(oltFlowService.internalFlowListener);
124 }
125
126 @After
127 public void tearDown() {
128 oltFlowService.deactivate(null);
129 }
130
131 @Test
132 public void testUpdateConnectPointStatus() {
133
134 DeviceId deviceId = DeviceId.deviceId("test-device");
135 ProviderId pid = new ProviderId("of", "foo");
136 Device device =
137 new DefaultDevice(pid, deviceId, Device.Type.OLT, "", "", "", "", null);
138 Port port1 = new DefaultPort(device, PortNumber.portNumber(1), true,
139 DefaultAnnotations.builder().set(PORT_NAME, "port-1").build());
140 Port port2 = new DefaultPort(device, PortNumber.portNumber(2), true,
141 DefaultAnnotations.builder().set(PORT_NAME, "port-2").build());
142 Port port3 = new DefaultPort(device, PortNumber.portNumber(3), true,
143 DefaultAnnotations.builder().set(PORT_NAME, "port-3").build());
144
145 ServiceKey sk1 = new ServiceKey(new AccessDevicePort(port1), new UniTagInformation());
146 ServiceKey sk2 = new ServiceKey(new AccessDevicePort(port2), new UniTagInformation());
147 ServiceKey sk3 = new ServiceKey(new AccessDevicePort(port3), new UniTagInformation());
148
149 // cpStatus map for the test
150 oltFlowService.cpStatus = oltFlowService.storageService.
151 <ServiceKey, OltPortStatus>consistentMapBuilder().build().asJavaMap();
152 OltPortStatus cp1Status = new OltPortStatus(PENDING_ADD, NONE, NONE);
153 oltFlowService.cpStatus.put(sk1, cp1Status);
154
155 //check that we only update the provided value
156 oltFlowService.updateConnectPointStatus(sk1, ADDED, null, null);
157 OltPortStatus updated = oltFlowService.cpStatus.get(sk1);
158 Assert.assertEquals(ADDED, updated.defaultEapolStatus);
159 Assert.assertEquals(NONE, updated.subscriberFlowsStatus);
160 Assert.assertEquals(NONE, updated.dhcpStatus);
161
162 // check that it creates an entry if it does not exist
163 oltFlowService.updateConnectPointStatus(sk2, PENDING_ADD, NONE, NONE);
164 Assert.assertNotNull(oltFlowService.cpStatus.get(sk2));
165
166 // check that if we create a new entry with null values they're converted to NONE
167 oltFlowService.updateConnectPointStatus(sk3, null, null, null);
168 updated = oltFlowService.cpStatus.get(sk3);
169 Assert.assertEquals(NONE, updated.defaultEapolStatus);
170 Assert.assertEquals(NONE, updated.subscriberFlowsStatus);
171 Assert.assertEquals(NONE, updated.dhcpStatus);
172 }
173
174 @Test
175 public void testHasDefaultEapol() {
176 DeviceId deviceId = DeviceId.deviceId("test-device");
177 ProviderId pid = new ProviderId("of", "foo");
178
179 Device device =
180 new DefaultDevice(pid, deviceId, Device.Type.OLT, "", "", "", "", null);
181
182 Port port = new DefaultPort(device, PortNumber.portNumber(16), true,
183 DefaultAnnotations.builder().set(PORT_NAME, "name-1").build());
184 ServiceKey skWithStatus = new ServiceKey(new AccessDevicePort(port),
185 oltFlowService.defaultEapolUniTag);
186
187 Port port17 = new DefaultPort(device, PortNumber.portNumber(17), true,
188 DefaultAnnotations.builder().set(PORT_NAME, "name-1").build());
189
190 OltPortStatus portStatusAdded = new OltPortStatus(
191 OltFlowService.OltFlowsStatus.ADDED,
192 NONE,
193 null
194 );
195
196 OltPortStatus portStatusRemoved = new OltPortStatus(
197 REMOVED,
198 NONE,
199 null
200 );
201
202 oltFlowService.cpStatus.put(skWithStatus, portStatusAdded);
203 Assert.assertTrue(oltFlowService.hasDefaultEapol(port));
204
205 oltFlowService.cpStatus.put(skWithStatus, portStatusRemoved);
206
207 Assert.assertFalse(oltFlowService.hasDefaultEapol(port17));
208 }
209
210 @Test
211 public void testHasSubscriberFlows() {
212 // TODO test with multiple services
213 DeviceId deviceId = DeviceId.deviceId("test-device");
214 ProviderId pid = new ProviderId("of", "foo");
215
216 Device device =
217 new DefaultDevice(pid, deviceId, Device.Type.OLT, "", "", "", "", null);
218
219 Port port = new DefaultPort(device, PortNumber.portNumber(16), true,
220 DefaultAnnotations.builder().set(PORT_NAME, "name-1").build());
221
222 UniTagInformation uti = new UniTagInformation.Builder().setServiceName("test").build();
223 ServiceKey skWithStatus = new ServiceKey(new AccessDevicePort(port),
224 uti);
225
226 OltPortStatus withDefaultEapol = new OltPortStatus(
227 ADDED,
228 NONE,
229 NONE
230 );
231
232 OltPortStatus withDhcp = new OltPortStatus(
233 REMOVED,
234 NONE,
235 ADDED
236 );
237
238 OltPortStatus withSubFlow = new OltPortStatus(
239 REMOVED,
240 ADDED,
241 ADDED
242 );
243
244 oltFlowService.cpStatus.put(skWithStatus, withDefaultEapol);
245 Assert.assertFalse(oltFlowService.hasSubscriberFlows(port, uti));
246
247 oltFlowService.cpStatus.put(skWithStatus, withDhcp);
248 Assert.assertTrue(oltFlowService.hasDhcpFlows(port, uti));
249
250 oltFlowService.cpStatus.put(skWithStatus, withSubFlow);
251 Assert.assertTrue(oltFlowService.hasSubscriberFlows(port, uti));
252 }
253
254 @Test
255 public void testHandleBasicPortFlowsNoEapol() throws Exception {
256 oltFlowService.enableEapol = false;
257 // create empty service for testing
258 List<UniTagInformation> uniTagInformationList = new LinkedList<>();
259 UniTagInformation empty = new UniTagInformation.Builder().build();
260 uniTagInformationList.add(empty);
261
262 SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
263 si.setUniTagList(uniTagInformationList);
264
265 final DiscoveredSubscriber addedSub =
266 new DiscoveredSubscriber(testDevice,
267 uniUpdateEnabled, DiscoveredSubscriber.Status.ADDED,
268 false, si);
269 oltFlowService.handleBasicPortFlows(addedSub, DEFAULT_BP_ID_DEFAULT, DEFAULT_BP_ID_DEFAULT);
270 // if eapol is not enabled there's nothing we need to do,
271 // so make sure we don't even call sadis
272 verify(oltFlowService.subsService, never()).get(any());
273 }
274
275 @Test
276 public void testHandleBasicPortFlowsWithEapolNoMeter() throws Exception {
277 // create empty service for testing
278 List<UniTagInformation> uniTagInformationList = new LinkedList<>();
279 UniTagInformation empty = new UniTagInformation.Builder().build();
280 uniTagInformationList.add(empty);
281 SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
282 si.setUniTagList(uniTagInformationList);
283 final DiscoveredSubscriber addedSub =
284 new DiscoveredSubscriber(testDevice,
285 uniUpdateEnabled, DiscoveredSubscriber.Status.ADDED,
286 false, si);
287 // whether the meter is pending or not is up to the createMeter method to handle
288 // we just don't proceed with the subscriber till it's ready
289 doReturn(false).when(oltFlowService.oltMeterService)
290 .createMeter(addedSub.device.id(), DEFAULT_BP_ID_DEFAULT);
291 boolean res = oltFlowService.handleBasicPortFlows(addedSub, DEFAULT_BP_ID_DEFAULT, DEFAULT_BP_ID_DEFAULT);
292
293 Assert.assertFalse(res);
294
295 // we do not create flows
296 verify(oltFlowService.flowObjectiveService, never())
297 .filter(eq(addedSub.device.id()), any());
298 }
299
300 @Test
301 public void testHandleBasicPortFlowsWithEapolAddedMeter() throws Exception {
302 // create empty service for testing
303 List<UniTagInformation> uniTagInformationList = new LinkedList<>();
304 UniTagInformation empty = new UniTagInformation.Builder().build();
305 uniTagInformationList.add(empty);
306 SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
307 si.setUniTagList(uniTagInformationList);
308 final DiscoveredSubscriber addedSub =
309 new DiscoveredSubscriber(testDevice,
310 uniUpdateEnabled, DiscoveredSubscriber.Status.ADDED,
311 false, si);
312 // this is the happy case, we have the meter so we check that the default EAPOL flow
313 // is installed
314 doReturn(true).when(oltFlowService.oltMeterService)
315 .createMeter(deviceId, DEFAULT_BP_ID_DEFAULT);
316 doReturn(true).when(oltFlowService.oltMeterService)
317 .hasMeterByBandwidthProfile(deviceId, DEFAULT_BP_ID_DEFAULT);
318 doReturn(MeterId.meterId(1)).when(oltFlowService.oltMeterService)
319 .getMeterIdForBandwidthProfile(deviceId, DEFAULT_BP_ID_DEFAULT);
320
321 FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
322 .permit()
323 .withKey(Criteria.matchInPort(uniUpdateEnabled.number()))
324 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
325 .fromApp(testAppId)
326 .withPriority(10000)
327 .withMeta(
328 DefaultTrafficTreatment.builder()
329 .meter(MeterId.meterId(1))
330 .writeMetadata(oltFlowService.createTechProfValueForWriteMetadata(
331 VlanId.vlanId(eapolDefaultVlan),
332 oltFlowService.defaultTechProfileId, MeterId.meterId(1)), 0)
333 .setOutput(PortNumber.CONTROLLER)
334 .pushVlan()
335 .setVlanId(VlanId.vlanId(eapolDefaultVlan)).build()
336 )
337 .add();
338
339
340 oltFlowService.handleBasicPortFlows(addedSub, DEFAULT_BP_ID_DEFAULT, DEFAULT_BP_ID_DEFAULT);
341
342 // we check for an existing meter (present)
343 // FIXME understand why the above test invokes this call and this one doesn't
344// verify(oltFlowService.oltMeterService, times(1))
345// .hasMeterByBandwidthProfile(eq(addedSub.device.id()), eq(DEFAULT_BP_ID_DEFAULT));
346
347 // the meter exist, no need to check for PENDING or to create it
348 verify(oltFlowService.oltMeterService, never())
349 .hasPendingMeterByBandwidthProfile(eq(deviceId), eq(DEFAULT_BP_ID_DEFAULT));
350 verify(oltFlowService.oltMeterService, never())
351 .createMeterForBp(eq(deviceId), eq(DEFAULT_BP_ID_DEFAULT));
352
353 verify(oltFlowService.flowObjectiveService, times(1))
354 .filter(eq(deviceId), argThat(new FilteringObjectiveMatcher(expectedFilter)));
355 }
356
357 @Test
358 public void testHandleBasicPortFlowsRemovedSub() throws Exception {
359 // create empty service for testing
360 List<UniTagInformation> uniTagInformationList = new LinkedList<>();
361 UniTagInformation empty = new UniTagInformation.Builder().build();
362 uniTagInformationList.add(empty);
363 SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
364 si.setUniTagList(uniTagInformationList);
365 final DiscoveredSubscriber removedSub =
366 new DiscoveredSubscriber(testDevice,
367 uniUpdateEnabled, DiscoveredSubscriber.Status.REMOVED,
368 false, si);
369 // we are testing that when a port goes down we remove the default EAPOL flow
370
371 doReturn(MeterId.meterId(1)).when(oltFlowService.oltMeterService)
372 .getMeterIdForBandwidthProfile(deviceId, DEFAULT_BP_ID_DEFAULT);
373
374 FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
375 .deny()
376 .withKey(Criteria.matchInPort(uniUpdateEnabled.number()))
377 .addCondition(Criteria.matchEthType(EthType.EtherType.EAPOL.ethType()))
378 .fromApp(testAppId)
379 .withPriority(10000)
380 .withMeta(
381 DefaultTrafficTreatment.builder()
382 .meter(MeterId.meterId(1))
383 .writeMetadata(oltFlowService.createTechProfValueForWriteMetadata(
384 VlanId.vlanId(eapolDefaultVlan),
385 oltFlowService.defaultTechProfileId, MeterId.meterId(1)), 0)
386 .setOutput(PortNumber.CONTROLLER)
387 .pushVlan()
388 .setVlanId(VlanId.vlanId(eapolDefaultVlan)).build()
389 )
390 .add();
391
392 oltFlowService.handleBasicPortFlows(removedSub, DEFAULT_BP_ID_DEFAULT, DEFAULT_BP_ID_DEFAULT);
393
394 verify(oltFlowService.flowObjectiveService, times(1))
395 .filter(eq(deviceId), argThat(new FilteringObjectiveMatcher(expectedFilter)));
396 }
397
398 @Test
399 public void testHandleNniFlowsOnlyLldp() {
400 oltFlowService.enableDhcpOnNni = false;
401 oltFlowService.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
402
403 FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
404 .permit()
405 .withKey(Criteria.matchInPort(nniPort.number()))
406 .addCondition(Criteria.matchEthType(EthType.EtherType.LLDP.ethType()))
407 .fromApp(testAppId)
408 .withPriority(10000)
409 .withMeta(DefaultTrafficTreatment.builder().setOutput(PortNumber.CONTROLLER).build())
410 .add();
411
412 verify(oltFlowService.flowObjectiveService, times(1))
413 .filter(eq(deviceId), argThat(new FilteringObjectiveMatcher(expectedFilter)));
414 verify(oltFlowService.flowObjectiveService, times(1))
415 .filter(eq(deviceId), any());
416 }
417
418 @Test
419 public void testHandleNniFlowsDhcpV4() {
420 oltFlowService.enableDhcpOnNni = true;
421 oltFlowService.enableDhcpV4 = true;
422 oltFlowService.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
423
424 FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
425 .permit()
426 .withKey(Criteria.matchInPort(nniPort.number()))
427 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
428 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_UDP))
429 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(67)))
430 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(68)))
431 .fromApp(testAppId)
432 .withPriority(10000)
433 .withMeta(DefaultTrafficTreatment.builder().setOutput(PortNumber.CONTROLLER).build())
434 .add();
435
436 // invoked with the correct DHCP filtering objective
437 verify(oltFlowService.flowObjectiveService, times(1))
438 .filter(eq(deviceId), argThat(new FilteringObjectiveMatcher(expectedFilter)));
439 // invoked only twice, LLDP and DHCP
440 verify(oltFlowService.flowObjectiveService, times(2))
441 .filter(eq(deviceId), any());
442 }
443
444 @Test
445 public void testRemoveNniFlowsDhcpV4() {
446 oltFlowService.enableDhcpOnNni = true;
447 oltFlowService.enableDhcpV4 = true;
448 oltFlowService.handleNniFlows(testDevice, nniPortDisabled, OltFlowService.FlowOperation.REMOVE);
449
450 FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
451 .deny()
452 .withKey(Criteria.matchInPort(nniPort.number()))
453 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
454 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_UDP))
455 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(67)))
456 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(68)))
457 .fromApp(testAppId)
458 .withPriority(10000)
459 .withMeta(DefaultTrafficTreatment.builder().setOutput(PortNumber.CONTROLLER).build())
460 .add();
461
462 // invoked with the correct DHCP filtering objective
463 verify(oltFlowService.flowObjectiveService, times(1))
464 .filter(eq(deviceId), argThat(new FilteringObjectiveMatcher(expectedFilter)));
465 // invoked only twice, LLDP and DHCP
466 verify(oltFlowService.flowObjectiveService, times(2))
467 .filter(eq(deviceId), any());
468 }
469
470 @Test
471 public void testHandleNniFlowsDhcpV6() {
472 oltFlowService.enableDhcpOnNni = true;
473 oltFlowService.enableDhcpV4 = false;
474 oltFlowService.enableDhcpV6 = true;
475 oltFlowService.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
476
477 FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
478 .permit()
479 .withKey(Criteria.matchInPort(nniPort.number()))
480 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV6.ethType()))
481 .addCondition(Criteria.matchIPProtocol(IPv6.PROTOCOL_UDP))
482 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(546)))
483 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(547)))
484 .fromApp(testAppId)
485 .withPriority(10000)
486 .withMeta(DefaultTrafficTreatment.builder().setOutput(PortNumber.CONTROLLER).build())
487 .add();
488
489 // invoked with the correct DHCP filtering objective
490 verify(oltFlowService.flowObjectiveService, times(1))
491 .filter(eq(deviceId), argThat(new FilteringObjectiveMatcher(expectedFilter)));
492 // invoked only twice, LLDP and DHCP
493 verify(oltFlowService.flowObjectiveService, times(2))
494 .filter(eq(deviceId), any());
495 }
496
497 @Test
498 public void testHandleNniFlowsIgmp() {
499 oltFlowService.enableDhcpOnNni = false;
500 oltFlowService.enableIgmpOnNni = true;
501 oltFlowService.handleNniFlows(testDevice, nniPort, OltFlowService.FlowOperation.ADD);
502
503 FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
504 .permit()
505 .withKey(Criteria.matchInPort(nniPort.number()))
506 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
507 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_IGMP))
508 .fromApp(testAppId)
509 .withPriority(10000)
510 .add();
511
512 // invoked with the correct DHCP filtering objective
513 verify(oltFlowService.flowObjectiveService, times(1))
514 .filter(eq(deviceId), argThat(new FilteringObjectiveMatcher(expectedFilter)));
515 // invoked only twice, LLDP and DHCP
516 verify(oltFlowService.flowObjectiveService, times(2))
517 .filter(eq(deviceId), any());
518 }
519
520 @Test
521 public void testMacAddressNotRequired() {
522 // create a single service that doesn't require mac address
523 List<UniTagInformation> uniTagInformationList = new LinkedList<>();
524 UniTagInformation hsia = new UniTagInformation.Builder()
525 .setEnableMacLearning(false)
526 .build();
527 uniTagInformationList.add(hsia);
528 SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
529 si.setUniTagList(uniTagInformationList);
530
531 boolean isMacAvailable = oltFlowService.isMacAddressAvailable(testDevice.id(), uniUpdateEnabled, si);
532 // we return true as we don't care wether it's available or not
533 Assert.assertTrue(isMacAvailable);
534 }
535
536 @Test
537 public void testIsMacAddressAvailableViaMacLearning() {
538
539 // create a single service that requires macLearning to be enabled
540 List<UniTagInformation> uniTagInformationList = new LinkedList<>();
541 VlanId hsiaCtag = VlanId.vlanId((short) 11);
542 UniTagInformation hsia = new UniTagInformation.Builder()
543 .setPonCTag(hsiaCtag)
544 .setEnableMacLearning(true).build();
545 uniTagInformationList.add(hsia);
546
547 SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
548 si.setUniTagList(uniTagInformationList);
549
550 // with no hosts discovered, return false
551 boolean isMacAvailable = oltFlowService.isMacAddressAvailable(testDevice.id(), uniUpdateEnabled, si);
552 Assert.assertFalse(isMacAvailable);
553
554 // with a discovered host, return true
555 Host fakeHost = new DefaultHost(ProviderId.NONE, HostId.hostId(MacAddress.NONE), MacAddress.ZERO,
556 hsiaCtag, HostLocation.NONE, new HashSet<>(), DefaultAnnotations.builder().build());
557 Set<Host> hosts = new HashSet<>(Arrays.asList(fakeHost));
558 doReturn(hosts).when(oltFlowService.hostService).getConnectedHosts((ConnectPoint) any());
559
560 isMacAvailable = oltFlowService.isMacAddressAvailable(testDevice.id(), uniUpdateEnabled, si);
561 Assert.assertTrue(isMacAvailable);
562 }
563
564 @Test
565 public void testIsMacAddressAvailableViaConfiguration() {
566 // create a single service that has a macAddress configured
567 List<UniTagInformation> uniTagInformationList = new LinkedList<>();
568 UniTagInformation hsia = new UniTagInformation.Builder()
569 .setConfiguredMacAddress("2e:0a:00:01:00:00")
570 .build();
571 uniTagInformationList.add(hsia);
572 SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
573 si.setUniTagList(uniTagInformationList);
574
575 boolean isMacAvailable = oltFlowService.isMacAddressAvailable(testDevice.id(), uniUpdateEnabled, si);
576 Assert.assertTrue(isMacAvailable);
577 }
578
579 @Test
580 public void testHandleSubscriberDhcpFlowsAdd() {
581
582 String usBp = "usBp";
583 String usOltBp = "usOltBp";
584 oltFlowService.enableDhcpV4 = true;
585
586 // create two services, one requires DHCP the other doesn't
587 List<UniTagInformation> uniTagInformationList = new LinkedList<>();
588 VlanId hsiaCtag = VlanId.vlanId((short) 11);
589 UniTagInformation hsia = new UniTagInformation.Builder()
590 .setPonCTag(hsiaCtag)
591 .setTechnologyProfileId(64)
592 .setUniTagMatch(VlanId.vlanId(VlanId.NO_VID))
593 .setUpstreamBandwidthProfile(usBp)
594 .setUpstreamOltBandwidthProfile(usOltBp)
595 .setIsDhcpRequired(true).build();
596 UniTagInformation mc = new UniTagInformation.Builder()
597 .setIsDhcpRequired(false).build();
598 uniTagInformationList.add(hsia);
599 uniTagInformationList.add(mc);
600
601 SubscriberAndDeviceInformation si = new SubscriberAndDeviceInformation();
602 si.setUniTagList(uniTagInformationList);
603
604 final DiscoveredSubscriber addedSub =
605 new DiscoveredSubscriber(testDevice,
606 uniUpdateEnabled, DiscoveredSubscriber.Status.ADDED,
607 false, si);
608
609 // return meter IDs
610 doReturn(MeterId.meterId(2)).when(oltFlowService.oltMeterService)
611 .getMeterIdForBandwidthProfile(addedSub.device.id(), usBp);
612 doReturn(MeterId.meterId(3)).when(oltFlowService.oltMeterService)
613 .getMeterIdForBandwidthProfile(addedSub.device.id(), usOltBp);
614
615 // TODO improve the matches on the filter
616 FilteringObjective expectedFilter = DefaultFilteringObjective.builder()
617 .permit()
618 .withKey(Criteria.matchInPort(addedSub.port.number()))
619 .addCondition(Criteria.matchEthType(EthType.EtherType.IPV4.ethType()))
620 .addCondition(Criteria.matchIPProtocol(IPv4.PROTOCOL_UDP))
621 .addCondition(Criteria.matchUdpSrc(TpPort.tpPort(68)))
622 .addCondition(Criteria.matchUdpDst(TpPort.tpPort(67)))
623 .fromApp(testAppId)
624 .withPriority(10000)
625 .add();
626
627 oltFlowService.handleSubscriberDhcpFlows(addedSub.device.id(), addedSub.port,
628 OltFlowService.FlowOperation.ADD, si);
629 verify(oltFlowService.flowObjectiveService, times(1))
630 .filter(eq(addedSub.device.id()), argThat(new FilteringObjectiveMatcher(expectedFilter)));
631 }
632
633 @Test
634 public void testInternalFlowListenerNotMaster() {
635 doReturn(false).when(oltFlowService.oltDeviceService).isLocalLeader(any());
636
637 FlowRule flowRule = DefaultFlowRule.builder()
638 .forDevice(DeviceId.deviceId("foo"))
639 .fromApp(testAppId)
640 .makePermanent()
641 .withPriority(1000)
642 .build();
643 FlowRuleEvent event = new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADDED,
644 flowRule);
645
646 internalFlowListener.event(event);
647
648 // if we're not master of the device, we should not update
649 verify(internalFlowListener, never()).updateCpStatus(any(), any(), any());
650 }
651
652 @Test
653 public void testInternalFlowListenerDifferentApp() {
654 ApplicationId someAppId = new DefaultApplicationId(1, "org.opencord.olt.not-test");
655 FlowRule flowRule = DefaultFlowRule.builder()
656 .forDevice(DeviceId.deviceId("foo"))
657 .fromApp(someAppId)
658 .makePermanent()
659 .withPriority(1000)
660 .build();
661 FlowRuleEvent event = new FlowRuleEvent(FlowRuleEvent.Type.RULE_ADDED,
662 flowRule);
663
664 internalFlowListener.event(event);
665
666 // if we're not master of the device, we should not update
667 verify(internalFlowListener, never()).updateCpStatus(any(), any(), any());
668 }
669}