/* * Copyright 2016-present Open Networking Laboratory * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.onosproject.incubator.net.neighbour.impl; import org.junit.Before; import org.junit.Test; import org.onlab.osgi.ComponentContextAdapter; import org.onlab.packet.Ethernet; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; import org.onlab.packet.VlanId; import org.onosproject.TestApplicationId; import org.onosproject.cfg.ComponentConfigAdapter; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.incubator.net.intf.Interface; import org.onosproject.incubator.net.neighbour.NeighbourHandlerRegistration; import org.onosproject.incubator.net.neighbour.NeighbourMessageContext; import org.onosproject.incubator.net.neighbour.NeighbourMessageHandler; import org.onosproject.net.ConnectPoint; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.host.HostService; import org.onosproject.net.packet.DefaultInboundPacket; import org.onosproject.net.packet.DefaultOutboundPacket; import org.onosproject.net.packet.InboundPacket; import org.onosproject.net.packet.PacketContextAdapter; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketPriority; import org.onosproject.net.packet.PacketProcessor; import org.onosproject.net.packet.PacketService; import org.onosproject.net.packet.PacketServiceAdapter; import java.util.Collection; import static org.easymock.EasyMock.anyInt; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.onosproject.incubator.net.neighbour.impl.DefaultNeighbourMessageContext.createContext; import static org.onosproject.incubator.net.neighbour.impl.NeighbourTestUtils.createArpRequest; import static org.onosproject.incubator.net.neighbour.impl.NeighbourTestUtils.intf; /** * Unit tests for the NeighbourResolutionManager. */ public class NeighbourResolutionManagerTest { private NeighbourResolutionManager neighbourManager; private PacketService packetService; private PacketProcessor packetProcessor; private static final NeighbourMessageHandler HANDLER = new TestNeighbourHandler(); private static final ConnectPoint CP1 = ConnectPoint.deviceConnectPoint("of:0000000000000001/1"); private static final ConnectPoint CP2 = ConnectPoint.deviceConnectPoint("of:0000000000000001/2"); private static final MacAddress MAC1 = MacAddress.valueOf(1); private static final IpAddress IP1 = IpAddress.valueOf(1); private static final IpAddress IP2 = IpAddress.valueOf(2); private static final Interface INTF1 = intf(CP1, IP1, MAC1, VlanId.NONE); private static final ApplicationId APP_ID = TestApplicationId.create("app"); @Before public void setUp() throws Exception { neighbourManager = new NeighbourResolutionManager(); packetService = createMock(PacketService.class); packetService.requestPackets(anyObject(TrafficSelector.class), anyObject(PacketPriority.class), anyObject(ApplicationId.class)); expectLastCall().anyTimes(); packetService.addProcessor(anyObject(PacketProcessor.class), anyInt()); expectLastCall().andDelegateTo(new TestPacketService()).once(); packetService.cancelPackets(anyObject(TrafficSelector.class), anyObject(PacketPriority.class), anyObject(ApplicationId.class)); expectLastCall().anyTimes(); replay(packetService); neighbourManager.packetService = packetService; CoreService coreService = createNiceMock(CoreService.class); replay(coreService); neighbourManager.coreService = coreService; neighbourManager.componentConfigService = new ComponentConfigAdapter(); neighbourManager.activate(new ComponentContextAdapter()); } @Test public void testRegistration() throws Exception { neighbourManager.registerNeighbourHandler(CP1, HANDLER, APP_ID); assertTrue(verifyRegistration(CP1, HANDLER, APP_ID)); } @Test public void testUnregister() { // Register a handler and verify the registration is there neighbourManager.registerNeighbourHandler(CP1, HANDLER, APP_ID); assertTrue(verifyRegistration(CP1, HANDLER, APP_ID)); // Unregister the handler but supply a different connect point neighbourManager.unregisterNeighbourHandler(CP2, HANDLER, APP_ID); // Verify the original registration is still there on the original // connect point assertTrue(verifyRegistration(CP1, HANDLER, APP_ID)); assertTrue(verifyNoRegistration(CP2)); // Unregister the handler from the original connect point neighbourManager.unregisterNeighbourHandler(CP1, HANDLER, APP_ID); // Verify that it is gone assertTrue(verifyNoRegistration(CP1)); } @Test public void testRegisterInterface() { neighbourManager.registerNeighbourHandler(INTF1, HANDLER, APP_ID); assertTrue(verifyRegistration(INTF1, HANDLER, APP_ID)); } @Test public void testUnregisterInterface() { // Register a handler for an interface and verify it is there neighbourManager.registerNeighbourHandler(INTF1, HANDLER, APP_ID); assertTrue(verifyRegistration(INTF1, HANDLER, APP_ID)); // Unregister the handler but use the connect point rather than the interface neighbourManager.unregisterNeighbourHandler(CP1, HANDLER, APP_ID); // Verify the interface registration is still there assertTrue(verifyRegistration(INTF1, HANDLER, APP_ID)); // Unregister the handler from the interface neighbourManager.unregisterNeighbourHandler(INTF1, HANDLER, APP_ID); // Verify the registration is gone assertTrue(verifyNoRegistration(INTF1)); } @Test public void testUnregisterByAppId() { // Register some handlers and verify they are there neighbourManager.registerNeighbourHandler(CP1, HANDLER, APP_ID); neighbourManager.registerNeighbourHandler(CP2, HANDLER, APP_ID); assertEquals(2, neighbourManager.getHandlerRegistrations().size()); // Unregister all handlers for the given app ID neighbourManager.unregisterNeighbourHandlers(APP_ID); // Verify the handlers are gone assertEquals(0, neighbourManager.getHandlerRegistrations().size()); } @Test public void testPacketDistribution() { Ethernet arpRequest = createArpRequest(IP1); NeighbourMessageHandler handler = createMock(NeighbourMessageHandler.class); handler.handleMessage(eq(createContext(arpRequest, CP1, null)), anyObject(HostService.class)); expectLastCall().once(); replay(handler); neighbourManager.registerNeighbourHandler(CP1, handler, APP_ID); // Incoming packet on the connect point where the handler is registered packetProcessor.process(context(arpRequest, CP1)); // Send a packet from a different connect point that should not be // delivered to the handler packetProcessor.process(context(arpRequest, CP2)); verify(handler); } @Test public void testPacketDistributionToInterface() { Ethernet arpRequest = createArpRequest(IP1); NeighbourMessageHandler handler = createMock(NeighbourMessageHandler.class); handler.handleMessage(eq(createContext(arpRequest, CP1, null)), anyObject(HostService.class)); expectLastCall().once(); replay(handler); neighbourManager.registerNeighbourHandler(INTF1, handler, APP_ID); // Incoming packet matching the interface where the handler is registered packetProcessor.process(context(arpRequest, CP1)); verify(handler); reset(handler); replay(handler); // Incoming packet on same connect point but not matching the interface packetProcessor.process(context(createArpRequest(IP2), CP1)); verify(handler); } /** * Verifies that there is one registration for the given connect point and * that the registration matches the given handler and appId. * * @param cp connect point to verify registration for * @param handler neighbour message handler * @param appId application ID * @return true if the registration is the only registration present for * this connect point, otherwise false */ private boolean verifyRegistration(ConnectPoint cp, NeighbourMessageHandler handler, ApplicationId appId) { Collection<NeighbourHandlerRegistration> registrations = neighbourManager.getHandlerRegistrations().get(cp); if (registrations == null) { return false; } if (registrations.size() != 1) { return false; } NeighbourHandlerRegistration reg = registrations.stream().findFirst().get(); return reg.appId().equals(appId) && reg.handler().equals(handler); } /** * Verifies that there is one registration for the given interface and * that the registration matches the given handler and appId. * * @param intf interface to verify registration for * @param handler neighbour message handler * @param appId application ID * @return true if the registration is the only registration present for * this interface, otherwise false */ private boolean verifyRegistration(Interface intf, NeighbourMessageHandler handler, ApplicationId appId) { return verifyRegistration(intf.connectPoint(), handler, appId); } /** * Verifies that there are no registrations for the given connect point. * * @param cp connect point * @return true if there are no registrations for this connect point, * otherwise false */ private boolean verifyNoRegistration(ConnectPoint cp) { return neighbourManager.getHandlerRegistrations().get(cp) == null; } /** * Verifies that there are no registrations for the given interface. * * @param intf interface * @return true if there are no registrations for this interface, * otherwise false */ private boolean verifyNoRegistration(Interface intf) { return verifyNoRegistration(intf.connectPoint()); } /** * Creates a packet context for the given packet coming in the given port. * * @param packet packet to wrap in a packet context * @param inPort input port of the packet * @return packet context */ private static PacketContext context(Ethernet packet, ConnectPoint inPort) { InboundPacket inboundPacket = new DefaultInboundPacket(inPort, packet, null); OutboundPacket outboundPacket = new DefaultOutboundPacket(null, null, null); return new PacketContextAdapter(0, inboundPacket, outboundPacket, false); } private class TestPacketService extends PacketServiceAdapter { @Override public void addProcessor(PacketProcessor processor, int priority) { NeighbourResolutionManagerTest.this.packetProcessor = processor; } } private static class TestNeighbourHandler implements NeighbourMessageHandler { @Override public void handleMessage(NeighbourMessageContext context, HostService hostService) { } } }