blob: 15a4a7edb9a52646bcb65b77223f159dc2bbe4d8 [file] [log] [blame]
Andrea Campanellae4084402017-12-15 15:27:31 +01001/*
2 * Copyright 2018-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.t3.impl;
17
18import com.google.common.collect.ImmutableList;
19import com.google.common.collect.ImmutableSet;
pierventrefe57fda2020-08-04 22:52:02 +020020import com.google.common.collect.Lists;
Andrea Campanellae4084402017-12-15 15:27:31 +010021import org.junit.Before;
22import org.junit.Test;
Andrea Campanella17d45192018-01-18 17:11:42 +010023import org.onlab.packet.ChassisId;
Andrea Campanellae4084402017-12-15 15:27:31 +010024import org.onlab.packet.EthType;
25import org.onlab.packet.IpAddress;
26import org.onlab.packet.MacAddress;
27import org.onlab.packet.VlanId;
Andrea Campanella54923d62018-01-23 12:46:04 +010028import org.onosproject.cluster.NodeId;
pierventrefe57fda2020-08-04 22:52:02 +020029import org.onosproject.driver.pipeline.ofdpa.Ofdpa2Pipeline;
30import org.onosproject.driver.traceable.OfdpaPipelineTraceable;
31import org.onosproject.net.AbstractProjectableModel;
32import org.onosproject.net.AnnotationKeys;
Andrea Campanellae4084402017-12-15 15:27:31 +010033import org.onosproject.net.ConnectPoint;
pierventrefe57fda2020-08-04 22:52:02 +020034import org.onosproject.net.DataPlaneEntity;
Andrea Campanella17d45192018-01-18 17:11:42 +010035import org.onosproject.net.DefaultAnnotations;
36import org.onosproject.net.DefaultDevice;
Andrea Campanellae4084402017-12-15 15:27:31 +010037import org.onosproject.net.DefaultLink;
Andrea Campanella4c6170a2018-01-17 16:34:51 +010038import org.onosproject.net.DefaultPort;
Andrea Campanella17d45192018-01-18 17:11:42 +010039import org.onosproject.net.Device;
Andrea Campanellae4084402017-12-15 15:27:31 +010040import org.onosproject.net.DeviceId;
41import org.onosproject.net.Host;
42import org.onosproject.net.Link;
Andrea Campanella4c6170a2018-01-17 16:34:51 +010043import org.onosproject.net.Port;
Andrea Campanella94dfb9e2018-02-27 12:36:00 +010044import org.onosproject.net.PortNumber;
pierventrefe57fda2020-08-04 22:52:02 +020045import org.onosproject.net.SparseAnnotations;
46import org.onosproject.net.behaviour.PipelineTraceable;
47import org.onosproject.net.driver.Behaviour;
48import org.onosproject.net.driver.Driver;
49import org.onosproject.net.driver.DriverAdapter;
50import org.onosproject.net.driver.DriverHandler;
51import org.onosproject.net.driver.DriverService;
52import org.onosproject.net.driver.DriverServiceAdapter;
53import org.onosproject.net.driver.HandlerBehaviour;
Andrea Campanellae4084402017-12-15 15:27:31 +010054import org.onosproject.net.flow.FlowEntry;
Andrea Campanellae4084402017-12-15 15:27:31 +010055import org.onosproject.net.flow.TrafficSelector;
56import org.onosproject.net.flow.criteria.Criterion;
57import org.onosproject.net.flow.criteria.EthTypeCriterion;
58import org.onosproject.net.flow.criteria.VlanIdCriterion;
59import org.onosproject.net.group.Group;
Andrea Campanellae4084402017-12-15 15:27:31 +010060import org.onosproject.net.provider.ProviderId;
Andrea Campanella08d07e12018-03-07 14:27:54 -080061import org.onosproject.routeservice.ResolvedRoute;
Seyeon Jeong83e79862020-02-28 01:17:34 -080062import org.onosproject.t3.api.DeviceNib;
63import org.onosproject.t3.api.DriverNib;
64import org.onosproject.t3.api.EdgePortNib;
65import org.onosproject.t3.api.FlowNib;
66import org.onosproject.t3.api.GroupNib;
67import org.onosproject.t3.api.HostNib;
68import org.onosproject.t3.api.LinkNib;
69import org.onosproject.t3.api.MastershipNib;
70import org.onosproject.t3.api.RouteNib;
Andrea Campanellae4084402017-12-15 15:27:31 +010071import org.onosproject.t3.api.StaticPacketTrace;
72import org.slf4j.Logger;
73
pierventrefe57fda2020-08-04 22:52:02 +020074import java.util.List;
Andrea Campanella08d07e12018-03-07 14:27:54 -080075import java.util.Optional;
Andrea Campanellae4084402017-12-15 15:27:31 +010076import java.util.Set;
77
78import static org.junit.Assert.assertEquals;
79import static org.junit.Assert.assertNotNull;
80import static org.junit.Assert.assertNull;
81import static org.junit.Assert.assertTrue;
Andrea Campanella17d45192018-01-18 17:11:42 +010082import static org.onosproject.net.Device.Type.SWITCH;
Andrea Campanellae4084402017-12-15 15:27:31 +010083import static org.onosproject.t3.impl.T3TestObjects.*;
Andrea Campanella1445f7a2018-02-07 12:00:12 +010084import static org.onosproject.t3.impl.TroubleshootManager.PACKET_TO_CONTROLLER;
Andrea Campanellae4084402017-12-15 15:27:31 +010085import static org.slf4j.LoggerFactory.getLogger;
86
87/**
88 * Test Class for Troubleshoot Manager.
89 */
90public class TroubleshootManagerTest {
91
92 private static final Logger log = getLogger(TroubleshootManager.class);
Andrea Campanellae4084402017-12-15 15:27:31 +010093 private TroubleshootManager mngr;
pierventrefe57fda2020-08-04 22:52:02 +020094 private Driver baseDriver = new TestDriver();
Andrea Campanellae4084402017-12-15 15:27:31 +010095
96 @Before
97 public void setUp() throws Exception {
pierventrefe57fda2020-08-04 22:52:02 +020098 // Setup step for the device
99 DriverService testDeviceService = new TestDriverService();
100 AbstractProjectableModel.setDriverService(null, testDeviceService);
101
Andrea Campanellae4084402017-12-15 15:27:31 +0100102 mngr = new TroubleshootManager();
Seyeon Jeong83e79862020-02-28 01:17:34 -0800103
104 mngr.flowNib = new TestFlowRuleService();
105 mngr.groupNib = new TestGroupService();
106 mngr.hostNib = new TestHostService();
107 mngr.linkNib = new TestLinkService();
108 mngr.deviceNib = new TestDeviceService();
pierventrefe57fda2020-08-04 22:52:02 +0200109 mngr.driverNib = new TestDriverNib();
Seyeon Jeong83e79862020-02-28 01:17:34 -0800110 mngr.mastershipNib = new TestMastershipService();
111 mngr.edgePortNib = new TestEdgePortService();
112 mngr.routeNib = new TestRouteService();
Andrea Campanellae4084402017-12-15 15:27:31 +0100113
114 assertNotNull("Manager should not be null", mngr);
115
Seyeon Jeong83e79862020-02-28 01:17:34 -0800116 assertNotNull("Flow rule Service should not be null", mngr.flowNib);
117 assertNotNull("Group Service should not be null", mngr.groupNib);
118 assertNotNull("Host Service should not be null", mngr.hostNib);
119 assertNotNull("Link Service should not be null", mngr.linkNib);
120 assertNotNull("Device Service should not be null", mngr.deviceNib);
121 assertNotNull("Driver Service should not be null", mngr.driverNib);
122 assertNotNull("Mastership Service should not be null", mngr.driverNib);
123 assertNotNull("EdgePort Service should not be null", mngr.driverNib);
124 assertNotNull("Route Service should not be null", mngr.routeNib);
Andrea Campanella17d45192018-01-18 17:11:42 +0100125 }
126
127 /**
128 * Tests failure on non existent device.
129 */
130 @Test(expected = NullPointerException.class)
131 public void nonExistentDevice() {
132 StaticPacketTrace traceFail = mngr.trace(PACKET_OK, ConnectPoint.deviceConnectPoint("nonexistent" + "/1"));
pierventrefe57fda2020-08-04 22:52:02 +0200133 log.info("trace {}", traceFail.resultMessage());
Andrea Campanella17d45192018-01-18 17:11:42 +0100134 }
135
136 /**
137 * Tests failure on offline device.
138 */
139 @Test
140 public void offlineDevice() {
141 StaticPacketTrace traceFail = mngr.trace(PACKET_OK, ConnectPoint.deviceConnectPoint(OFFLINE_DEVICE + "/1"));
142 assertNotNull("Trace should not be null", traceFail);
pierventrefe57fda2020-08-04 22:52:02 +0200143 assertTrue("Device should be offline",
144 traceFail.resultMessage().contains("Device is offline"));
145 assertNull("Trace should have 0 output", traceFail.getHitChains(SINGLE_FLOW_DEVICE));
146 log.info("trace {}", traceFail.resultMessage());
Andrea Campanella7d3cf652018-01-22 15:10:30 +0100147 }
148
149 /**
150 * Tests failure on same output.
151 */
152 @Test
153 public void sameOutput() {
154 StaticPacketTrace traceFail = mngr.trace(PACKET_OK, SAME_OUTPUT_FLOW_CP);
155 assertNotNull("Trace should not be null", traceFail);
156 assertTrue("Trace should be unsuccessful",
157 traceFail.resultMessage().contains("is same as initial input"));
Andrea Campanella17d45192018-01-18 17:11:42 +0100158 log.info("trace {}", traceFail.resultMessage());
Andrea Campanellae4084402017-12-15 15:27:31 +0100159 }
160
Andrea Campanella54923d62018-01-23 12:46:04 +0100161 /**
162 * Tests ARP to controller.
163 */
164 @Test
165 public void arpToController() {
166 StaticPacketTrace traceSuccess = mngr.trace(PACKET_ARP, ARP_FLOW_CP);
167 assertNotNull("Trace should not be null", traceSuccess);
168 assertTrue("Trace should be successful",
Andrea Campanella1445f7a2018-02-07 12:00:12 +0100169 traceSuccess.resultMessage().contains(PACKET_TO_CONTROLLER));
Andrea Campanella54923d62018-01-23 12:46:04 +0100170 assertTrue("Master should be Master1",
171 traceSuccess.resultMessage().contains(MASTER_1));
pierventre4fd3b462020-10-15 17:31:44 +0200172 ConnectPoint connectPoint = traceSuccess.getHitChains(ARP_FLOW_DEVICE).get(0).outputPort();
Andrea Campanella54923d62018-01-23 12:46:04 +0100173 assertEquals("Packet Should go to CONTROLLER", PortNumber.CONTROLLER, connectPoint.port());
pierventrefe57fda2020-08-04 22:52:02 +0200174 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) traceSuccess.getHitChains(ARP_FLOW_DEVICE).get(0)
pierventre4fd3b462020-10-15 17:31:44 +0200175 .egressPacket().packet().getCriterion(Criterion.Type.VLAN_VID);
pierventrefe57fda2020-08-04 22:52:02 +0200176 assertEquals("VlanId should be None", VlanId.NONE, vlanIdCriterion.vlanId());
Andrea Campanella54923d62018-01-23 12:46:04 +0100177 log.info("trace {}", traceSuccess.resultMessage());
178 }
179
pierventrefe57fda2020-08-04 22:52:02 +0200180 /**
181 * Tests ARP to controller and Vlan id removal.
182 */
183 @Test
184 public void arpToControllerVlan() {
185 StaticPacketTrace traceSuccess = mngr.trace(PACKET_ARP, ARP_FLOW_VLAN_CP);
186 assertNotNull("Trace should not be null", traceSuccess);
187 assertTrue("Trace should be successful",
188 traceSuccess.resultMessage().contains(PACKET_TO_CONTROLLER));
189 assertTrue("Master should be Master1",
190 traceSuccess.resultMessage().contains(MASTER_1));
pierventre4fd3b462020-10-15 17:31:44 +0200191 ConnectPoint connectPoint = traceSuccess.getHitChains(ARP_FLOW_VLAN_DEVICE).get(0).outputPort();
pierventrefe57fda2020-08-04 22:52:02 +0200192 assertEquals("Packet Should go to CONTROLLER", PortNumber.CONTROLLER, connectPoint.port());
193 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) traceSuccess.getHitChains(ARP_FLOW_VLAN_DEVICE).get(0)
pierventre4fd3b462020-10-15 17:31:44 +0200194 .egressPacket().packet().getCriterion(Criterion.Type.VLAN_VID);
pierventrefe57fda2020-08-04 22:52:02 +0200195 assertEquals("VlanId should be None", VlanId.NONE, vlanIdCriterion.vlanId());
196 log.info("trace {}", traceSuccess.resultMessage());
197 }
Andrea Campanella7d3cf652018-01-22 15:10:30 +0100198
Andrea Campanellae4084402017-12-15 15:27:31 +0100199 /**
Andrea Campanella4401bd72018-01-18 16:54:34 +0100200 * Tests failure on device with no flows.
Andrea Campanellae4084402017-12-15 15:27:31 +0100201 */
202 @Test
203 public void noFlows() {
204 StaticPacketTrace traceFail = mngr.trace(PACKET_OK, ConnectPoint.deviceConnectPoint("test/1"));
205 assertNotNull("Trace should not be null", traceFail);
pierventrefe57fda2020-08-04 22:52:02 +0200206 assertNull("Trace should have 0 output", traceFail.getHitChains(SINGLE_FLOW_DEVICE));
Andrea Campanellae4084402017-12-15 15:27:31 +0100207 log.info("trace {}", traceFail.resultMessage());
208 }
209
210 /**
Andrea Campanella94dfb9e2018-02-27 12:36:00 +0100211 * Test group with no buckets.
212 */
213 @Test
pierventrefe57fda2020-08-04 22:52:02 +0200214 public void noBucketsTest() {
Andrea Campanella94dfb9e2018-02-27 12:36:00 +0100215 StaticPacketTrace traceFail = mngr.trace(PACKET_OK, NO_BUCKET_CP);
216 assertNotNull("Trace should not be null", traceFail);
217 assertTrue("Trace should be unsuccessful",
218 traceFail.resultMessage().contains("no buckets"));
219 log.info("trace {}", traceFail.resultMessage());
Andrea Campanella94dfb9e2018-02-27 12:36:00 +0100220 }
221
222 /**
Andrea Campanellae4084402017-12-15 15:27:31 +0100223 * Test a single flow rule that has output port in it.
224 */
225 @Test
226 public void testSingleFlowRule() {
pierventrefe57fda2020-08-04 22:52:02 +0200227 // Happy ending
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100228 testSuccess(PACKET_OK, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE, SINGLE_FLOW_OUT_CP, 1, 1);
pierventrefe57fda2020-08-04 22:52:02 +0200229 // Failure scenario
230 testFailure(PACKET_FAIL, SINGLE_FLOW_IN_CP, SINGLE_FLOW_DEVICE, 1);
Andrea Campanellae4084402017-12-15 15:27:31 +0100231 }
232
233 /**
234 * Tests two flow rule the last one of which has output port in it.
235 */
236 @Test
237 public void testDualFlowRule() {
pierventrefe57fda2020-08-04 22:52:02 +0200238 // Test Success
Andrea Campanella4401bd72018-01-18 16:54:34 +0100239 StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, DUAL_FLOW_IN_CP, DUAL_FLOW_DEVICE,
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100240 DUAL_FLOW_OUT_CP, 1, 1);
pierventrefe57fda2020-08-04 22:52:02 +0200241 // Verifying Vlan
242 Criterion criterion = traceSuccess.getHitChains(DUAL_FLOW_DEVICE).get(0).
pierventre4fd3b462020-10-15 17:31:44 +0200243 egressPacket().packet().getCriterion(Criterion.Type.VLAN_VID);
Andrea Campanellae4084402017-12-15 15:27:31 +0100244 assertNotNull("Packet Should have Vlan", criterion);
Andrea Campanellae4084402017-12-15 15:27:31 +0100245 VlanIdCriterion vlanIdCriterion = (VlanIdCriterion) criterion;
Andrea Campanellae4084402017-12-15 15:27:31 +0100246 assertEquals("Vlan should be 100", VlanId.vlanId((short) 100), vlanIdCriterion.vlanId());
247
pierventrefe57fda2020-08-04 22:52:02 +0200248 // Test Failure
249 testFailure(PACKET_FAIL, DUAL_FLOW_IN_CP, DUAL_FLOW_DEVICE, 1);
Andrea Campanellae4084402017-12-15 15:27:31 +0100250 }
251
252 /**
253 * Test a single flow rule that points to a group with output port in it.
254 */
255 @Test
pierventrefe57fda2020-08-04 22:52:02 +0200256 public void flowAndGroup() {
257 // Test Success
Andrea Campanella4401bd72018-01-18 16:54:34 +0100258 StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, GROUP_FLOW_IN_CP, GROUP_FLOW_DEVICE,
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100259 GROUP_FLOW_OUT_CP, 1, 1);
pierventrefe57fda2020-08-04 22:52:02 +0200260 // Verify the output of the test
261 assertTrue("Wrong Output Group", traceSuccess.getHitChains(GROUP_FLOW_DEVICE)
pierventre4fd3b462020-10-15 17:31:44 +0200262 .get(0).hitChain().contains(new DataPlaneEntity(GROUP)));
Andrea Campanella3970e472018-01-25 16:44:04 +0100263 assertEquals("Packet should not have MPLS Label", EthType.EtherType.IPV4.ethType(),
pierventre4fd3b462020-10-15 17:31:44 +0200264 ((EthTypeCriterion) traceSuccess.getHitChains(GROUP_FLOW_DEVICE).get(0)
265 .egressPacket().packet().getCriterion(Criterion.Type.ETH_TYPE)).ethType());
266 assertNull("Packet should not have MPLS Label", traceSuccess.getHitChains(GROUP_FLOW_DEVICE).get(0)
267 .egressPacket().packet().getCriterion(Criterion.Type.MPLS_LABEL));
268 assertNull("Packet should not have MPLS BoS", traceSuccess.getHitChains(GROUP_FLOW_DEVICE).get(0)
269 .egressPacket().packet().getCriterion(Criterion.Type.MPLS_BOS));
Seyeon Jeonga9745512020-04-07 12:06:18 -0700270 }
271
272 /**
Andrea Campanellae4084402017-12-15 15:27:31 +0100273 * Test path through a 3 device topology.
274 */
275 @Test
pierventrefe57fda2020-08-04 22:52:02 +0200276 public void singlePathTopology() {
277 // Test success
Andrea Campanellae4084402017-12-15 15:27:31 +0100278 StaticPacketTrace traceSuccess = testSuccess(PACKET_OK_TOPO, TOPO_FLOW_1_IN_CP,
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100279 TOPO_FLOW_3_DEVICE, TOPO_FLOW_3_OUT_CP, 1, 1);
pierventrefe57fda2020-08-04 22:52:02 +0200280 // Verify that the complete path contains all the traversed connect points
281 List<ConnectPoint> path = Lists.newArrayList(TOPO_FLOW_1_IN_CP, TOPO_FLOW_1_OUT_CP,
282 TOPO_FLOW_2_IN_CP, TOPO_FLOW_2_OUT_CP, TOPO_FLOW_3_IN_CP, TOPO_FLOW_3_OUT_CP);
283 assertEquals(path, traceSuccess.getCompletePaths().get(0));
Andrea Campanellae4084402017-12-15 15:27:31 +0100284 }
285
286 /**
287 * Test path through a 4 device topology with first device that has groups with multiple output buckets.
288 */
289 @Test
pierventrefe57fda2020-08-04 22:52:02 +0200290 public void testGroupTopo() {
291 // Test success
Andrea Campanellae4084402017-12-15 15:27:31 +0100292 StaticPacketTrace traceSuccess = testSuccess(PACKET_OK_TOPO, TOPO_FLOW_IN_CP,
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100293 TOPO_FLOW_3_DEVICE, TOPO_FLOW_3_OUT_CP, 2, 1);
pierventrefe57fda2020-08-04 22:52:02 +0200294 // Verify the multiple output actions
Andrea Campanellae4084402017-12-15 15:27:31 +0100295 assertTrue("Incorrect groups",
pierventre4fd3b462020-10-15 17:31:44 +0200296 traceSuccess.getHitChains(TOPO_GROUP_FLOW_DEVICE).get(0).hitChain()
pierventrefe57fda2020-08-04 22:52:02 +0200297 .contains(new DataPlaneEntity(TOPO_GROUP)));
Andrea Campanellae4084402017-12-15 15:27:31 +0100298 assertTrue("Incorrect bucket",
pierventre4fd3b462020-10-15 17:31:44 +0200299 traceSuccess.getHitChains(TOPO_GROUP_FLOW_DEVICE).get(1).hitChain()
pierventrefe57fda2020-08-04 22:52:02 +0200300 .contains(new DataPlaneEntity(TOPO_GROUP)));
Andrea Campanella94c594a2018-02-06 18:58:40 +0100301 }
302
303 /**
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100304 * Test dual links between 3 topology elements.
305 */
306 @Test
pierventrefe57fda2020-08-04 22:52:02 +0200307 public void dualLinks() {
308 // Success
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100309 StaticPacketTrace traceSuccess = testSuccess(PACKET_OK, DUAL_LINK_1_CP_1_IN,
310 DUAL_LINK_3, DUAL_LINK_3_CP_3_OUT, 4, 1);
pierventrefe57fda2020-08-04 22:52:02 +0200311 // Verify that the complete path contains all the traversed connect points
312 List<ConnectPoint> path = Lists.newArrayList(DUAL_LINK_1_CP_1_IN, DUAL_LINK_1_CP_2_OUT,
313 DUAL_LINK_2_CP_1_IN, DUAL_LINK_2_CP_2_OUT, DUAL_LINK_3_CP_1_IN, DUAL_LINK_3_CP_3_OUT);
314 assertTrue(traceSuccess.getCompletePaths().contains(path));
315 path = Lists.newArrayList(DUAL_LINK_1_CP_1_IN, DUAL_LINK_1_CP_2_OUT,
316 DUAL_LINK_2_CP_1_IN, DUAL_LINK_2_CP_3_OUT, DUAL_LINK_3_CP_2_IN, DUAL_LINK_3_CP_3_OUT);
317 assertTrue(traceSuccess.getCompletePaths().contains(path));
318 path = Lists.newArrayList(DUAL_LINK_1_CP_1_IN, DUAL_LINK_1_CP_3_OUT,
319 DUAL_LINK_2_CP_4_IN, DUAL_LINK_2_CP_2_OUT, DUAL_LINK_3_CP_1_IN, DUAL_LINK_3_CP_3_OUT);
320 assertTrue(traceSuccess.getCompletePaths().contains(path));
321 path = Lists.newArrayList(DUAL_LINK_1_CP_1_IN, DUAL_LINK_1_CP_3_OUT,
322 DUAL_LINK_2_CP_4_IN, DUAL_LINK_2_CP_3_OUT, DUAL_LINK_3_CP_2_IN, DUAL_LINK_3_CP_3_OUT);
323 assertTrue(traceSuccess.getCompletePaths().contains(path));
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100324 }
325
Andrea Campanella8292ba62018-01-31 16:43:23 +0100326 /**
Andrea Campanella1445f7a2018-02-07 12:00:12 +0100327 * Test LLDP output to controller.
328 */
329 @Test
330 public void lldpToController() {
331 StaticPacketTrace traceSuccess = mngr.trace(PACKET_LLDP, LLDP_FLOW_CP);
332 assertNotNull("Trace should not be null", traceSuccess);
333 assertTrue("Trace should be successful",
334 traceSuccess.resultMessage().contains("Packet goes to the controller"));
335 assertTrue("Master should be Master1",
336 traceSuccess.resultMessage().contains(MASTER_1));
pierventre4fd3b462020-10-15 17:31:44 +0200337 ConnectPoint connectPoint = traceSuccess.getHitChains(LLDP_FLOW_DEVICE).get(0).outputPort();
Andrea Campanella1445f7a2018-02-07 12:00:12 +0100338 assertEquals("Packet Should go to CONTROLLER", PortNumber.CONTROLLER, connectPoint.port());
339 log.info("trace {}", traceSuccess.resultMessage());
340 }
341
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100342 /**
343 * Test multicast in single device.
344 */
345 @Test
pierventrefe57fda2020-08-04 22:52:02 +0200346 public void multicastTest() {
347 // Test success
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100348 StaticPacketTrace traceSuccess = mngr.trace(PACKET_OK_MULTICAST, MULTICAST_IN_CP);
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100349 log.info("trace {}", traceSuccess);
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100350 log.info("trace {}", traceSuccess.resultMessage());
351
pierventrefe57fda2020-08-04 22:52:02 +0200352 // Verify some conditions on the test
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100353 assertNotNull("trace should not be null", traceSuccess);
pierventrefe57fda2020-08-04 22:52:02 +0200354 assertEquals("Trace should have " + 2 + " hitchains", 2,
355 traceSuccess.getHitChains(MULTICAST_GROUP_FLOW_DEVICE).size());
356 assertEquals("Trace should only have " + 2 + "paths", 2,
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100357 traceSuccess.getCompletePaths().size());
358 assertTrue("Trace should be successful",
359 traceSuccess.resultMessage().contains("reached output"));
360 assertEquals("Incorrect Output CP", MULTICAST_OUT_CP_2,
pierventre4fd3b462020-10-15 17:31:44 +0200361 traceSuccess.getHitChains(MULTICAST_GROUP_FLOW_DEVICE).get(0).outputPort());
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100362 assertEquals("Incorrect Output CP", MULTICAST_OUT_CP,
pierventre4fd3b462020-10-15 17:31:44 +0200363 traceSuccess.getHitChains(MULTICAST_GROUP_FLOW_DEVICE).get(1).outputPort());
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100364 }
365
Andrea Campanella4906ba72018-03-01 16:22:21 +0100366 /**
367 * Tests dual homing of a host.
368 */
369 @Test
pierventrefe57fda2020-08-04 22:52:02 +0200370 public void dualhomedTest() {
371 // Test success
Andrea Campanella4906ba72018-03-01 16:22:21 +0100372 StaticPacketTrace traceSuccess = mngr.trace(PACKET_DUAL_HOME, DUAL_HOME_CP_1_1);
pierventrefe57fda2020-08-04 22:52:02 +0200373 log.info("trace {}", traceSuccess);
374 log.info("trace {}", traceSuccess.resultMessage());
Andrea Campanella4906ba72018-03-01 16:22:21 +0100375
pierventrefe57fda2020-08-04 22:52:02 +0200376 // Verify paths
Andrea Campanella4906ba72018-03-01 16:22:21 +0100377 assertNotNull("trace should not be null", traceSuccess);
pierventrefe57fda2020-08-04 22:52:02 +0200378 assertEquals("Should have 2 output paths", 2, traceSuccess.getCompletePaths().size());
Andrea Campanella4906ba72018-03-01 16:22:21 +0100379 assertTrue("Should contain proper path", traceSuccess.getCompletePaths()
380 .contains(ImmutableList.of(DUAL_HOME_CP_1_1, DUAL_HOME_CP_1_2, DUAL_HOME_CP_2_1, DUAL_HOME_CP_2_2)));
381 assertTrue("Should contain proper path", traceSuccess.getCompletePaths()
382 .contains(ImmutableList.of(DUAL_HOME_CP_1_1, DUAL_HOME_CP_1_3, DUAL_HOME_CP_3_1, DUAL_HOME_CP_3_2)));
383
384 }
385
pierventrefe57fda2020-08-04 22:52:02 +0200386 private StaticPacketTrace testSuccess(TrafficSelector packet, ConnectPoint in, DeviceId deviceId,
387 ConnectPoint out, int paths, int hitchains) {
Andrea Campanellae4084402017-12-15 15:27:31 +0100388 StaticPacketTrace traceSuccess = mngr.trace(packet, in);
Andrea Campanellae4084402017-12-15 15:27:31 +0100389 log.info("trace {}", traceSuccess);
Andrea Campanellae4084402017-12-15 15:27:31 +0100390 log.info("trace {}", traceSuccess.resultMessage());
391
392 assertNotNull("trace should not be null", traceSuccess);
pierventrefe57fda2020-08-04 22:52:02 +0200393 assertEquals("Trace should have " + hitchains + " hitchains", hitchains,
394 traceSuccess.getHitChains(deviceId).size());
Andrea Campanellae4084402017-12-15 15:27:31 +0100395 assertEquals("Trace should only have " + paths + "output", paths, traceSuccess.getCompletePaths().size());
396 assertTrue("Trace should be successful",
397 traceSuccess.resultMessage().contains("Reached required destination Host"));
398 assertEquals("Incorrect Output CP", out,
pierventre4fd3b462020-10-15 17:31:44 +0200399 traceSuccess.getHitChains(deviceId).get(0).outputPort());
Andrea Campanellae4084402017-12-15 15:27:31 +0100400
401 return traceSuccess;
402 }
403
pierventrefe57fda2020-08-04 22:52:02 +0200404 private void testFailure(TrafficSelector packet, ConnectPoint in, DeviceId deviceId,
405 int hitchains) {
Andrea Campanellae4084402017-12-15 15:27:31 +0100406 StaticPacketTrace traceFail = mngr.trace(packet, in);
Andrea Campanellae4084402017-12-15 15:27:31 +0100407 log.info("trace {}", traceFail.resultMessage());
408
409 assertNotNull("Trace should not be null", traceFail);
pierventrefe57fda2020-08-04 22:52:02 +0200410 assertEquals("Trace should have " + hitchains + " hitchains", hitchains,
411 traceFail.getHitChains(deviceId).size());
Andrea Campanellae4084402017-12-15 15:27:31 +0100412 }
413
pierventrefe57fda2020-08-04 22:52:02 +0200414 private static class TestFlowRuleService extends FlowNib {
415
Andrea Campanellae4084402017-12-15 15:27:31 +0100416 @Override
Andrea Campanella39ec33e2018-04-13 12:14:48 +0200417 public Iterable<FlowEntry> getFlowEntriesByState(DeviceId deviceId, FlowEntry.FlowEntryState state) {
Andrea Campanellae4084402017-12-15 15:27:31 +0100418 if (deviceId.equals(SINGLE_FLOW_DEVICE)) {
419 return ImmutableList.of(SINGLE_FLOW_ENTRY);
420 } else if (deviceId.equals(DUAL_FLOW_DEVICE)) {
421 return ImmutableList.of(FIRST_FLOW_ENTRY, SECOND_FLOW_ENTRY);
422 } else if (deviceId.equals(GROUP_FLOW_DEVICE)) {
423 return ImmutableList.of(GROUP_FLOW_ENTRY);
424 } else if (deviceId.equals(TOPO_FLOW_DEVICE) ||
425 deviceId.equals(TOPO_FLOW_2_DEVICE) ||
426 deviceId.equals(TOPO_FLOW_3_DEVICE) ||
427 deviceId.equals(TOPO_FLOW_4_DEVICE)) {
428 return ImmutableList.of(TOPO_SINGLE_FLOW_ENTRY, TOPO_SECOND_INPUT_FLOW_ENTRY);
429 } else if (deviceId.equals(TOPO_GROUP_FLOW_DEVICE)) {
430 return ImmutableList.of(TOPO_GROUP_FLOW_ENTRY);
Andrea Campanella7d3cf652018-01-22 15:10:30 +0100431 } else if (deviceId.equals(SAME_OUTPUT_FLOW_DEVICE)) {
432 return ImmutableList.of(SAME_OUTPUT_FLOW_ENTRY);
Andrea Campanella54923d62018-01-23 12:46:04 +0100433 } else if (deviceId.equals(ARP_FLOW_DEVICE)) {
pierventrefe57fda2020-08-04 22:52:02 +0200434 return ImmutableList.of(ARP_FLOW_ENTRY);
435 } else if (deviceId.equals(ARP_FLOW_VLAN_DEVICE)) {
436 return ImmutableList.of(ARP_FLOW_VLAN_ENTRY, ARP_FLOW_ENTRY);
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100437 } else if (deviceId.equals(DUAL_LINK_1)) {
438 return ImmutableList.of(DUAL_LINK_1_GROUP_FLOW_ENTRY);
439 } else if (deviceId.equals(DUAL_LINK_2)) {
440 return ImmutableList.of(DUAL_LINK_1_GROUP_FLOW_ENTRY, DUAL_LINK_2_GROUP_FLOW_ENTRY);
441 } else if (deviceId.equals(DUAL_LINK_3)) {
442 return ImmutableList.of(DUAL_LINK_3_FLOW_ENTRY, DUAL_LINK_3_FLOW_ENTRY_2);
Andrea Campanella1445f7a2018-02-07 12:00:12 +0100443 } else if (deviceId.equals(LLDP_FLOW_DEVICE)) {
444 return ImmutableList.of(LLDP_FLOW_ENTRY);
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100445 } else if (deviceId.equals(MULTICAST_GROUP_FLOW_DEVICE)) {
446 return ImmutableList.of(MULTICAST_GROUP_FLOW_ENTRY);
Andrea Campanella94dfb9e2018-02-27 12:36:00 +0100447 } else if (deviceId.equals(NO_BUCKET_DEVICE)) {
448 return ImmutableList.of(NO_BUCKET_ENTRY);
Andrea Campanella4906ba72018-03-01 16:22:21 +0100449 } else if (deviceId.equals(DUAL_HOME_DEVICE_1)) {
450 return ImmutableList.of(DUAL_HOME_FLOW_ENTRY);
451 } else if (deviceId.equals(DUAL_HOME_DEVICE_2) || deviceId.equals(DUAL_HOME_DEVICE_3)) {
452 return ImmutableList.of(DUAL_HOME_OUT_FLOW_ENTRY);
Andrea Campanellae4084402017-12-15 15:27:31 +0100453 }
454 return ImmutableList.of();
455 }
456 }
457
pierventrefe57fda2020-08-04 22:52:02 +0200458 private static class TestGroupService extends GroupNib {
459
Andrea Campanellae4084402017-12-15 15:27:31 +0100460 @Override
pierventrefe57fda2020-08-04 22:52:02 +0200461 public Iterable<Group> getGroupsByState(DeviceId deviceId, Group.GroupState groupState) {
Andrea Campanellae4084402017-12-15 15:27:31 +0100462 if (deviceId.equals(GROUP_FLOW_DEVICE)) {
463 return ImmutableList.of(GROUP);
464 } else if (deviceId.equals(TOPO_GROUP_FLOW_DEVICE)) {
465 return ImmutableList.of(TOPO_GROUP);
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100466 } else if (deviceId.equals(DUAL_LINK_1) || deviceId.equals(DUAL_LINK_2)) {
467 return ImmutableList.of(DUAL_LINK_GROUP);
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100468 } else if (deviceId.equals(MULTICAST_GROUP_FLOW_DEVICE)) {
469 return ImmutableList.of(MULTICAST_GROUP);
Andrea Campanella94dfb9e2018-02-27 12:36:00 +0100470 } else if (deviceId.equals(NO_BUCKET_DEVICE)) {
471 return ImmutableList.of(NO_BUCKET_GROUP);
Andrea Campanella4906ba72018-03-01 16:22:21 +0100472 } else if (deviceId.equals(DUAL_HOME_DEVICE_1)) {
473 return ImmutableList.of(DUAL_HOME_GROUP);
Andrea Campanellae4084402017-12-15 15:27:31 +0100474 }
475 return ImmutableList.of();
476 }
477 }
478
pierventrefe57fda2020-08-04 22:52:02 +0200479 private static class TestHostService extends HostNib {
Andrea Campanellae4084402017-12-15 15:27:31 +0100480 @Override
481 public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
482 if (connectPoint.equals(TOPO_FLOW_3_OUT_CP)) {
483 return ImmutableSet.of(H2);
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100484 } else if (connectPoint.equals(DUAL_LINK_1_CP_2_OUT) || connectPoint.equals(DUAL_LINK_1_CP_3_OUT) ||
485 connectPoint.equals(DUAL_LINK_2_CP_2_OUT) || connectPoint.equals(DUAL_LINK_2_CP_3_OUT)) {
486 return ImmutableSet.of();
Andrea Campanellae4084402017-12-15 15:27:31 +0100487 }
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100488 if (connectPoint.equals(SINGLE_FLOW_OUT_CP) ||
489 connectPoint.equals(DUAL_FLOW_OUT_CP) ||
490 connectPoint.equals(GROUP_FLOW_OUT_CP) ||
pierventrefe57fda2020-08-04 22:52:02 +0200491 connectPoint.equals(DUAL_LINK_3_CP_3_OUT)) {
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100492 return ImmutableSet.of(H1);
493 }
Andrea Campanella4906ba72018-03-01 16:22:21 +0100494 if (connectPoint.equals(DUAL_HOME_CP_2_2) || connectPoint.equals(DUAL_HOME_CP_3_2)) {
495 return ImmutableSet.of(DUAL_HOME_H);
496 }
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100497 return ImmutableSet.of();
Andrea Campanellae4084402017-12-15 15:27:31 +0100498 }
499
500 @Override
501 public Set<Host> getHostsByMac(MacAddress mac) {
502 if (mac.equals(H1.mac())) {
503 return ImmutableSet.of(H1);
504 } else if (mac.equals(H2.mac())) {
505 return ImmutableSet.of(H2);
Andrea Campanella4906ba72018-03-01 16:22:21 +0100506 } else if (mac.equals(DUAL_HOME_H.mac())) {
507 return ImmutableSet.of(DUAL_HOME_H);
Andrea Campanellae4084402017-12-15 15:27:31 +0100508 }
509 return ImmutableSet.of();
510 }
511
512 @Override
513 public Set<Host> getHostsByIp(IpAddress ip) {
514 if ((H1.ipAddresses().contains(ip))) {
515 return ImmutableSet.of(H1);
516 } else if ((H2.ipAddresses().contains(ip))) {
517 return ImmutableSet.of(H2);
Andrea Campanella4906ba72018-03-01 16:22:21 +0100518 } else if ((DUAL_HOME_H.ipAddresses().contains(ip))) {
519 return ImmutableSet.of(DUAL_HOME_H);
Andrea Campanellae4084402017-12-15 15:27:31 +0100520 }
521 return ImmutableSet.of();
522 }
523 }
524
pierventrefe57fda2020-08-04 22:52:02 +0200525 private static class TestLinkService extends LinkNib {
Andrea Campanellae4084402017-12-15 15:27:31 +0100526 @Override
527 public Set<Link> getEgressLinks(ConnectPoint connectPoint) {
528 if (connectPoint.equals(TOPO_FLOW_1_OUT_CP)
529 || connectPoint.equals(TOPO_FLOW_OUT_CP_1)) {
530 return ImmutableSet.of(DefaultLink.builder()
531 .providerId(ProviderId.NONE)
532 .type(Link.Type.DIRECT)
533 .src(connectPoint)
534 .dst(TOPO_FLOW_2_IN_CP)
535 .build());
536 } else if (connectPoint.equals(TOPO_FLOW_2_OUT_CP)) {
537 return ImmutableSet.of(DefaultLink.builder()
538 .providerId(ProviderId.NONE)
539 .type(Link.Type.DIRECT)
540 .src(TOPO_FLOW_2_OUT_CP)
541 .dst(TOPO_FLOW_3_IN_CP)
542 .build());
543 } else if (connectPoint.equals(TOPO_FLOW_OUT_CP_2)) {
544 return ImmutableSet.of(DefaultLink.builder()
545 .providerId(ProviderId.NONE)
546 .type(Link.Type.DIRECT)
547 .src(TOPO_FLOW_OUT_CP_2)
548 .dst(TOPO_FLOW_4_IN_CP)
549 .build());
550 } else if (connectPoint.equals(TOPO_FLOW_4_OUT_CP)) {
551 return ImmutableSet.of(DefaultLink.builder()
552 .providerId(ProviderId.NONE)
553 .type(Link.Type.DIRECT)
554 .src(TOPO_FLOW_4_OUT_CP)
555 .dst(TOPO_FLOW_3_IN_2_CP)
556 .build());
Andrea Campanellab022b5e2018-01-31 14:59:03 +0100557 } else if (connectPoint.equals(DUAL_LINK_1_CP_2_OUT)) {
558 return ImmutableSet.of(DefaultLink.builder()
559 .providerId(ProviderId.NONE)
560 .type(Link.Type.DIRECT)
561 .src(DUAL_LINK_1_CP_2_OUT)
562 .dst(DUAL_LINK_2_CP_1_IN)
563 .build());
564 } else if (connectPoint.equals(DUAL_LINK_1_CP_3_OUT)) {
565 return ImmutableSet.of(DefaultLink.builder()
566 .providerId(ProviderId.NONE)
567 .type(Link.Type.DIRECT)
568 .src(DUAL_LINK_1_CP_3_OUT)
569 .dst(DUAL_LINK_2_CP_4_IN)
570 .build());
571 } else if (connectPoint.equals(DUAL_LINK_2_CP_2_OUT)) {
572 return ImmutableSet.of(DefaultLink.builder()
573 .providerId(ProviderId.NONE)
574 .type(Link.Type.DIRECT)
575 .src(DUAL_LINK_2_CP_2_OUT)
576 .dst(DUAL_LINK_3_CP_1_IN)
577 .build());
578 } else if (connectPoint.equals(DUAL_LINK_2_CP_3_OUT)) {
579 return ImmutableSet.of(DefaultLink.builder()
580 .providerId(ProviderId.NONE)
581 .type(Link.Type.DIRECT)
582 .src(DUAL_LINK_2_CP_3_OUT)
583 .dst(DUAL_LINK_3_CP_2_IN)
584 .build());
Andrea Campanella4906ba72018-03-01 16:22:21 +0100585 } else if (connectPoint.equals(DUAL_HOME_CP_1_2)) {
586 return ImmutableSet.of(DefaultLink.builder()
587 .providerId(ProviderId.NONE)
588 .type(Link.Type.DIRECT)
589 .src(DUAL_HOME_CP_1_2)
590 .dst(DUAL_HOME_CP_2_1)
591 .build());
592 } else if (connectPoint.equals(DUAL_HOME_CP_1_3)) {
593 return ImmutableSet.of(DefaultLink.builder()
594 .providerId(ProviderId.NONE)
595 .type(Link.Type.DIRECT)
596 .src(DUAL_HOME_CP_1_3)
597 .dst(DUAL_HOME_CP_3_1)
598 .build());
Andrea Campanellae4084402017-12-15 15:27:31 +0100599 }
600 return ImmutableSet.of();
601 }
602 }
Andrea Campanella17d45192018-01-18 17:11:42 +0100603
pierventrefe57fda2020-08-04 22:52:02 +0200604 private static class TestDeviceService extends DeviceNib {
Andrea Campanella17d45192018-01-18 17:11:42 +0100605 @Override
606 public Device getDevice(DeviceId deviceId) {
607 if (deviceId.equals(DeviceId.deviceId("nonexistent"))) {
608 return null;
609 }
pierventrefe57fda2020-08-04 22:52:02 +0200610 SparseAnnotations annotations = DefaultAnnotations.builder()
611 .set("foo", "bar")
612 .set(AnnotationKeys.DRIVER, OFDPA_DRIVER)
613 .build();
614 return new DefaultDevice(ProviderId.NONE, deviceId, SWITCH,
615 MANUFACTURER, HW_VERSION, SW_VERSION, SERIAL_NUMBER, new ChassisId(),
616 annotations);
Andrea Campanella17d45192018-01-18 17:11:42 +0100617 }
618
619 @Override
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100620 public Port getPort(ConnectPoint cp) {
621 return new DefaultPort(null, cp.port(), true, DefaultAnnotations.builder().build());
622 }
623
624 @Override
Andrea Campanella17d45192018-01-18 17:11:42 +0100625 public boolean isAvailable(DeviceId deviceId) {
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100626 return !deviceId.equals(OFFLINE_DEVICE);
627 }
628 }
629
pierventrefe57fda2020-08-04 22:52:02 +0200630 private static class TestDriverNib extends DriverNib {
Seyeon Jeong83e79862020-02-28 01:17:34 -0800631 @Override
632 public String getDriverName(DeviceId deviceId) {
Seyeon Jeong83e79862020-02-28 01:17:34 -0800633 return "NotHWDriver";
634 }
635 }
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100636
pierventrefe57fda2020-08-04 22:52:02 +0200637 private static class TestMastershipService extends MastershipNib {
Seyeon Jeong83e79862020-02-28 01:17:34 -0800638 @Override
639 public NodeId getMasterFor(DeviceId deviceId) {
640 return NodeId.nodeId(MASTER_1);
641 }
642 }
643
pierventrefe57fda2020-08-04 22:52:02 +0200644 private static class TestEdgePortService extends EdgePortNib {
Andrea Campanella4c6170a2018-01-17 16:34:51 +0100645 @Override
646 public boolean isEdgePoint(ConnectPoint point) {
647 return point.equals(MULTICAST_OUT_CP) ||
648 point.equals(MULTICAST_OUT_CP_2);
Andrea Campanella17d45192018-01-18 17:11:42 +0100649 }
650 }
Andrea Campanella54923d62018-01-23 12:46:04 +0100651
pierventrefe57fda2020-08-04 22:52:02 +0200652 private static class TestRouteService extends RouteNib {
Andrea Campanella08d07e12018-03-07 14:27:54 -0800653 @Override
654 public Optional<ResolvedRoute> longestPrefixLookup(IpAddress ip) {
655 return Optional.empty();
656 }
657 }
658
pierventrefe57fda2020-08-04 22:52:02 +0200659 private class TestDriverService extends DriverServiceAdapter {
660 @Override
661 public Driver getDriver(DeviceId deviceId) {
662 return baseDriver;
663 }
664 }
665
666 private static class TestDriver extends DriverAdapter {
667
668 @Override
669 public String manufacturer() {
670 return MANUFACTURER;
671 }
672
673 @Override
674 public String hwVersion() {
675 return HW_VERSION;
676 }
677
678 @Override
679 public String swVersion() {
680 return SW_VERSION;
681 }
682
683 @Override
684 public String name() {
685 return OFDPA_DRIVER;
686 }
687
688 @Override
689 @SuppressWarnings("unchecked")
690 public <T extends Behaviour> T createBehaviour(DriverHandler handler, Class<T> behaviourClass) {
691 if (behaviourClass == PipelineTraceable.class) {
692 T behaviour = (T) new OfdpaPipelineTraceable();
693 behaviour.setData(handler.data());
694 ((HandlerBehaviour) behaviour).setHandler(handler);
695 return behaviour;
696 } else {
697 T behaviour = (T) new Ofdpa2Pipeline();
698 behaviour.setData(handler.data());
699 ((HandlerBehaviour) behaviour).setHandler(handler);
700 return behaviour;
701 }
702 }
703
704 }
705
Andrea Campanellae4084402017-12-15 15:27:31 +0100706}