blob: c55544ec661b328aa83636249354925e01622256 [file] [log] [blame]
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +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.cordmcast;
17
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000018import static org.easymock.EasyMock.expect;
19import static org.easymock.EasyMock.replay;
Arjun E Kabf9e6e2020-03-02 10:15:21 +000020
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000021import org.easymock.EasyMock;
22import org.junit.After;
23import org.junit.Before;
24import org.junit.Test;
Arjun E Kabf9e6e2020-03-02 10:15:21 +000025import org.onlab.junit.TestUtils;
26import org.onlab.packet.IpAddress;
27import org.onlab.packet.VlanId;
28import org.onosproject.cfg.ComponentConfigAdapter;
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000029import org.onosproject.cfg.ComponentConfigService;
30import org.onosproject.mcast.api.McastEvent;
Arjun E Kabf9e6e2020-03-02 10:15:21 +000031import org.onosproject.mcast.api.McastRoute;
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000032import org.onosproject.mcast.api.McastRouteUpdate;
33import org.onosproject.mcast.api.MulticastRouteService;
34import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.DeviceId;
36import org.onosproject.net.HostId;
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000037import org.onosproject.net.flow.TrafficSelector;
38import org.onosproject.net.flow.TrafficTreatment;
39import org.onosproject.net.flow.criteria.IPCriterion;
40import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
41import org.onosproject.net.flowobjective.Objective;
42import org.onosproject.store.service.StorageServiceAdapter;
43import org.onosproject.store.service.TestConsistentMap;
44import org.osgi.service.component.ComponentContext;
45import com.google.common.collect.ImmutableMap;
46import com.google.common.collect.Sets;
Arjun E Kabf9e6e2020-03-02 10:15:21 +000047
48import java.util.Dictionary;
49import java.util.HashSet;
50import java.util.Hashtable;
51import java.util.Set;
52import java.util.Map;
53import java.util.Arrays;
54import java.util.Collection;
55
56import static org.junit.Assert.*;
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000057import static org.onlab.junit.TestTools.assertAfter;
58
59public class McastTest extends McastTestBase {
60
61 private CordMcast cordMcast;
Arjun E Kabf9e6e2020-03-02 10:15:21 +000062 private CordMcastStatisticsManager cordMcastStatisticsManager;
63
64 private MockCordMcastStatisticsEventListener mockListener = new MockCordMcastStatisticsEventListener();
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000065
66 private static final int WAIT_TIMEOUT = 1000;
67 private static final int WAIT = 250;
68 McastRouteUpdate previousSubject, currentSubject;
69
70 @Before
71 public void setUp() {
72 cordMcast = new CordMcast();
Arjun E Kabf9e6e2020-03-02 10:15:21 +000073 cordMcastStatisticsManager = new CordMcastStatisticsManager();
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000074
75 cordMcast.coreService = new MockCoreService();
Arjun E Kabf9e6e2020-03-02 10:15:21 +000076 cordMcast.networkConfig = new TestNetworkConfigRegistry();
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000077 cordMcast.flowObjectiveService = new MockFlowObjectiveService();
78 cordMcast.mastershipService = new TestMastershipService();
Esin Karaman996177c2020-03-05 13:21:09 +000079 cordMcast.deviceService = new MockDeviceService();
Arjun E Kabf9e6e2020-03-02 10:15:21 +000080 cordMcast.componentConfigService = new ComponentConfigAdapter();
81 cordMcastStatisticsManager.componentConfigService = new ComponentConfigAdapter();
82 cordMcastStatisticsManager.addListener(mockListener);
Esin Karaman996177c2020-03-05 13:21:09 +000083 cordMcast.sadisService = new MockSadisService();
Arjun E Kabf9e6e2020-03-02 10:15:21 +000084 cordMcast.cordMcastStatisticsService = cordMcastStatisticsManager;
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000085
Arjun E Kabf9e6e2020-03-02 10:15:21 +000086 cordMcast.storageService = EasyMock.createMock(StorageServiceAdapter.class);
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000087 expect(cordMcast.storageService.consistentMapBuilder()).andReturn(new TestConsistentMap.Builder<>());
88 replay(cordMcast.storageService);
89
90 Dictionary<String, Object> cfgDict = new Hashtable<String, Object>();
91 cfgDict.put("vlanEnabled", false);
Arjun E Kabf9e6e2020-03-02 10:15:21 +000092 cfgDict.put("eventGenerationPeriodInSeconds", EVENT_GENERATION_PERIOD);
93
94 cordMcast.componentConfigService = EasyMock.createNiceMock(ComponentConfigService.class);
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +000095 replay(cordMcast.componentConfigService);
96
Arjun E Kabf9e6e2020-03-02 10:15:21 +000097 Set<McastRoute> route1Set = new HashSet<McastRoute>();
98 route1Set.add(route1);
99
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +0000100 cordMcast.mcastService = EasyMock.createNiceMock(MulticastRouteService.class);
101 expect(cordMcast.mcastService.getRoutes()).andReturn(Sets.newHashSet());
102 replay(cordMcast.mcastService);
103
Arjun E Kabf9e6e2020-03-02 10:15:21 +0000104 cordMcastStatisticsManager.mcastService = EasyMock.createNiceMock(MulticastRouteService.class);
105 expect(cordMcastStatisticsManager.mcastService.getRoutes()).andReturn(route1Set).times(2);
106 replay(cordMcastStatisticsManager.mcastService);
107
108 TestUtils.setField(cordMcastStatisticsManager, "eventDispatcher", new TestEventDispatcher());
109
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +0000110 ComponentContext componentContext = EasyMock.createMock(ComponentContext.class);
Arjun E Kabf9e6e2020-03-02 10:15:21 +0000111 expect(componentContext.getProperties()).andReturn(cfgDict).times(2);
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +0000112 replay(componentContext);
Arjun E Kabf9e6e2020-03-02 10:15:21 +0000113 cordMcast.cordMcastStatisticsService = cordMcastStatisticsManager;
114 cordMcastStatisticsManager.activate(componentContext);
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +0000115
116 cordMcast.activate(componentContext);
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +0000117 }
118
119 @After
120 public void tearDown() {
121 cordMcast.deactivate();
122 forwardMap.clear();
123 nextMap.clear();
124 }
125
126 @Test
127 public void testAddingSinkEvent() throws InterruptedException {
128
129 Set<ConnectPoint> sinks2Cp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B));
130 Map<HostId, Set<ConnectPoint>> sinks2 = ImmutableMap.of(HOST_ID_NONE, sinks2Cp);
131
132 //Adding the details to create different routes
133 previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
134 currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks2);
135 // Creating new mcast event for adding sink
136 McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
137 cordMcast.listener.event(event);
138 synchronized (forwardMap) {
139 forwardMap.wait(WAIT_TIMEOUT);
140 }
141
142 // ForwardMap will contain the operation "Add" in the flowObjective. None -> CP_B
143 assertNotNull(forwardMap.get(DEVICE_ID_OF_A));
144 assertTrue(forwardMap.get(DEVICE_ID_OF_A).op() == Objective.Operation.ADD);
145
146 // Output port number will be PORT_B i.e. 16
147 Collection<TrafficTreatment> traffictreatMentCollection =
148 nextMap.get(DEVICE_ID_OF_A).next();
149 assertTrue(1 == traffictreatMentCollection.size());
150 OutputInstruction output = null;
151 for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
152 output = outputPort(trafficTreatment);
153 }
154 assertNotNull(output);
155 assertTrue(PORT_B == output.port());
156 // Checking the group ip address
157 TrafficSelector trafficSelector = forwardMap.get(DEVICE_ID_OF_A).selector();
158 IPCriterion ipCriterion = ipAddress(trafficSelector);
159 assertNotNull(ipCriterion);
160 assertTrue(MULTICAST_IP.equals(ipCriterion.ip().address()));
161
162 }
163
164 @Test
165 public void testAddToExistingSinkEvent() throws InterruptedException {
166
167 // Adding first sink (none --> CP_B)
168 testAddingSinkEvent();
169
170 Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B));
171 Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
172 previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
173 sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B, CONNECT_POINT_C));
174 sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
175 currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
176 // Again listening the mcast event with different output port ( none --> CP_B, CP_C)
177 McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
178 cordMcast.listener.event(event);
179
180 // NextMap will contain the operation "ADD_TO_EXISTING" in the DefaultNextObjective.
181 assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
182 assertTrue(nextMap.get(DEVICE_ID_OF_A).op() == Objective.Operation.ADD_TO_EXISTING));
183 // Output port number will be changed to 24 i.e. PORT_C
184 Collection<TrafficTreatment> traffictreatMentCollection = nextMap.get(DEVICE_ID_OF_A).next();
185 assertTrue(1 == traffictreatMentCollection.size());
186 OutputInstruction output = null;
187 for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
188 output = outputPort(trafficTreatment);
189 }
190 assertNotNull(output);
191 assertTrue(PORT_C == output.port());
192 }
193
194 @Test
195 public void testRemoveSinkEvent() throws InterruptedException {
196
197 testAddToExistingSinkEvent();
198 // Handling the mcast event for removing sink.
199 Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_B, CONNECT_POINT_C));
200 Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
201 previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
202 sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_C));
203 sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
204 currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
205 McastEvent event = new McastEvent(McastEvent.Type.SINKS_REMOVED, previousSubject, currentSubject);
206 cordMcast.listener.event(event);
207 // Operation will be REMOVE_FROM_EXISTING and nextMap will be updated. ( None --> CP_C)
208 assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
209 assertTrue(nextMap.get(DEVICE_ID_OF_A).op() == Objective.Operation.REMOVE_FROM_EXISTING));
210
211 // Output port number will be PORT_B i.e. 16
212 // Port_B is removed from the group.
213 Collection<TrafficTreatment> traffictreatMentCollection =
214 nextMap.get(DEVICE_ID_OF_A).next();
215 assertTrue(1 == traffictreatMentCollection.size());
216 OutputInstruction output = null;
217 for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
218 output = outputPort(trafficTreatment);
219 }
220 assertNotNull(output);
221 assertTrue(PORT_B == output.port());
222
223 }
224
225 @Test
226 public void testRemoveLastSinkEvent() throws InterruptedException {
227
228 testRemoveSinkEvent();
229 // Handling the mcast event for removing sink.
230 Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList(CONNECT_POINT_C));
231 Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
232 previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
233 sinksCp = new HashSet<ConnectPoint>(Arrays.asList());
234 sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
235 currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
236 McastEvent event = new McastEvent(McastEvent.Type.SINKS_REMOVED, previousSubject, currentSubject);
237 cordMcast.listener.event(event);
238
239 // Operation will be REMOVE_FROM_EXISTING and nextMap will be updated. None --> { }
240 assertAfter(WAIT_TIMEOUT, WAIT_TIMEOUT * 2, () ->
241 assertTrue(nextMap.get(DEVICE_ID_OF_A).op() == Objective.Operation.REMOVE_FROM_EXISTING));
242
243 // Output port number will be changed to 24 i.e. PORT_C
244 Collection<TrafficTreatment> traffictreatMentCollection = nextMap.get(DEVICE_ID_OF_A).next();
245 assertTrue(1 == traffictreatMentCollection.size());
246 OutputInstruction output = null;
247 for (TrafficTreatment trafficTreatment : traffictreatMentCollection) {
248 output = outputPort(trafficTreatment);
249 }
250 assertNotNull(output);
251 assertTrue(PORT_C == output.port());
252 }
253
254 @Test
255 public void testUnkownOltDevice() throws InterruptedException {
256
257 // Configuration of mcast event for unknown olt device
258 final DeviceId deviceIdOfB = DeviceId.deviceId("of:1");
259
260 ConnectPoint connectPointA = new ConnectPoint(deviceIdOfB, PORT_A);
261 ConnectPoint connectPointB = new ConnectPoint(deviceIdOfB, PORT_B);
262 Set<ConnectPoint> sourcesCp = new HashSet<ConnectPoint>(Arrays.asList(connectPointA));
263 Set<ConnectPoint> sinksCp = new HashSet<ConnectPoint>(Arrays.asList());
264 Set<ConnectPoint> sinks2Cp = new HashSet<ConnectPoint>(Arrays.asList(connectPointB));
265 Map<HostId, Set<ConnectPoint>> sources = ImmutableMap.of(HOST_ID_NONE, sourcesCp);
266
267 Map<HostId, Set<ConnectPoint>> sinks = ImmutableMap.of(HOST_ID_NONE, sinksCp);
268 Map<HostId, Set<ConnectPoint>> sinks2 = ImmutableMap.of(HOST_ID_NONE, sinks2Cp);
269 //Adding the details to create different routes
270 McastRouteUpdate previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
271 McastRouteUpdate currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks2);
272 // Creating new mcast event for adding sink
273 McastEvent event = new McastEvent(McastEvent.Type.SINKS_ADDED, previousSubject, currentSubject);
274 cordMcast.listener.event(event);
275 // OltInfo flag is set to true when olt device is unkown
276 assertAfter(WAIT, WAIT * 2, () -> assertTrue(knownOltFlag));
277 assertTrue(0 == forwardMap.size());
278 assertTrue(0 == nextMap.size());
279
280 }
281
282 @Test
283 public void testRouteAddedEvent() throws InterruptedException {
284
285 //Adding the details to create different routes
286 previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
287 currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
288 // Creating new mcast event for route adding
289 McastEvent event = new McastEvent(McastEvent.Type.ROUTE_ADDED, previousSubject, currentSubject);
290 cordMcast.listener.event(event);
291 // There will be no forwarding objective
292 assertAfter(WAIT, WAIT * 2, () -> assertTrue(0 == forwardMap.size()));
293 assertTrue(0 == nextMap.size());
294
295 }
296
297
298 @Test
299 public void testRouteRemovedEvent() throws InterruptedException {
300
301 testRouteAddedEvent();
302
303 //Adding the details to create different routes
304 previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
305 currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
306 // Creating new mcast event for route removing
307 McastEvent event = new McastEvent(McastEvent.Type.ROUTE_REMOVED, previousSubject, currentSubject);
308 cordMcast.listener.event(event);
309 // There will be no forwarding objective
310 assertAfter(WAIT, WAIT * 2, () -> assertTrue(0 == forwardMap.size()));
311 assertTrue(0 == nextMap.size());
312
313 }
314
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +0000315 @Test
316 public void testSourceAddedEvent() throws InterruptedException {
317
318 // Adding route before adding source.
319 testRouteAddedEvent();
320
321 //Adding the details to create different routes
322 previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
323 currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
324 // Creating new mcast event for source adding
325 McastEvent event = new McastEvent(McastEvent.Type.SOURCES_ADDED, previousSubject, currentSubject);
326 cordMcast.listener.event(event);
327 // There will be no forwarding objective
328 assertAfter(WAIT, WAIT * 2, () -> assertTrue(0 == forwardMap.size()));
329 assertTrue(0 == nextMap.size());
330
331 }
332
333 @Test
334 public void testSourcesRemovedEvent() throws InterruptedException {
335
336 testSourceAddedEvent();
337
338 //Adding the details to create different routes
339 previousSubject = McastRouteUpdate.mcastRouteUpdate(route1, sources, sinks);
340 currentSubject = McastRouteUpdate.mcastRouteUpdate(route1, emptySource, sinks);
341 // Creating new mcast event for removing source
342 // Warning message of unknown event will be displayed.
343 McastEvent event = new McastEvent(McastEvent.Type.SOURCES_REMOVED, previousSubject, currentSubject);
344 cordMcast.listener.event(event);
345 assertAfter(WAIT, WAIT * 2, () -> assertTrue(0 == forwardMap.size()));
346 assertTrue(0 == nextMap.size());
347 }
348
Arjun E Kabf9e6e2020-03-02 10:15:21 +0000349 @Test
350 public void mcastTestEventGeneration() throws InterruptedException {
351 //fetching route details used to push CordMcastStatisticsEvent.
352 IpAddress testGroup = route1.group();
353 String testSource = route1.source().isEmpty() ? "*" : route1.source().get().toString();
354 VlanId testVlan = cordMcast.assignedVlan();
355
356 // Thread is scheduled without any delay
357 assertAfter(WAIT, WAIT * 2, () ->
358 assertEquals(1, mockListener.mcastEventList.size()));
359
360 for (CordMcastStatisticsEvent event: mockListener.mcastEventList) {
361 assertEquals(event.type(), CordMcastStatisticsEvent.Type.STATUS_UPDATE);
362 }
363
364 CordMcastStatistics cordMcastStatistics = mockListener.mcastEventList.get(0).subject().get(0);
365 assertEquals(VlanId.NONE, cordMcastStatistics.getVlanId());
366 assertEquals(testVlan, cordMcastStatistics.getVlanId());
367 assertEquals(testSource, cordMcastStatistics.getSourceAddress());
368 assertEquals(testGroup, cordMcastStatistics.getGroupAddress());
369
370 // Test for vlanEnabled
371 Dictionary<String, Object> cfgDict = new Hashtable<>();
372 cfgDict.put("vlanEnabled", true);
373
374 ComponentContext componentContext = EasyMock.createMock(ComponentContext.class);
375 expect(componentContext.getProperties()).andReturn(cfgDict);
376 replay(componentContext);
377 cordMcast.modified(componentContext);
378 testVlan = cordMcast.assignedVlan();
379
380 assertAfter(EVENT_GENERATION_PERIOD, EVENT_GENERATION_PERIOD * 1000, () ->
381 assertEquals(2, mockListener.mcastEventList.size()));
382
383 for (CordMcastStatisticsEvent event: mockListener.mcastEventList) {
384 assertEquals(event.type(), CordMcastStatisticsEvent.Type.STATUS_UPDATE);
385 }
386
387 cordMcastStatistics = mockListener.mcastEventList.get(1).subject().get(0);
388 assertNotEquals(VlanId.NONE, cordMcastStatistics.getVlanId());
389 assertEquals(testVlan, cordMcastStatistics.getVlanId());
390 assertEquals(testSource, cordMcastStatistics.getSourceAddress());
391 assertEquals(testGroup, cordMcastStatistics.getGroupAddress());
392 }
Sonal Kasliwala0bbe6c2020-01-06 10:46:30 +0000393}