| /* |
| * Copyright 2017-present Open Networking Foundation |
| * |
| * 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.virtual.impl; |
| |
| import com.google.common.collect.Sets; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.onlab.junit.TestUtils; |
| import org.onlab.osgi.TestServiceDirectory; |
| import org.onosproject.TestApplicationId; |
| import org.onosproject.cluster.ClusterService; |
| import org.onosproject.cluster.ClusterServiceAdapter; |
| import org.onosproject.common.event.impl.TestEventDispatcher; |
| import org.onosproject.core.ApplicationId; |
| import org.onosproject.core.CoreService; |
| import org.onosproject.core.CoreServiceAdapter; |
| import org.onosproject.core.IdGenerator; |
| import org.onosproject.event.EventDeliveryService; |
| import org.onosproject.incubator.net.virtual.NetworkId; |
| import org.onosproject.incubator.net.virtual.VirtualDevice; |
| import org.onosproject.incubator.net.virtual.VirtualNetwork; |
| import org.onosproject.incubator.net.virtual.VirtualNetworkFlowObjectiveStore; |
| import org.onosproject.incubator.net.virtual.VirtualNetworkFlowRuleStore; |
| import org.onosproject.incubator.net.virtual.VirtualNetworkPacketStore; |
| import org.onosproject.incubator.net.virtual.VirtualNetworkStore; |
| import org.onosproject.incubator.net.virtual.impl.provider.VirtualProviderManager; |
| import org.onosproject.incubator.net.virtual.provider.AbstractVirtualProvider; |
| import org.onosproject.incubator.net.virtual.provider.VirtualFlowRuleProvider; |
| import org.onosproject.incubator.net.virtual.provider.VirtualPacketProvider; |
| import org.onosproject.incubator.net.virtual.provider.VirtualProviderRegistryService; |
| import org.onosproject.incubator.store.virtual.impl.DistributedVirtualNetworkStore; |
| import org.onosproject.incubator.store.virtual.impl.SimpleVirtualFlowObjectiveStore; |
| import org.onosproject.incubator.store.virtual.impl.SimpleVirtualFlowRuleStore; |
| import org.onosproject.incubator.store.virtual.impl.SimpleVirtualPacketStore; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.NetTestTools; |
| import org.onosproject.net.flow.DefaultTrafficSelector; |
| import org.onosproject.net.flow.DefaultTrafficTreatment; |
| import org.onosproject.net.flow.FlowRule; |
| import org.onosproject.net.flow.oldbatch.FlowRuleBatchOperation; |
| import org.onosproject.net.flow.TrafficSelector; |
| import org.onosproject.net.flowobjective.FlowObjectiveServiceAdapter; |
| import org.onosproject.net.flowobjective.ForwardingObjective; |
| import org.onosproject.net.flowobjective.Objective; |
| import org.onosproject.net.packet.DefaultOutboundPacket; |
| 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.provider.ProviderId; |
| import org.onosproject.store.service.StorageService; |
| import org.onosproject.store.service.TestStorageService; |
| |
| import java.nio.ByteBuffer; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Optional; |
| import java.util.Set; |
| import java.util.concurrent.atomic.AtomicLong; |
| |
| import static org.junit.Assert.*; |
| import static org.onosproject.net.flowobjective.Objective.Operation.ADD; |
| import static org.onosproject.net.flowobjective.Objective.Operation.REMOVE; |
| import static org.onosproject.net.packet.PacketPriority.CONTROL; |
| import static org.onosproject.net.packet.PacketPriority.REACTIVE; |
| |
| /** |
| * Junit tests for VirtualNetworkPacketManager using SimpleVirtualPacketStore. |
| */ |
| public class VirtualNetworkPacketManagerTest extends VirtualNetworkTestUtil { |
| |
| private static final int PROCESSOR_PRIORITY = 1; |
| |
| protected VirtualNetworkManager manager; |
| protected DistributedVirtualNetworkStore virtualNetworkManagerStore; |
| private CoreService coreService = new TestCoreService(); |
| protected TestServiceDirectory testDirectory; |
| private EventDeliveryService eventDeliveryService; |
| private VirtualProviderManager providerRegistryService; |
| |
| private VirtualNetwork vnet1; |
| private VirtualNetwork vnet2; |
| |
| private VirtualPacketProvider provider = new TestPacketProvider(); |
| protected VirtualNetworkPacketStore packetStore = new SimpleVirtualPacketStore(); |
| |
| protected VirtualNetworkPacketManager packetManager1; |
| private VirtualNetworkPacketManager packetManager2; |
| |
| private ApplicationId appId = new TestApplicationId("VirtualPacketManagerTest"); |
| |
| private VirtualFlowRuleProvider flowRuleProvider = new TestFlowRuleProvider(); |
| private SimpleVirtualFlowRuleStore flowRuleStore; |
| private SimpleVirtualFlowObjectiveStore flowObjectiveStore; |
| protected StorageService storageService = new TestStorageService(); |
| |
| @Before |
| public void setUp() throws TestUtils.TestUtilsException { |
| virtualNetworkManagerStore = new DistributedVirtualNetworkStore(); |
| |
| TestUtils.setField(virtualNetworkManagerStore, "coreService", coreService); |
| TestUtils.setField(virtualNetworkManagerStore, "storageService", storageService); |
| virtualNetworkManagerStore.activate(); |
| |
| manager = new VirtualNetworkManager(); |
| manager.store = virtualNetworkManagerStore; |
| manager.coreService = coreService; |
| NetTestTools.injectEventDispatcher(manager, new TestEventDispatcher()); |
| |
| flowObjectiveStore = new SimpleVirtualFlowObjectiveStore(); |
| TestUtils.setField(flowObjectiveStore, "storageService", storageService); |
| flowObjectiveStore.activate(); |
| flowRuleStore = new SimpleVirtualFlowRuleStore(); |
| flowRuleStore.activate(); |
| |
| providerRegistryService = new VirtualProviderManager(); |
| providerRegistryService.registerProvider(provider); |
| providerRegistryService.registerProvider(flowRuleProvider); |
| |
| testDirectory = new TestServiceDirectory() |
| .add(VirtualNetworkStore.class, virtualNetworkManagerStore) |
| .add(CoreService.class, coreService) |
| .add(VirtualProviderRegistryService.class, providerRegistryService) |
| .add(EventDeliveryService.class, eventDeliveryService) |
| .add(ClusterService.class, new ClusterServiceAdapter()) |
| .add(VirtualNetworkFlowRuleStore.class, flowRuleStore) |
| .add(VirtualNetworkFlowObjectiveStore.class, flowObjectiveStore) |
| .add(VirtualNetworkPacketStore.class, packetStore); |
| TestUtils.setField(manager, "serviceDirectory", testDirectory); |
| |
| eventDeliveryService = new TestEventDispatcher(); |
| NetTestTools.injectEventDispatcher(manager, eventDeliveryService); |
| |
| manager.activate(); |
| |
| vnet1 = VirtualNetworkTestUtil.setupVirtualNetworkTopology(manager, TID1); |
| vnet2 = VirtualNetworkTestUtil.setupVirtualNetworkTopology(manager, TID2); |
| |
| packetManager1 = new VirtualNetworkPacketManager(manager, vnet1.id()); |
| packetManager2 = new VirtualNetworkPacketManager(manager, vnet2.id()); |
| } |
| |
| /** |
| * Tests the correct usage of addProcessor() for a outbound packet. |
| */ |
| @Test |
| public void addProcessorTest() { |
| PacketProcessor testProcessor = new TestProcessor(); |
| packetManager1.addProcessor(testProcessor, PROCESSOR_PRIORITY); |
| |
| assertEquals("1 processor expected", 1, |
| packetManager1.getProcessors().size()); |
| assertEquals("0 processor expected", 0, |
| packetManager2.getProcessors().size()); |
| |
| assertEquals("not equal packet processor", testProcessor, |
| packetManager1.getProcessors().get(0).processor()); |
| assertEquals("not equal packet processor priority", PROCESSOR_PRIORITY, |
| packetManager1.getProcessors().get(0).priority()); |
| } |
| |
| /** |
| * Tests the correct usage of addProcessor() for a outbound packet. |
| */ |
| @Test |
| public void removeProcessorTest() { |
| PacketProcessor testProcessor = new TestProcessor(); |
| packetManager1.addProcessor(testProcessor, PROCESSOR_PRIORITY); |
| |
| assertEquals("1 processor expected", 1, |
| packetManager1.getProcessors().size()); |
| assertEquals("0 processor expected", 0, |
| packetManager2.getProcessors().size()); |
| |
| packetManager1.removeProcessor(testProcessor); |
| |
| assertEquals("0 processor expected", 0, |
| packetManager1.getProcessors().size()); |
| assertEquals("0 processor expected", 0, |
| packetManager2.getProcessors().size()); |
| } |
| |
| /** |
| * Tests the correct usage of emit() for a outbound packet. |
| */ |
| @Test |
| public void emitTest() { |
| OutboundPacket packet = |
| new DefaultOutboundPacket(VDID1, DefaultTrafficTreatment.emptyTreatment(), ByteBuffer.allocate(5)); |
| packetManager1.emit(packet); |
| assertEquals("Packet not emitted correctly", packet, emittedPacket); |
| } |
| |
| /** |
| * Tests the addition and removal of packet requests for a device. |
| * |
| * @throws TestUtils.TestUtilsException |
| */ |
| @Test |
| public void requestAndCancelPacketsForDeviceTest() throws TestUtils.TestUtilsException { |
| TestFlowObjectiveService testFlowObjectiveService = new TestFlowObjectiveService(); |
| TestUtils.setField(packetManager1, "objectiveService", testFlowObjectiveService); |
| TrafficSelector ts = DefaultTrafficSelector.emptySelector(); |
| Optional<DeviceId> optionalDeviceId = Optional.of(VDID3); |
| |
| // add first request |
| packetManager1.requestPackets(ts, CONTROL, appId, optionalDeviceId); |
| assertEquals("1 packet expected", 1, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, CONTROL, ADD); |
| |
| // add same request as first |
| packetManager1.requestPackets(ts, CONTROL, appId, optionalDeviceId); |
| assertEquals("1 packet expected", 1, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, CONTROL, ADD); |
| |
| // add second request |
| packetManager1.requestPackets(ts, REACTIVE, appId, optionalDeviceId); |
| assertEquals("2 packets expected", 2, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, REACTIVE, ADD); |
| |
| // cancel second request |
| packetManager1.cancelPackets(ts, REACTIVE, appId, optionalDeviceId); |
| assertEquals("1 packet expected", 1, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, REACTIVE, REMOVE); |
| |
| // cancel second request again |
| packetManager1.cancelPackets(ts, REACTIVE, appId, optionalDeviceId); |
| assertEquals("1 packet expected", 1, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, REACTIVE, REMOVE); |
| |
| // cancel first request |
| packetManager1.cancelPackets(ts, CONTROL, appId, optionalDeviceId); |
| assertEquals("0 packet expected", 0, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectiveForDevice(VDID3, ts, CONTROL, REMOVE); |
| } |
| |
| /** |
| * Tests the addition and removal of packet requests for all devices in a virtual |
| * network. |
| * |
| * @throws TestUtils.TestUtilsException |
| */ |
| @Test |
| public void requestAndCancelPacketsForVnetTest() throws TestUtils.TestUtilsException { |
| TestFlowObjectiveService testFlowObjectiveService = new TestFlowObjectiveService(); |
| TestUtils.setField(packetManager1, "objectiveService", testFlowObjectiveService); |
| TrafficSelector ts = DefaultTrafficSelector.emptySelector(); |
| Set<VirtualDevice> vnet1Devices = manager.getVirtualDevices(vnet1.id()); |
| |
| // add first request |
| packetManager1.requestPackets(ts, CONTROL, appId); |
| assertEquals("1 packet expected", 1, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectives(vnet1Devices, ts, CONTROL, ADD); |
| |
| // add same request as first |
| packetManager1.requestPackets(ts, CONTROL, appId); |
| assertEquals("1 packet expected", 1, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectives(vnet1Devices, ts, CONTROL, ADD); |
| |
| // add second request |
| packetManager1.requestPackets(ts, REACTIVE, appId); |
| assertEquals("2 packets expected", 2, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectives(vnet1Devices, ts, REACTIVE, ADD); |
| |
| // cancel second request |
| packetManager1.cancelPackets(ts, REACTIVE, appId); |
| assertEquals("1 packet expected", 1, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectives(vnet1Devices, ts, REACTIVE, REMOVE); |
| |
| // cancel second request again |
| packetManager1.cancelPackets(ts, REACTIVE, appId); |
| assertEquals("1 packet expected", 1, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectives(vnet1Devices, ts, REACTIVE, REMOVE); |
| |
| // cancel first request |
| packetManager1.cancelPackets(ts, CONTROL, appId); |
| assertEquals("0 packet expected", 0, packetManager1.getRequests().size()); |
| testFlowObjectiveService.validateObjectives(vnet1Devices, ts, CONTROL, REMOVE); |
| } |
| |
| protected OutboundPacket emittedPacket = null; |
| |
| /** |
| * Core service test class. |
| */ |
| private class TestCoreService extends CoreServiceAdapter { |
| |
| @Override |
| public IdGenerator getIdGenerator(String topic) { |
| return new IdGenerator() { |
| private AtomicLong counter = new AtomicLong(0); |
| |
| @Override |
| public long getNewId() { |
| return counter.getAndIncrement(); |
| } |
| }; |
| } |
| |
| @Override |
| public ApplicationId registerApplication(String name) { |
| return appId; |
| } |
| } |
| |
| private class TestPacketProvider extends AbstractVirtualProvider |
| implements VirtualPacketProvider { |
| |
| /** |
| * Creates a provider with the supplied identifier. |
| */ |
| protected TestPacketProvider() { |
| super(new ProviderId("test-packet", |
| "org.onosproject.virtual.test-packet")); |
| } |
| |
| @Override |
| public void emit(NetworkId networkId, OutboundPacket packet) { |
| emittedPacket = packet; |
| } |
| |
| } |
| |
| private class TestProcessor implements PacketProcessor { |
| |
| @Override |
| public void process(PacketContext context) { |
| |
| } |
| } |
| |
| private class TestFlowObjectiveService extends FlowObjectiveServiceAdapter { |
| // track objectives received for each device |
| private final Map<DeviceId, Set<ForwardingObjective>> deviceFwdObjs = new HashMap<>(); |
| |
| @Override |
| public void forward(DeviceId deviceId, ForwardingObjective forwardingObjective) { |
| deviceFwdObjs.compute(deviceId, (deviceId1, forwardingObjectives) -> { |
| if (forwardingObjectives == null) { |
| return Sets.newHashSet(forwardingObjective); |
| } |
| forwardingObjectives.add(forwardingObjective); |
| return forwardingObjectives; |
| } |
| ); |
| } |
| |
| private void validateObjectives(Set<VirtualDevice> vdevs, TrafficSelector ts, |
| PacketPriority pp, Objective.Operation op) { |
| assertNotNull("set of devices must not be null", vdevs); |
| for (VirtualDevice vdev: vdevs) { |
| assertTrue("Forwarding objective must exist for device " + vdev.id(), |
| deviceHasObjective(vdev.id(), ts, pp, op)); |
| } |
| } |
| |
| private void validateObjectiveForDevice(DeviceId deviceId, TrafficSelector ts, |
| PacketPriority pp, Objective.Operation op) { |
| assertNotNull("deviceId must not be null", deviceId); |
| assertTrue("Forwarding objective must exist for device " + deviceId, |
| deviceHasObjective(deviceId, ts, pp, op)); |
| } |
| |
| private boolean deviceHasObjective(DeviceId deviceId, TrafficSelector ts, |
| PacketPriority pp, Objective.Operation op) { |
| Set<ForwardingObjective> fos = deviceFwdObjs.get(deviceId); |
| if (fos != null) { |
| for (ForwardingObjective fo: fos) { |
| if (fo.selector().equals(ts) |
| && fo.priority() == pp.priorityValue() |
| && fo.op().equals(op)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| } |
| |
| private class TestFlowRuleProvider extends AbstractVirtualProvider |
| implements VirtualFlowRuleProvider { |
| |
| protected TestFlowRuleProvider() { |
| super(new ProviderId("test", "org.onosproject.virtual.testprovider")); |
| } |
| |
| @Override |
| public void applyFlowRule(NetworkId networkId, FlowRule... flowRules) { |
| |
| } |
| |
| @Override |
| public void removeFlowRule(NetworkId networkId, FlowRule... flowRules) { |
| |
| } |
| |
| @Override |
| public void executeBatch(NetworkId networkId, FlowRuleBatchOperation batch) { |
| |
| } |
| } |
| } |