blob: 566ed2b1fe641de4c039751b991fef5b3036cc58 [file] [log] [blame]
Yi Tseng0f1ffd12020-09-18 11:10:47 -07001/*
2 * Copyright 2020-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.onosproject.inbandtelemetry.impl;
17
18
Yi Tseng4027cac2020-10-13 19:15:12 -070019import com.fasterxml.jackson.databind.JsonNode;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070020import com.fasterxml.jackson.databind.ObjectMapper;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070021import com.google.common.collect.ImmutableList;
Yi Tseng4027cac2020-10-13 19:15:12 -070022import com.google.common.collect.ImmutableMap;
23import com.google.common.collect.ImmutableSet;
24import com.google.common.collect.Sets;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070025import org.easymock.Capture;
26import org.easymock.EasyMock;
27import org.junit.After;
28import org.junit.Before;
29import org.junit.Test;
30import org.onlab.packet.IpAddress;
Yi Tseng4027cac2020-10-13 19:15:12 -070031import org.onlab.packet.IpPrefix;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070032import org.onlab.packet.TpPort;
Yi Tseng4027cac2020-10-13 19:15:12 -070033import org.onlab.packet.VlanId;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070034import org.onosproject.TestApplicationId;
35import org.onosproject.core.ApplicationId;
36import org.onosproject.core.CoreService;
Yi Tseng4027cac2020-10-13 19:15:12 -070037import org.onosproject.inbandtelemetry.api.IntIntent;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070038import org.onosproject.mastership.MastershipService;
Yi Tseng4027cac2020-10-13 19:15:12 -070039import org.onosproject.net.ConnectPoint;
40import org.onosproject.net.DefaultDevice;
41import org.onosproject.net.DefaultHost;
42import org.onosproject.net.DefaultPort;
43import org.onosproject.net.Device;
44import org.onosproject.net.DeviceId;
45import org.onosproject.net.Host;
46import org.onosproject.net.HostId;
47import org.onosproject.net.Port;
48import org.onosproject.net.PortNumber;
49import org.onosproject.net.behaviour.inbandtelemetry.IntObjective;
50import org.onosproject.net.behaviour.inbandtelemetry.IntProgrammable;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070051import org.onosproject.net.behaviour.inbandtelemetry.IntReportConfig;
52import org.onosproject.net.behaviour.inbandtelemetry.IntDeviceConfig;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070053import org.onosproject.net.config.NetworkConfigEvent;
54import org.onosproject.net.config.NetworkConfigListener;
55import org.onosproject.net.config.NetworkConfigRegistry;
56import org.onosproject.net.config.NetworkConfigService;
57import org.onosproject.net.device.DeviceService;
Yi Tseng4027cac2020-10-13 19:15:12 -070058import org.onosproject.net.flow.DefaultTrafficSelector;
59import org.onosproject.net.flow.TrafficSelector;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070060import org.onosproject.net.host.HostService;
61import org.onosproject.store.service.StorageService;
62import org.onosproject.store.service.TestStorageService;
63
Yi Tseng4027cac2020-10-13 19:15:12 -070064import java.io.IOException;
65import java.io.InputStream;
66import java.util.List;
67import java.util.Map;
68
Yi Tseng0f1ffd12020-09-18 11:10:47 -070069import static org.easymock.EasyMock.anyObject;
70import static org.easymock.EasyMock.createNiceMock;
Yi Tseng4027cac2020-10-13 19:15:12 -070071import static org.easymock.EasyMock.eq;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070072import static org.easymock.EasyMock.expect;
73import static org.easymock.EasyMock.expectLastCall;
74import static org.easymock.EasyMock.newCapture;
75import static org.easymock.EasyMock.replay;
Yi Tseng4027cac2020-10-13 19:15:12 -070076import static org.easymock.EasyMock.reset;
77import static org.easymock.EasyMock.verify;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070078import static org.junit.Assert.assertEquals;
Yi Tseng4027cac2020-10-13 19:15:12 -070079import static org.junit.Assert.assertTrue;
80import static org.onosproject.net.behaviour.inbandtelemetry.IntProgrammable.IntFunctionality.POSTCARD;
81import static org.onosproject.net.behaviour.inbandtelemetry.IntProgrammable.IntFunctionality.SINK;
82import static org.onosproject.net.behaviour.inbandtelemetry.IntProgrammable.IntFunctionality.SOURCE;
83import static org.onosproject.net.behaviour.inbandtelemetry.IntProgrammable.IntFunctionality.TRANSIT;
Yi Tseng0f1ffd12020-09-18 11:10:47 -070084
85public class SimpleIntManagerTest {
86 private static final String APP_NAME = "org.onosproject.inbandtelemetry";
87 private static final ApplicationId APP_ID = new TestApplicationId(APP_NAME);
88 private static final IpAddress COLLECTOR_IP = IpAddress.valueOf("10.0.0.1");
Yi Tseng4027cac2020-10-13 19:15:12 -070089 private static final TpPort COLLECTOR_PORT = TpPort.tpPort(32766);
90 private static final int MIN_FLOW_HOP_LATENCY_CHANGE_NS = 32;
91 private static final String INT_REPORT_CONFIG_KEY = "report";
92 private static final DeviceId DEVICE_ID = DeviceId.deviceId("device:leaf1");
93 private static final TrafficSelector FLOW_SELECTOR1 = DefaultTrafficSelector.builder()
94 .matchIPDst(IpPrefix.valueOf("192.168.10.0/24"))
95 .matchVlanId(VlanId.vlanId((short) 10))
96 .build();
97 private static final TrafficSelector FLOW_SELECTOR2 = DefaultTrafficSelector.builder()
98 .matchIPDst(IpPrefix.valueOf("192.168.20.0/24"))
99 .matchVlanId(VlanId.vlanId((short) 20))
100 .build();
101 private static final Device DEFAULT_DEVICE =
102 new DefaultDevice(null, DEVICE_ID, Device.Type.SWITCH, "", "", "", "", null);
103 private static final List<Port> DEVICE_PORTS = ImmutableList.of(
104 new DefaultPort(DEFAULT_DEVICE, PortNumber.portNumber(1), true),
105 new DefaultPort(DEFAULT_DEVICE, PortNumber.portNumber(2), true)
106 );
107 private static final Host HOST1 =
108 new DefaultHost(null, HostId.hostId("00:00:00:00:00:01/None"), null,
109 VlanId.NONE, ImmutableSet.of(), ImmutableSet.of(), true);
110 private static final Host HOST2 =
111 new DefaultHost(null, HostId.hostId("00:00:00:00:00:02/None"), null,
112 VlanId.NONE, ImmutableSet.of(), ImmutableSet.of(), true);
113 private static final Map<ConnectPoint, Host> HOSTS = ImmutableMap.of(
114 ConnectPoint.fromString("device:leaf1/1"), HOST1,
115 ConnectPoint.fromString("device:leaf1/2"), HOST2
116 );
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700117
118 private SimpleIntManager manager;
119 private StorageService storageService;
120 private MastershipService mastershipService;
121 private CoreService coreService;
122 private HostService hostService;
123 private DeviceService deviceService;
124 private NetworkConfigRegistry networkConfigRegistry;
125 private NetworkConfigService networkConfigService;
126 private NetworkConfigListener networkConfigListener;
127
128
129 @Before
Yi Tseng4027cac2020-10-13 19:15:12 -0700130 public void setup() throws IOException {
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700131 storageService = new TestStorageService();
132 mastershipService = createNiceMock(MastershipService.class);
133 coreService = createNiceMock(CoreService.class);
134 hostService = createNiceMock(HostService.class);
135 deviceService = createNiceMock(DeviceService.class);
136 expect(deviceService.getDevices()).andReturn(ImmutableList.of()).anyTimes();
137 networkConfigRegistry = createNiceMock(NetworkConfigRegistry.class);
138 networkConfigService = createNiceMock(NetworkConfigService.class);
139
140 manager = new SimpleIntManager();
Yi Tseng4027cac2020-10-13 19:15:12 -0700141 manager.coreService = coreService;
142 manager.deviceService = deviceService;
143 manager.storageService = storageService;
144 manager.mastershipService = mastershipService;
145 manager.hostService = hostService;
146 manager.netcfgService = networkConfigService;
147 manager.netcfgRegistry = networkConfigRegistry;
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700148
Yi Tseng4027cac2020-10-13 19:15:12 -0700149 expect(coreService.registerApplication(APP_NAME))
150 .andReturn(APP_ID).anyTimes();
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700151 networkConfigRegistry.registerConfigFactory(anyObject());
152 expectLastCall().once();
153
154 Capture<NetworkConfigListener> capture = newCapture();
155 networkConfigService.addListener(EasyMock.capture(capture));
156 expectLastCall().once();
Yi Tseng4027cac2020-10-13 19:15:12 -0700157 IntReportConfig config = getIntReportConfig("/report-config.json");
158 expect(networkConfigService.getConfig(APP_ID, IntReportConfig.class))
159 .andReturn(config)
160 .anyTimes();
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700161 replay(mastershipService, deviceService, coreService,
162 hostService, networkConfigRegistry, networkConfigService);
163 manager.activate();
164 networkConfigListener = capture.getValue();
165 }
166
167 @After
168 public void teardown() {
169 manager.deactivate();
170 }
171
172 @Test
Yi Tseng4027cac2020-10-13 19:15:12 -0700173 public void testPushIntAppConfig() throws IOException {
174 IntReportConfig config = getIntReportConfig("/report-config.json");
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700175 NetworkConfigEvent event =
176 new NetworkConfigEvent(NetworkConfigEvent.Type.CONFIG_ADDED, APP_ID,
177 config, null, IntReportConfig.class);
178 networkConfigListener.event(event);
179
180 // We expected that the manager will store the device config which
181 // converted from the app config.
Yi Tseng4027cac2020-10-13 19:15:12 -0700182 IntDeviceConfig expectedConfig = createIntDeviceConfig();
183 IntDeviceConfig actualConfig = manager.getConfig();
184 assertEquals(expectedConfig, actualConfig);
185 }
186
187 @Test
188 public void testConfigNonIntDevice() {
189 reset(deviceService);
190 Device device = getMockDevice(false, DEVICE_ID);
191 expect(deviceService.getDevice(DEVICE_ID))
192 .andReturn(device)
193 .anyTimes();
194 expect(deviceService.getDevices())
195 .andReturn(ImmutableSet.of(device))
196 .anyTimes();
197 replay(deviceService, device);
198 assertTrue(manager.configDevice(DEVICE_ID));
199 verify();
200 }
201
202 @Test
203 public void testConfigSourceDevice() {
204 reset(deviceService, hostService);
205 Device device = getMockDevice(true, DEVICE_ID);
206 IntProgrammable intProg = getMockIntProgrammable(true, false, false, false);
207 setUpDeviceTest(device, intProg, true, false);
208 IntObjective intObj = IntObjective.builder()
209 .withSelector(FLOW_SELECTOR2)
210 .build();
211 expect(intProg.addIntObjective(eq(intObj)))
212 .andReturn(true)
213 .once();
214 expect(intProg.setSourcePort(PortNumber.portNumber(1))).andReturn(true).once();
215 expect(intProg.setSourcePort(PortNumber.portNumber(2))).andReturn(true).once();
216 replay(deviceService, hostService, device, intProg);
217 installTestIntents();
218 assertTrue(manager.configDevice(DEVICE_ID));
219 verify(intProg);
220 }
221
222 @Test
223 public void testConfigTransitDevice() {
224 reset(deviceService, hostService);
225 Device device = getMockDevice(true, DEVICE_ID);
226 IntProgrammable intProg = getMockIntProgrammable(false, true, false, false);
227 setUpDeviceTest(device, intProg, false, false);
228 replay(deviceService, hostService, device, intProg);
229 installTestIntents();
230 assertTrue(manager.configDevice(DEVICE_ID));
231 verify(intProg);
232 }
233
234 @Test
235 public void testConfigSinkDevice() {
236 reset(deviceService, hostService);
237 Device device = getMockDevice(true, DEVICE_ID);
238 IntProgrammable intProg = getMockIntProgrammable(false, false, true, false);
239 setUpDeviceTest(device, intProg, true, true);
240 expect(intProg.setSinkPort(PortNumber.portNumber(1))).andReturn(true).once();
241 expect(intProg.setSinkPort(PortNumber.portNumber(2))).andReturn(true).once();
242 replay(deviceService, hostService, device, intProg);
243 installTestIntents();
244 assertTrue(manager.configDevice(DEVICE_ID));
245 verify(intProg);
246 }
247
248 @Test
249 public void testConfigPostcardOnlyDevice() {
250 reset(deviceService, hostService);
251 Device device = getMockDevice(true, DEVICE_ID);
252 IntProgrammable intProg = getMockIntProgrammable(false, false, false, true);
253 setUpDeviceTest(device, intProg, true, true);
254 IntObjective intObj = IntObjective.builder()
255 .withSelector(FLOW_SELECTOR1)
256 .build();
257 expect(intProg.addIntObjective(eq(intObj)))
258 .andReturn(true)
259 .once();
260 replay(deviceService, hostService, device, intProg);
261 installTestIntents();
262 assertTrue(manager.configDevice(DEVICE_ID));
263 verify(intProg);
264 }
265
266 /*
267 * Utilities
268 */
269 private void installTestIntents() {
270 // Pre-install an INT intent to the manager.
271 IntIntent.Builder intentBuilder = IntIntent.builder()
272 .withHeaderType(IntIntent.IntHeaderType.HOP_BY_HOP)
273 .withReportType(IntIntent.IntReportType.TRACKED_FLOW);
274
275 IntIntent postcardIntent = intentBuilder
276 .withTelemetryMode(IntIntent.TelemetryMode.POSTCARD)
277 .withSelector(FLOW_SELECTOR1)
278 .build();
279 IntIntent nonPoscardIntent = intentBuilder
280 .withTelemetryMode(IntIntent.TelemetryMode.INBAND_TELEMETRY)
281 .withSelector(FLOW_SELECTOR2)
282 .build();
283 manager.installIntIntent(nonPoscardIntent);
284 manager.installIntIntent(postcardIntent);
285 }
286
287 private void setUpDeviceTest(Device device, IntProgrammable intProg,
288 boolean hostConnected, boolean setupIntConfig) {
289 expect(device.as(IntProgrammable.class))
290 .andReturn(intProg)
291 .anyTimes();
292 expect(deviceService.getDevice(eq(DEVICE_ID)))
293 .andReturn(device)
294 .anyTimes();
295 expect(deviceService.getDevices())
296 .andReturn(ImmutableList.of(device))
297 .anyTimes();
298 if (setupIntConfig) {
299 IntDeviceConfig expectedConfig = createIntDeviceConfig();
300 expect(intProg.setupIntConfig(eq(expectedConfig)))
301 .andReturn(true)
302 .atLeastOnce();
303 }
304 expect(deviceService.getPorts(DEVICE_ID))
305 .andReturn(DEVICE_PORTS)
306 .anyTimes();
307
308 if (hostConnected) {
309 HOSTS.forEach((cp, host) -> {
310 expect(hostService.getConnectedHosts(eq(cp)))
311 .andReturn(ImmutableSet.of(host))
312 .anyTimes();
313 });
314 expect(hostService.getConnectedHosts(eq(DEVICE_ID)))
315 .andReturn(Sets.newHashSet(HOSTS.values()));
316 } else {
317 expect(hostService.getConnectedHosts(eq(DEVICE_ID)))
318 .andReturn(ImmutableSet.of())
319 .anyTimes();
320 }
321 }
322
323 private IntReportConfig getIntReportConfig(String fileName) throws IOException {
324 IntReportConfig config = new IntReportConfig();
325 InputStream jsonStream = getClass().getResourceAsStream(fileName);
326 ObjectMapper mapper = new ObjectMapper();
327 JsonNode jsonNode = mapper.readTree(jsonStream);
328 config.init(APP_ID, INT_REPORT_CONFIG_KEY, jsonNode, mapper, c -> {
329 });
330 return config;
331 }
332
333 private Device getMockDevice(boolean supportInt, DeviceId deviceId) {
334 Device device = createNiceMock(Device.class);
335 expect(device.is(IntProgrammable.class))
336 .andReturn(supportInt)
337 .anyTimes();
338 expect(device.id())
339 .andReturn(deviceId)
340 .anyTimes();
341 return device;
342 }
343
344 private IntProgrammable getMockIntProgrammable(boolean supportSource, boolean supportTransit, boolean supportSink,
345 boolean supportPostcard) {
346 IntProgrammable intProg = createNiceMock(IntProgrammable.class);
347 if (supportSource) {
348 expect(intProg.supportsFunctionality(SOURCE))
349 .andReturn(true).anyTimes();
350 }
351 if (supportTransit) {
352 expect(intProg.supportsFunctionality(TRANSIT))
353 .andReturn(true).anyTimes();
354 }
355 if (supportSink) {
356 expect(intProg.supportsFunctionality(SINK))
357 .andReturn(true).anyTimes();
358 }
359 if (supportPostcard) {
360 expect(intProg.supportsFunctionality(POSTCARD))
361 .andReturn(true).anyTimes();
362 }
363 expect(intProg.init())
364 .andReturn(true)
365 .anyTimes();
366 return intProg;
367 }
368
369 private IntDeviceConfig createIntDeviceConfig() {
370 return IntDeviceConfig.builder()
371 .withMinFlowHopLatencyChangeNs(MIN_FLOW_HOP_LATENCY_CHANGE_NS)
372 .withCollectorPort(COLLECTOR_PORT)
373 .withCollectorIp(COLLECTOR_IP)
374 .enabled(true)
375 .build();
Yi Tseng0f1ffd12020-09-18 11:10:47 -0700376 }
377}