/* * Copyright 2017-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.routing.fibinstaller; import com.google.common.collect.Sets; import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; import org.onlab.packet.Ethernet; import org.onlab.packet.Ip4Prefix; import org.onlab.packet.IpAddress; import org.onlab.packet.IpPrefix; import org.onlab.packet.MacAddress; import org.onlab.packet.VlanId; import org.onosproject.TestApplicationId; import org.onosproject.app.ApplicationService; import org.onosproject.cfg.ComponentConfigService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.incubator.net.intf.Interface; import org.onosproject.incubator.net.intf.InterfaceListener; import org.onosproject.incubator.net.intf.InterfaceService; import org.onosproject.incubator.net.intf.InterfaceServiceAdapter; import org.onosproject.incubator.net.routing.ResolvedRoute; import org.onosproject.incubator.net.routing.Route; import org.onosproject.incubator.net.routing.RouteEvent; import org.onosproject.incubator.net.routing.RouteListener; import org.onosproject.incubator.net.routing.RouteServiceAdapter; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DeviceId; import org.onosproject.net.PortNumber; import org.onosproject.net.config.NetworkConfigListener; import org.onosproject.net.config.NetworkConfigRegistry; import org.onosproject.net.config.NetworkConfigService; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceService; import org.onosproject.net.device.DeviceServiceAdapter; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flowobjective.DefaultForwardingObjective; import org.onosproject.net.flowobjective.DefaultNextObjective; import org.onosproject.net.flowobjective.FlowObjectiveService; import org.onosproject.net.flowobjective.ForwardingObjective; import org.onosproject.net.flowobjective.NextObjective; import org.onosproject.net.host.InterfaceIpAddress; import org.onosproject.routing.RoutingService; import org.onosproject.routing.config.RouterConfig; import org.onosproject.routing.config.RoutersConfig; import org.osgi.service.component.ComponentContext; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.anyString; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.reset; import static org.easymock.EasyMock.verify; /** * Unit tests for SingleSwitchFibInstaller. */ public class FibInstallerTest { private static final DeviceId DEVICE_ID = DeviceId.deviceId("of:0000000000000001"); private static final ConnectPoint SW1_ETH1 = new ConnectPoint( DEVICE_ID, PortNumber.portNumber(1)); private static final ConnectPoint SW1_ETH2 = new ConnectPoint( DEVICE_ID, PortNumber.portNumber(2)); private static final int NEXT_ID = 11; private static final VlanId VLAN1 = VlanId.vlanId((short) 1); private static final MacAddress MAC1 = MacAddress.valueOf("00:00:00:00:00:01"); private static final MacAddress MAC2 = MacAddress.valueOf("00:00:00:00:00:02"); private static final IpPrefix PREFIX1 = Ip4Prefix.valueOf("1.1.1.0/24"); private static final IpAddress NEXT_HOP1 = IpAddress.valueOf("192.168.10.1"); private static final IpAddress NEXT_HOP2 = IpAddress.valueOf("192.168.20.1"); private static final InterfaceIpAddress INTF1 = InterfaceIpAddress.valueOf("192.168.10.2/24"); private static final InterfaceIpAddress INTF2 = InterfaceIpAddress.valueOf("192.168.20.2/24"); private final Set<Interface> interfaces = Sets.newHashSet(); private InterfaceService interfaceService; private NetworkConfigService networkConfigService; private NetworkConfigRegistry networkConfigRegistry; private FlowObjectiveService flowObjectiveService; private ApplicationService applicationService; private DeviceService deviceService; private static final ApplicationId APPID = TestApplicationId.create("foo"); private RouteListener routeListener; private DeviceListener deviceListener; private RouterConfig routerConfig; private FibInstaller sSfibInstaller; private InterfaceListener interfaceListener; @Before public void setUp() throws Exception { sSfibInstaller = new FibInstaller(); sSfibInstaller.componentConfigService = createNiceMock(ComponentConfigService.class); ComponentContext mockContext = createNiceMock(ComponentContext.class); routerConfig = new TestRouterConfig(); interfaceService = createMock(InterfaceService.class); networkConfigService = createMock(NetworkConfigService.class); networkConfigService.addListener(anyObject(NetworkConfigListener.class)); expectLastCall().anyTimes(); networkConfigRegistry = createMock(NetworkConfigRegistry.class); flowObjectiveService = createMock(FlowObjectiveService.class); applicationService = createNiceMock(ApplicationService.class); replay(applicationService); deviceService = new TestDeviceService(); CoreService coreService = createNiceMock(CoreService.class); expect(coreService.registerApplication(anyString())).andReturn(APPID).anyTimes(); replay(coreService); sSfibInstaller.networkConfigService = networkConfigService; sSfibInstaller.networkConfigRegistry = networkConfigRegistry; sSfibInstaller.interfaceService = interfaceService; sSfibInstaller.flowObjectiveService = flowObjectiveService; sSfibInstaller.applicationService = applicationService; sSfibInstaller.coreService = coreService; sSfibInstaller.routeService = new TestRouteService(); sSfibInstaller.deviceService = deviceService; setUpNetworkConfigService(); setUpInterfaceService(); sSfibInstaller.activate(mockContext); } /** * Sets up InterfaceService. */ private void setUpInterfaceService() { interfaceService.addListener(anyObject(InterfaceListener.class)); expectLastCall().andDelegateTo(new TestInterfaceService()); // Interface with no VLAN Interface sw1Eth1 = new Interface("intf1", SW1_ETH1, Collections.singletonList(INTF1), MAC1, VlanId.NONE); expect(interfaceService.getMatchingInterface(NEXT_HOP1)).andReturn(sw1Eth1); interfaces.add(sw1Eth1); // Interface with a VLAN Interface sw2Eth1 = new Interface("intf2", SW1_ETH2, Collections.singletonList(INTF2), MAC2, VLAN1); expect(interfaceService.getMatchingInterface(NEXT_HOP2)).andReturn(sw2Eth1); interfaces.add(sw2Eth1); expect(interfaceService.getInterfaces()).andReturn(interfaces); replay(interfaceService); } /* * Sets up NetworkConfigService. */ private void setUpNetworkConfigService() { expect(networkConfigService.getConfig( anyObject(ApplicationId.class), eq(RoutingService.ROUTER_CONFIG_CLASS))). andReturn(routerConfig); expect(networkConfigService.getConfig(anyObject(ApplicationId.class), eq(RoutersConfig.class))) .andReturn(null); replay(networkConfigService); } /** * Sets up FlowObjectiveService. */ private void setUpFlowObjectiveService() { expect(flowObjectiveService.allocateNextId()).andReturn(NEXT_ID); replay(flowObjectiveService); } /** * Creates a next objective with the given parameters. * * @param srcMac source MAC address * @param dstMac destination MAC address * @param port port number * @param vlan vlan ID * @param add whether to create an add objective or remove objective * @return new next objective */ private NextObjective createNextObjective(MacAddress srcMac, MacAddress dstMac, PortNumber port, VlanId vlan, boolean add) { TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder() .setEthSrc(srcMac) .setEthDst(dstMac); TrafficSelector.Builder metabuilder = null; if (!vlan.equals(VlanId.NONE)) { treatment.pushVlan() .setVlanId(vlan) .setVlanPcp((byte) 0); } else { metabuilder = DefaultTrafficSelector.builder(); metabuilder.matchVlanId(VlanId.vlanId(FibInstaller.ASSIGNED_VLAN)); } treatment.setOutput(port); NextObjective.Builder nextBuilder = DefaultNextObjective.builder() .withId(NEXT_ID) .addTreatment(treatment.build()) .withType(NextObjective.Type.SIMPLE) .fromApp(APPID); if (metabuilder != null) { nextBuilder.withMeta(metabuilder.build()); } return add ? nextBuilder.add() : nextBuilder.remove(); } /** * Creates a new forwarding objective with the given parameters. * * @param prefix IP prefix * @param add whether to create an add objective or a remove objective * @return new forwarding objective */ private ForwardingObjective createForwardingObjective(IpPrefix prefix, boolean add) { TrafficSelector selector = DefaultTrafficSelector.builder() .matchEthType(Ethernet.TYPE_IPV4) .matchIPDst(prefix) .build(); int priority = prefix.prefixLength() * 5 + 100; ForwardingObjective.Builder fwdBuilder = DefaultForwardingObjective.builder() .fromApp(APPID) .makePermanent() .withSelector(selector) .withPriority(priority) .withFlag(ForwardingObjective.Flag.SPECIFIC); if (add) { fwdBuilder.nextStep(NEXT_ID); } else { fwdBuilder.withTreatment(DefaultTrafficTreatment.builder().build()); } return add ? fwdBuilder.add() : fwdBuilder.remove(); } /** * Tests adding a route. * * We verify that the flowObjectiveService records the correct state and that the * correct flow is submitted to the flowObjectiveService. */ @Test public void testRouteAdd() { ResolvedRoute resolvedRoute = createRoute(PREFIX1, NEXT_HOP1, MAC1, SW1_ETH1); // Create the next objective NextObjective nextObjective = createNextObjective(MAC1, MAC1, SW1_ETH1.port(), VlanId.NONE, true); flowObjectiveService.next(DEVICE_ID, nextObjective); // Create the flow objective ForwardingObjective fwd = createForwardingObjective(PREFIX1, true); flowObjectiveService.forward(DEVICE_ID, fwd); EasyMock.expectLastCall().once(); setUpFlowObjectiveService(); // Send in the add event RouteEvent routeEvent = new RouteEvent(RouteEvent.Type.ROUTE_ADDED, resolvedRoute); routeListener.event(routeEvent); verify(flowObjectiveService); } /** * Tests adding a route with to a next hop in a VLAN. * * We verify that the flowObjectiveService records the correct state and that the * correct flowObjectiveService is submitted to the flowObjectiveService. */ @Test public void testRouteAddWithVlan() { ResolvedRoute route = createRoute(PREFIX1, NEXT_HOP2, MAC2, SW1_ETH2); // Create the next objective NextObjective nextObjective = createNextObjective(MAC2, MAC2, SW1_ETH2.port(), VLAN1, true); flowObjectiveService.next(DEVICE_ID, nextObjective); // Create the flow objective ForwardingObjective fwd = createForwardingObjective(PREFIX1, true); flowObjectiveService.forward(DEVICE_ID, fwd); EasyMock.expectLastCall().once(); setUpFlowObjectiveService(); // Send in the add event routeListener.event(new RouteEvent(RouteEvent.Type.ROUTE_ADDED, route)); verify(flowObjectiveService); } /** * Tests updating a route. * * We verify that the flowObjectiveService records the correct state and that the * correct flow is submitted to the flowObjectiveService. */ @Test public void testRouteUpdate() { // Firstly add a route testRouteAdd(); reset(flowObjectiveService); ResolvedRoute oldRoute = createRoute(PREFIX1, NEXT_HOP1, MAC1, SW1_ETH1); ResolvedRoute route = createRoute(PREFIX1, NEXT_HOP2, MAC2, SW1_ETH2); // Create the next objective NextObjective nextObjective = createNextObjective(MAC2, MAC2, SW1_ETH2.port(), VLAN1, true); flowObjectiveService.next(DEVICE_ID, nextObjective); // Create the flow objective ForwardingObjective fwd = createForwardingObjective(PREFIX1, true); flowObjectiveService.forward(DEVICE_ID, fwd); EasyMock.expectLastCall().once(); setUpFlowObjectiveService(); // Send in the update event routeListener.event(new RouteEvent(RouteEvent.Type.ROUTE_UPDATED, route, oldRoute)); verify(flowObjectiveService); } /** * Tests deleting a route. * * We verify that the flowObjectiveService records the correct state and that the * correct flow is withdrawn from the flowObjectiveService. */ @Test public void testRouteDelete() { // Firstly add a route testRouteAdd(); // Construct the existing route ResolvedRoute route = createRoute(PREFIX1, NEXT_HOP1, MAC1, SW1_ETH1); // Create the flow objective reset(flowObjectiveService); ForwardingObjective fwd = createForwardingObjective(PREFIX1, false); flowObjectiveService.forward(DEVICE_ID, fwd); replay(flowObjectiveService); // Send in the delete event routeListener.event(new RouteEvent(RouteEvent.Type.ROUTE_REMOVED, route)); verify(flowObjectiveService); } private static ResolvedRoute createRoute(IpPrefix prefix, IpAddress nextHop, MacAddress nextHopMac, ConnectPoint location) { return new ResolvedRoute( new Route(Route.Source.UNDEFINED, prefix, nextHop), nextHopMac, location); } private class TestInterfaceService extends InterfaceServiceAdapter { @Override public void addListener(InterfaceListener listener) { interfaceListener = listener; } } private class TestRouteService extends RouteServiceAdapter { @Override public void addListener(RouteListener listener) { FibInstallerTest.this.routeListener = listener; } } private class TestRouterConfig extends RouterConfig { @Override public List<String> getInterfaces() { ArrayList<String> interfaces = new ArrayList<>(); interfaces.add("of:0000000000000001/1"); interfaces.add("of:0000000000000001/2"); return interfaces; } @Override public ConnectPoint getControlPlaneConnectPoint() { return SW1_ETH1; } @Override public boolean getOspfEnabled() { return true; } } private class TestDeviceService extends DeviceServiceAdapter { @Override public boolean isAvailable(DeviceId deviceId) { return true; } @Override public void addListener(DeviceListener listener) { FibInstallerTest.this.deviceListener = listener; } } }