6070b857288c156d9744f502a05a342bc4c63ec6
[onosfw.git] /
1 /*
2  * Copyright 2014-2015 Open Networking Laboratory
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 package org.onosproject.provider.lldp.impl;
17
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;
63
64 import java.nio.ByteBuffer;
65 import java.util.Collections;
66 import java.util.HashMap;
67 import java.util.List;
68 import java.util.Map;
69 import java.util.Set;
70 import java.util.concurrent.CompletableFuture;
71
72 import static org.easymock.EasyMock.*;
73 import static org.junit.Assert.*;
74
75 public class LLDPLinkProviderTest {
76
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");
80
81     private static Port pd1;
82     private static Port pd2;
83     private static Port pd3;
84     private static Port pd4;
85
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();
92
93     private CoreService coreService;
94     private TestLinkProviderService providerService;
95
96     private PacketProcessor testProcessor;
97     private DeviceListener deviceListener;
98
99     private ApplicationId appId =
100             new DefaultApplicationId(100, "org.onosproject.provider.lldp");
101
102     @Before
103     public void setUp() {
104         coreService = createMock(CoreService.class);
105         expect(coreService.registerApplication(appId.name()))
106             .andReturn(appId).anyTimes();
107         replay(coreService);
108
109         provider.cfgService = new ComponentConfigAdapter();
110         provider.coreService = coreService;
111
112         provider.deviceService = deviceService;
113         provider.linkService = linkService;
114         provider.packetService = packetService;
115         provider.providerRegistry = linkRegistry;
116         provider.masterService = masterService;
117
118         provider.activate(null);
119     }
120
121     @Test
122     public void basics() {
123         assertNotNull("registration expected", providerService);
124         assertEquals("incorrect provider", provider, providerService.provider());
125     }
126
127     @Test
128     public void switchAdd() {
129         DeviceEvent de = deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1);
130         deviceListener.event(de);
131
132         assertFalse("Device not added", provider.discoverers.isEmpty());
133     }
134
135     @Test
136     public void switchRemove() {
137         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
138         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_REMOVED, DID1));
139
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());
145         }
146         assertTrue("Device is not gone.", vanishedDpid(DID1));
147     }
148
149     /**
150      * Checks that links on a reconfigured switch are properly removed.
151      */
152     @Test
153     public void switchSuppressed() {
154         // add device to stub DeviceService
155         deviceService.putDevice(device(DID3));
156         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
157
158         assertFalse("Device not added", provider.discoverers.isEmpty());
159
160         // update device in stub DeviceService with suppression config
161         deviceService.putDevice(device(DID3, DefaultAnnotations.builder()
162                                               .set(LLDPLinkProvider.NO_LLDP, "true")
163                                               .build()));
164         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_UPDATED, DID3));
165
166         assertTrue("Links on suppressed Device was expected to vanish.", vanishedDpid(DID3));
167     }
168
169     @Test
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)));
173
174         assertTrue("Port not added to discoverer",
175                    provider.discoverers.get(DID1).containsPort(3L));
176     }
177
178     @Test
179     public void portDown() {
180
181         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID1));
182         deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID1, port(DID1, 1, false)));
183
184         assertFalse("Port added to discoverer",
185                     provider.discoverers.get(DID1).containsPort(1L));
186         assertTrue("Port is not gone.", vanishedPort(1L));
187     }
188
189     @Test
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)));
194
195         assertTrue("Port is not gone.", vanishedPort(3L));
196         assertFalse("Port was not removed from discoverer",
197                    provider.discoverers.get(DID1).containsPort(3L));
198     }
199
200     /**
201      * Checks that discovery on reconfigured switch are properly restarted.
202      */
203     @Test
204     public void portSuppressedByDeviceConfig() {
205
206         /// When Device is configured with suppression:ON, Port also is same
207
208         // add device in stub DeviceService with suppression configured
209         deviceService.putDevice(device(DID3, DefaultAnnotations.builder()
210                                               .set(LLDPLinkProvider.NO_LLDP, "true")
211                                               .build()));
212         deviceListener.event(deviceEvent(DeviceEvent.Type.DEVICE_ADDED, DID3));
213
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)));
218
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());
223         }
224
225         /// When Device is reconfigured without suppression:OFF,
226         /// Port should be included for discovery
227
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));
233
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));
237     }
238
239     /**
240      * Checks that discovery on reconfigured port are properly restarted.
241      */
242     @Test
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));
247
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")
253                                           .build());
254         deviceService.putPorts(DID3, port3);
255         deviceListener.event(portEvent(DeviceEvent.Type.PORT_ADDED, DID3, port3));
256
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));
261     }
262
263     @Test
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)));
268
269
270         assertNull("DeviceId exists",
271                    provider.discoverers.get(DID3));
272     }
273
274     @Test
275     public void unknownPktCtx() {
276
277         // Note: DID3 hasn't been added to TestDeviceService
278         PacketContext pktCtx = new TestPacketContext(device(DID3));
279
280         testProcessor.process(pktCtx);
281         assertFalse("Context should still be free", pktCtx.isHandled());
282     }
283
284     @Test
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));
289
290
291         testProcessor.process(pktCtx);
292
293         assertTrue("Link not detected", detectedLink(DID1, DID2));
294
295     }
296
297
298     @After
299     public void tearDown() {
300         provider.deactivate();
301         provider.coreService = null;
302         provider.providerRegistry = null;
303         provider.deviceService = null;
304         provider.packetService = null;
305     }
306
307     private DeviceEvent deviceEvent(DeviceEvent.Type type, DeviceId did) {
308         return new DeviceEvent(type, deviceService.getDevice(did));
309
310     }
311
312     private DefaultDevice device(DeviceId did) {
313         return new DefaultDevice(ProviderId.NONE, did, Device.Type.SWITCH,
314                              "TESTMF", "TESTHW", "TESTSW", "TESTSN", new ChassisId());
315     }
316
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);
320     }
321
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));
326     }
327
328     private DeviceEvent portEvent(DeviceEvent.Type type, DeviceId did, Port port) {
329         return new  DeviceEvent(type, deviceService.getDevice(did), port);
330     }
331
332     private Port port(DeviceId did, long port, boolean enabled) {
333         return new DefaultPort(deviceService.getDevice(did),
334                                PortNumber.portNumber(port), enabled);
335     }
336
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);
340     }
341
342     private boolean vanishedDpid(DeviceId... dids) {
343         for (int i = 0; i < dids.length; i++) {
344             if (!providerService.vanishedDpid.contains(dids[i])) {
345                 return false;
346             }
347         }
348         return true;
349     }
350
351     private boolean vanishedPort(Long... ports) {
352         for (int i = 0; i < ports.length; i++) {
353             if (!providerService.vanishedPort.contains(ports[i])) {
354                 return false;
355             }
356         }
357         return true;
358     }
359
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);
364             }
365         }
366         return false;
367     }
368
369
370     private class TestLinkRegistry implements LinkProviderRegistry {
371
372         @Override
373         public LinkProviderService register(LinkProvider provider) {
374             providerService = new TestLinkProviderService(provider);
375             return providerService;
376         }
377
378         @Override
379         public void unregister(LinkProvider provider) {
380         }
381
382         @Override
383         public Set<ProviderId> getProviders() {
384             return null;
385         }
386
387     }
388
389     private class TestLinkProviderService
390             extends AbstractProviderService<LinkProvider>
391             implements LinkProviderService {
392
393         List<DeviceId> vanishedDpid = Lists.newLinkedList();
394         List<Long> vanishedPort = Lists.newLinkedList();
395         Map<DeviceId, DeviceId> discoveredLinks = Maps.newHashMap();
396
397         protected TestLinkProviderService(LinkProvider provider) {
398             super(provider);
399         }
400
401         @Override
402         public void linkDetected(LinkDescription linkDescription) {
403             DeviceId sDid = linkDescription.src().deviceId();
404             DeviceId dDid = linkDescription.dst().deviceId();
405             discoveredLinks.put(sDid, dDid);
406         }
407
408         @Override
409         public void linkVanished(LinkDescription linkDescription) {
410         }
411
412         @Override
413         public void linksVanished(ConnectPoint connectPoint) {
414             vanishedPort.add(connectPoint.port().toLong());
415
416         }
417
418         @Override
419         public void linksVanished(DeviceId deviceId) {
420             vanishedDpid.add(deviceId);
421         }
422
423
424     }
425
426
427
428     private class TestPacketContext implements PacketContext {
429
430         protected Device device;
431         protected boolean blocked = false;
432
433         public TestPacketContext(Device dev) {
434             device = dev;
435         }
436
437         @Override
438         public long time() {
439             return 0;
440         }
441
442         @Override
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());
448
449
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);
455
456
457
458             ethPacket.setSourceMACAddress("DE:AD:BE:EF:BA:11");
459
460             ConnectPoint cp = new ConnectPoint(device.id(), pd3.number());
461
462             return new DefaultInboundPacket(cp, ethPacket,
463                                             ByteBuffer.wrap(ethPacket.serialize()));
464
465         }
466
467         @Override
468         public OutboundPacket outPacket() {
469             return null;
470         }
471
472         @Override
473         public TrafficTreatment.Builder treatmentBuilder() {
474             return null;
475         }
476
477         @Override
478         public void send() {
479
480         }
481
482         @Override
483         public boolean block() {
484             blocked = true;
485             return blocked;
486         }
487
488         @Override
489         public boolean isHandled() {
490             return blocked;
491         }
492
493     }
494
495     private class TestPacketService extends PacketServiceAdapter {
496         @Override
497         public void addProcessor(PacketProcessor processor, int priority) {
498             testProcessor = processor;
499         }
500     }
501
502     private class TestDeviceService extends DeviceServiceAdapter {
503
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);
518
519             ports.putAll(DID1, Lists.newArrayList(pd1, pd2));
520             ports.putAll(DID2, Lists.newArrayList(pd3, pd4));
521         }
522
523         private void putDevice(Device device) {
524             DeviceId deviceId = device.id();
525             devices.put(deviceId, device);
526         }
527
528         private void putPorts(DeviceId did, Port...ports) {
529             this.ports.putAll(did, Lists.newArrayList(ports));
530         }
531
532         @Override
533         public int getDeviceCount() {
534             return devices.values().size();
535         }
536
537         @Override
538         public Iterable<Device> getDevices() {
539             return ImmutableList.copyOf(devices.values());
540         }
541
542         @Override
543         public Device getDevice(DeviceId deviceId) {
544             return devices.get(deviceId);
545         }
546
547         @Override
548         public MastershipRole getRole(DeviceId deviceId) {
549             return MastershipRole.MASTER;
550         }
551
552         @Override
553         public List<Port> getPorts(DeviceId deviceId) {
554             return ports.get(deviceId);
555         }
556
557         @Override
558         public Port getPort(DeviceId deviceId, PortNumber portNumber) {
559             for (Port p : ports.get(deviceId)) {
560                 if (p.number().equals(portNumber)) {
561                     return p;
562                 }
563             }
564             return null;
565         }
566
567         @Override
568         public boolean isAvailable(DeviceId deviceId) {
569             return true;
570         }
571
572         @Override
573         public void addListener(DeviceListener listener) {
574             deviceListener = listener;
575
576         }
577
578         @Override
579         public void removeListener(DeviceListener listener) {
580
581         }
582     }
583
584     private final class TestMasterShipService implements MastershipService {
585
586         @Override
587         public MastershipRole getLocalRole(DeviceId deviceId) {
588             return MastershipRole.MASTER;
589         }
590
591         @Override
592         public CompletableFuture<MastershipRole> requestRoleFor(DeviceId deviceId) {
593             return CompletableFuture.completedFuture(null);
594         }
595
596         @Override
597         public CompletableFuture<Void> relinquishMastership(DeviceId deviceId) {
598             return null;
599         }
600
601         @Override
602         public NodeId getMasterFor(DeviceId deviceId) {
603             return null;
604         }
605
606         @Override
607         public Set<DeviceId> getDevicesOf(NodeId nodeId) {
608             return null;
609         }
610
611         @Override
612         public void addListener(MastershipListener listener) {
613
614         }
615
616         @Override
617         public void removeListener(MastershipListener listener) {
618
619         }
620
621         @Override
622         public RoleInfo getNodesFor(DeviceId deviceId) {
623             return new RoleInfo(new NodeId("foo"), Collections.<NodeId>emptyList());
624         }
625     }
626
627
628     private class TestLinkService extends LinkServiceAdapter {
629     }
630 }