2 * Copyright 2014-2015 Open Networking Laboratory
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org.onosproject.provider.lldp.impl;
18 import com.google.common.collect.ArrayListMultimap;
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.Lists;
21 import com.google.common.collect.Maps;
22 import org.junit.After;
23 import org.junit.Before;
24 import org.junit.Test;
25 import org.onlab.packet.ChassisId;
26 import org.onlab.packet.Ethernet;
27 import org.onlab.packet.ONOSLLDP;
28 import org.onosproject.cfg.ComponentConfigAdapter;
29 import org.onosproject.cluster.NodeId;
30 import org.onosproject.cluster.RoleInfo;
31 import org.onosproject.core.ApplicationId;
32 import org.onosproject.core.CoreService;
33 import org.onosproject.core.DefaultApplicationId;
34 import org.onosproject.mastership.MastershipListener;
35 import org.onosproject.mastership.MastershipService;
36 import org.onosproject.net.Annotations;
37 import org.onosproject.net.ConnectPoint;
38 import org.onosproject.net.DefaultAnnotations;
39 import org.onosproject.net.DefaultDevice;
40 import org.onosproject.net.DefaultPort;
41 import org.onosproject.net.Device;
42 import org.onosproject.net.DeviceId;
43 import org.onosproject.net.MastershipRole;
44 import org.onosproject.net.Port;
45 import org.onosproject.net.PortNumber;
46 import org.onosproject.net.device.DeviceEvent;
47 import org.onosproject.net.device.DeviceListener;
48 import org.onosproject.net.device.DeviceServiceAdapter;
49 import org.onosproject.net.flow.TrafficTreatment;
50 import org.onosproject.net.link.LinkDescription;
51 import org.onosproject.net.link.LinkProvider;
52 import org.onosproject.net.link.LinkProviderRegistry;
53 import org.onosproject.net.link.LinkProviderService;
54 import org.onosproject.net.link.LinkServiceAdapter;
55 import org.onosproject.net.packet.DefaultInboundPacket;
56 import org.onosproject.net.packet.InboundPacket;
57 import org.onosproject.net.packet.OutboundPacket;
58 import org.onosproject.net.packet.PacketContext;
59 import org.onosproject.net.packet.PacketProcessor;
60 import org.onosproject.net.packet.PacketServiceAdapter;
61 import org.onosproject.net.provider.AbstractProviderService;
62 import org.onosproject.net.provider.ProviderId;
64 import java.nio.ByteBuffer;
65 import java.util.Collections;
66 import java.util.HashMap;
67 import java.util.List;
70 import java.util.concurrent.CompletableFuture;
72 import static org.easymock.EasyMock.*;
73 import static org.junit.Assert.*;
75 public class LLDPLinkProviderTest {
77 private static final DeviceId DID1 = DeviceId.deviceId("of:0000000000000001");
78 private static final DeviceId DID2 = DeviceId.deviceId("of:0000000000000002");
79 private static final DeviceId DID3 = DeviceId.deviceId("of:0000000000000003");
81 private static Port pd1;
82 private static Port pd2;
83 private static Port pd3;
84 private static Port pd4;
86 private final LLDPLinkProvider provider = new LLDPLinkProvider();
87 private final TestLinkRegistry linkRegistry = new TestLinkRegistry();
88 private final TestLinkService linkService = new TestLinkService();
89 private final TestPacketService packetService = new TestPacketService();
90 private final TestDeviceService deviceService = new TestDeviceService();
91 private final TestMasterShipService masterService = new TestMasterShipService();
93 private CoreService coreService;
94 private TestLinkProviderService providerService;
96 private PacketProcessor testProcessor;
97 private DeviceListener deviceListener;
99 private ApplicationId appId =
100 new DefaultApplicationId(100, "org.onosproject.provider.lldp");
103 public void setUp() {
104 coreService = createMock(CoreService.class);
105 expect(coreService.registerApplication(appId.name()))
106 .andReturn(appId).anyTimes();
109 provider.cfgService = new ComponentConfigAdapter();
110 provider.coreService = coreService;
112 provider.deviceService = deviceService;
113 provider.linkService = linkService;
114 provider.packetService = packetService;
115 provider.providerRegistry = linkRegistry;
116 provider.masterService = masterService;
118 provider.activate(null);
122 public void basics() {
123 assertNotNull("registration expected", providerService);
124 assertEquals("incorrect provider", provider, providerService.provider());
128 public void switchAdd() {
129 DeviceEvent de = deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1);
130 deviceListener.event(de);
132 assertFalse("Device not added", provider.discoverers.isEmpty());
136 public void switchRemove() {
137 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
138 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_REMOVED, DID1));
140 final LinkDiscovery linkDiscovery = provider.discoverers.get(DID1);
141 if (linkDiscovery != null) {
142 // If LinkDiscovery helper is there after DEVICE_REMOVED,
143 // it should be stopped
144 assertTrue("Discoverer is not stopped", linkDiscovery.isStopped());
146 assertTrue("Device is not gone.", vanishedDpid(DID1));
150 * Checks that links on a reconfigured switch are properly removed.
153 public void switchSuppressed() {
154 // add device to stub DeviceService
155 deviceService.putDevice(device(DID3));
156 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
158 assertFalse("Device not added", provider.discoverers.isEmpty());
160 // update device in stub DeviceService with suppression config
161 deviceService.putDevice(device(DID3, DefaultAnnotations.builder()
162 .set(LLDPLinkProvider.NO_LLDP, "true")
164 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
166 assertTrue("Links on suppressed Device was expected to vanish.", vanishedDpid(DID3));
170 public void portUp() {
171 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
172 deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 3, true)));
174 assertTrue("Port not added to discoverer",
175 provider.discoverers.get(DID1).containsPort(3L));
179 public void portDown() {
181 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
182 deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 1, false)));
184 assertFalse("Port added to discoverer",
185 provider.discoverers.get(DID1).containsPort(1L));
186 assertTrue("Port is not gone.", vanishedPort(1L));
190 public void portRemoved() {
191 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
192 deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 3, true)));
193 deviceListener.event(portEvent(DeviceEvent.Type.PORT_REMOVED, DID1, port(DID1, 3, true)));
195 assertTrue("Port is not gone.", vanishedPort(3L));
196 assertFalse("Port was not removed from discoverer",
197 provider.discoverers.get(DID1).containsPort(3L));
201 * Checks that discovery on reconfigured switch are properly restarted.
204 public void portSuppressedByDeviceConfig() {
206 /// When Device is configured with suppression:ON, Port also is same
208 // add device in stub DeviceService with suppression configured
209 deviceService.putDevice(device(DID3, DefaultAnnotations.builder()
210 .set(LLDPLinkProvider.NO_LLDP, "true")
212 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
214 // non-suppressed port added to suppressed device
215 final long portno3 = 3L;
216 deviceService.putPorts(DID3, port(DID3, portno3, true));
217 deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, portno3, true)));
219 // discovery on device is expected to be stopped
220 LinkDiscovery linkDiscovery = provider.discoverers.get(DID3);
221 if (linkDiscovery != null) {
222 assertTrue("Discovery expected to be stopped", linkDiscovery.isStopped());
225 /// When Device is reconfigured without suppression:OFF,
226 /// Port should be included for discovery
228 // update device in stub DeviceService without suppression configured
229 deviceService.putDevice(device(DID3));
230 // update the Port in stub DeviceService. (Port has reference to Device)
231 deviceService.putPorts(DID3, port(DID3, portno3, true));
232 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
234 // discovery should come back on
235 assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped());
236 assertTrue("Discoverer should contain the port there", provider.discoverers.get(DID3).containsPort(portno3));
240 * Checks that discovery on reconfigured port are properly restarted.
243 public void portSuppressedByPortConfig() {
244 // add device in stub DeviceService without suppression configured
245 deviceService.putDevice(device(DID3));
246 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
248 // suppressed port added to non-suppressed device
249 final long portno3 = 3L;
250 final Port port3 = port(DID3, portno3, true,
251 DefaultAnnotations.builder()
252 .set(LLDPLinkProvider.NO_LLDP, "true")
254 deviceService.putPorts(DID3, port3);
255 deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port3));
257 // discovery helper should be there turned on
258 assertFalse("Discoverer is expected to start", provider.discoverers.get(DID3).isStopped());
259 assertFalse("Discoverer should not contain the port there",
260 provider.discoverers.get(DID3).containsPort(portno3));
264 public void portUnknown() {
265 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
266 // Note: DID3 hasn't been added to TestDeviceService, but only port is added
267 deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port(DID3, 1, false)));
270 assertNull("DeviceId exists",
271 provider.discoverers.get(DID3));
275 public void unknownPktCtx() {
277 // Note: DID3 hasn't been added to TestDeviceService
278 PacketContext pktCtx = new TestPacketContext(device(DID3));
280 testProcessor.process(pktCtx);
281 assertFalse("Context should still be free", pktCtx.isHandled());
285 public void knownPktCtx() {
286 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
287 deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID2));
288 PacketContext pktCtx = new TestPacketContext(deviceService.getDevice(DID2));
291 testProcessor.process(pktCtx);
293 assertTrue("Link not detected", detectedLink(DID1, DID2));
299 public void tearDown() {
300 provider.deactivate();
301 provider.coreService = null;
302 provider.providerRegistry = null;
303 provider.deviceService = null;
304 provider.packetService = null;
307 private DeviceEvent deviceEvent(DeviceEvent.Type type, DeviceId did) {
308 return new DeviceEvent(type, deviceService.getDevice(did));
312 private DefaultDevice device(DeviceId did) {
313 return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH,
314 "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
317 private DefaultDevice device(DeviceId did, Annotations annotations) {
318 return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH,
319 "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId(), annotations);
322 @SuppressWarnings(value = { "unused" })
323 private DeviceEvent portEvent(DeviceEvent.Type type, DeviceId did, PortNumber port) {
324 return new DeviceEvent(type, deviceService.getDevice(did),
325 deviceService.getPort(did, port));
328 private DeviceEvent portEvent(DeviceEvent.Type type, DeviceId did, Port port) {
329 return new DeviceEvent(type, deviceService.getDevice(did), port);
332 private Port port(DeviceId did, long port, boolean enabled) {
333 return new DefaultPort(deviceService.getDevice(did),
334 PortNumber.portNumber(port), enabled);
337 private Port port(DeviceId did, long port, boolean enabled, Annotations annotations) {
338 return new DefaultPort(deviceService.getDevice(did),
339 PortNumber.portNumber(port), enabled, annotations);
342 private boolean vanishedDpid(DeviceId... dids) {
343 for (int i = 0; i < dids.length; i++) {
344 if (!providerService.vanishedDpid.contains(dids[i])) {
351 private boolean vanishedPort(Long... ports) {
352 for (int i = 0; i < ports.length; i++) {
353 if (!providerService.vanishedPort.contains(ports[i])) {
360 private boolean detectedLink(DeviceId src, DeviceId dst) {
361 for (DeviceId key : providerService.discoveredLinks.keySet()) {
362 if (key.equals(src)) {
363 return providerService.discoveredLinks.get(src).equals(dst);
370 private class TestLinkRegistry implements LinkProviderRegistry {
373 public LinkProviderService register(LinkProvider provider) {
374 providerService = new TestLinkProviderService(provider);
375 return providerService;
379 public void unregister(LinkProvider provider) {
383 public Set<ProviderId> getProviders() {
389 private class TestLinkProviderService
390 extends AbstractProviderService<LinkProvider>
391 implements LinkProviderService {
393 List<DeviceId> vanishedDpid = Lists.newLinkedList();
394 List<Long> vanishedPort = Lists.newLinkedList();
395 Map<DeviceId, DeviceId> discoveredLinks = Maps.newHashMap();
397 protected TestLinkProviderService(LinkProvider provider) {
402 public void linkDetected(LinkDescription linkDescription) {
403 DeviceId sDid = linkDescription.src().deviceId();
404 DeviceId dDid = linkDescription.dst().deviceId();
405 discoveredLinks.put(sDid, dDid);
409 public void linkVanished(LinkDescription linkDescription) {
413 public void linksVanished(ConnectPoint connectPoint) {
414 vanishedPort.add(connectPoint.port().toLong());
419 public void linksVanished(DeviceId deviceId) {
420 vanishedDpid.add(deviceId);
428 private class TestPacketContext implements PacketContext {
430 protected Device device;
431 protected boolean blocked = false;
433 public TestPacketContext(Device dev) {
443 public InboundPacket inPacket() {
444 ONOSLLDP lldp = new ONOSLLDP();
445 lldp.setChassisId(device.chassisId());
446 lldp.setPortId((int) pd1.number().toLong());
447 lldp.setDevice(deviceService.getDevice(DID1).id().toString());
450 Ethernet ethPacket = new Ethernet();
451 ethPacket.setEtherType(Ethernet.TYPE_LLDP);
452 ethPacket.setDestinationMACAddress(ONOSLLDP.LLDP_NICIRA);
453 ethPacket.setPayload(lldp);
454 ethPacket.setPad(true);
458 ethPacket.setSourceMACAddress("DE:AD:BE:EF:BA:11");
460 ConnectPoint cp = new ConnectPoint(device.id(), pd3.number());
462 return new DefaultInboundPacket(cp, ethPacket,
463 ByteBuffer.wrap(ethPacket.serialize()));
468 public OutboundPacket outPacket() {
473 public TrafficTreatment.Builder treatmentBuilder() {
483 public boolean block() {
489 public boolean isHandled() {
495 private class TestPacketService extends PacketServiceAdapter {
497 public void addProcessor(PacketProcessor processor, int priority) {
498 testProcessor = processor;
502 private class TestDeviceService extends DeviceServiceAdapter {
504 private final Map<DeviceId, Device> devices = new HashMap<>();
505 private final ArrayListMultimap<DeviceId, Port> ports =
506 ArrayListMultimap.create();
507 public TestDeviceService() {
508 Device d1 = new DefaultDevice(ProviderId.NONE, DID1, Device.Type.SWITCH,
509 "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
510 Device d2 = new DefaultDevice(ProviderId.NONE, DID2, Device.Type.SWITCH,
511 "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
512 devices.put(DID1, d1);
513 devices.put(DID2, d2);
514 pd1 = new DefaultPort(d1, PortNumber.portNumber(1), true);
515 pd2 = new DefaultPort(d1, PortNumber.portNumber(2), true);
516 pd3 = new DefaultPort(d2, PortNumber.portNumber(1), true);
517 pd4 = new DefaultPort(d2, PortNumber.portNumber(2), true);
519 ports.putAll(DID1, Lists.newArrayList(pd1, pd2));
520 ports.putAll(DID2, Lists.newArrayList(pd3, pd4));
523 private void putDevice(Device device) {
524 DeviceId deviceId = device.id();
525 devices.put(deviceId, device);
528 private void putPorts(DeviceId did, Port...ports) {
529 this.ports.putAll(did, Lists.newArrayList(ports));
533 public int getDeviceCount() {
534 return devices.values().size();
538 public Iterable<Device> getDevices() {
539 return ImmutableList.copyOf(devices.values());
543 public Device getDevice(DeviceId deviceId) {
544 return devices.get(deviceId);
548 public MastershipRole getRole(DeviceId deviceId) {
549 return MastershipRole.MASTER;
553 public List<Port> getPorts(DeviceId deviceId) {
554 return ports.get(deviceId);
558 public Port getPort(DeviceId deviceId, PortNumber portNumber) {
559 for (Port p : ports.get(deviceId)) {
560 if (p.number().equals(portNumber)) {
568 public boolean isAvailable(DeviceId deviceId) {
573 public void addListener(DeviceListener listener) {
574 deviceListener = listener;
579 public void removeListener(DeviceListener listener) {
584 private final class TestMasterShipService implements MastershipService {
587 public MastershipRole getLocalRole(DeviceId deviceId) {
588 return MastershipRole.MASTER;
592 public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) {
593 return CompletableFuture.completedFuture(null);
597 public CompletableFuture<Void> relinquishMastership(DeviceId deviceId) {
602 public NodeId getMasterFor(DeviceId deviceId) {
607 public Set<DeviceId> getDevicesOf(NodeId nodeId) {
612 public void addListener(MastershipListener listener) {
617 public void removeListener(MastershipListener listener) {
622 public RoleInfo getNodesFor(DeviceId deviceId) {
623 return new RoleInfo(new NodeId("foo"), Collections.<NodeId>emptyList());
628 private class TestLinkService extends LinkServiceAdapter {