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