| /* |
| * 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.net.flowobjective.impl; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.onlab.junit.TestUtils; |
| import org.onlab.packet.ChassisId; |
| import org.onosproject.net.DefaultAnnotations; |
| import org.onosproject.net.DefaultDevice; |
| import org.onosproject.net.Device; |
| import org.onosproject.net.DeviceId; |
| import org.onosproject.net.NetTestTools; |
| import org.onosproject.net.behaviour.DefaultNextGroup; |
| import org.onosproject.net.behaviour.NextGroup; |
| import org.onosproject.net.behaviour.PipelinerAdapter; |
| import org.onosproject.net.behaviour.PipelinerContext; |
| import org.onosproject.net.device.DeviceEvent; |
| import org.onosproject.net.device.DeviceListener; |
| import org.onosproject.net.device.DeviceServiceAdapter; |
| import org.onosproject.net.driver.AbstractDriverLoader; |
| import org.onosproject.net.driver.Behaviour; |
| import org.onosproject.net.driver.DefaultDriverData; |
| import org.onosproject.net.driver.DefaultDriverHandler; |
| import org.onosproject.net.driver.DefaultDriverProviderService; |
| import org.onosproject.net.driver.Driver; |
| import org.onosproject.net.driver.DriverAdapter; |
| import org.onosproject.net.driver.DriverData; |
| import org.onosproject.net.driver.DriverHandler; |
| import org.onosproject.net.driver.DriverServiceAdapter; |
| 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.flow.criteria.Criteria; |
| import org.onosproject.net.flowobjective.DefaultFilteringObjective; |
| import org.onosproject.net.flowobjective.DefaultForwardingObjective; |
| import org.onosproject.net.flowobjective.DefaultNextObjective; |
| import org.onosproject.net.flowobjective.FilteringObjective; |
| import org.onosproject.net.flowobjective.FlowObjectiveStoreDelegate; |
| import org.onosproject.net.flowobjective.ForwardingObjective; |
| import org.onosproject.net.flowobjective.NextObjective; |
| import org.onosproject.net.flowobjective.ObjectiveEvent; |
| import org.onosproject.net.intent.TestTools; |
| |
| import static org.hamcrest.CoreMatchers.hasItem; |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.hamcrest.Matchers.hasSize; |
| import static org.hamcrest.Matchers.notNullValue; |
| import static org.onlab.junit.TestUtils.TestUtilsException; |
| |
| /** |
| * Tests for the flow objective manager. |
| */ |
| public class FlowObjectiveManagerTest { |
| |
| private static final int RETRY_MS = 250; |
| private FlowObjectiveManager manager; |
| DeviceId id1 = NetTestTools.did("d1"); |
| DefaultDevice d1 = new DefaultDevice(NetTestTools.PID, id1, Device.Type.SWITCH, |
| "test", "1.0", "1.0", |
| "abacab", new ChassisId("c"), |
| DefaultAnnotations.EMPTY); |
| |
| DeviceId id2 = NetTestTools.did("d2"); |
| DefaultDevice d2 = new DefaultDevice(NetTestTools.PID, id2, Device.Type.SWITCH, |
| "test", "1.0", "1.0", |
| "abacab", new ChassisId("c"), |
| DefaultAnnotations.EMPTY); |
| |
| List<String> filteringObjectives; |
| List<String> forwardingObjectives; |
| List<String> nextObjectives; |
| |
| private class TestDeviceService extends DeviceServiceAdapter { |
| |
| List<Device> deviceList; |
| |
| TestDeviceService() { |
| deviceList = new ArrayList<>(); |
| |
| deviceList.add(d1); |
| } |
| |
| @Override |
| public Iterable<Device> getDevices() { |
| return deviceList; |
| } |
| |
| @Override |
| public boolean isAvailable(DeviceId deviceId) { |
| return true; |
| } |
| } |
| |
| private class TestFlowObjectiveStore extends FlowObjectiveStoreAdapter { |
| @Override |
| public NextGroup getNextGroup(Integer nextId) { |
| if (nextId != 4) { |
| byte[] data = new byte[1]; |
| data[0] = 5; |
| return new DefaultNextGroup(data); |
| } else { |
| return null; |
| } |
| } |
| |
| } |
| |
| private class TestDriversLoader extends AbstractDriverLoader implements DefaultDriverProviderService { |
| public TestDriversLoader() { |
| super("/onos-drivers.xml"); |
| } |
| } |
| |
| private class TestDriver extends DriverAdapter { |
| |
| @Override |
| public boolean hasBehaviour(Class<? extends Behaviour> behaviourClass) { |
| return true; |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <T extends Behaviour> T createBehaviour(DriverData data, Class<T> behaviourClass) { |
| return (T) new TestPipeliner(); |
| } |
| |
| @Override |
| @SuppressWarnings("unchecked") |
| public <T extends Behaviour> T createBehaviour(DriverHandler handler, Class<T> behaviourClass) { |
| return (T) new TestPipeliner(); |
| } |
| |
| } |
| |
| private class TestPipeliner extends PipelinerAdapter { |
| DeviceId deviceId; |
| |
| @Override |
| public void init(DeviceId deviceId, PipelinerContext context) { |
| this.deviceId = deviceId; |
| } |
| |
| @Override |
| public void filter(FilteringObjective filterObjective) { |
| filteringObjectives.add(deviceId.toString()); |
| } |
| |
| @Override |
| public void forward(ForwardingObjective forwardObjective) { |
| forwardingObjectives.add(deviceId.toString()); |
| } |
| |
| @Override |
| public void next(NextObjective nextObjective) { |
| nextObjectives.add(deviceId.toString()); |
| } |
| } |
| |
| private class TestDriverService extends DriverServiceAdapter { |
| @Override |
| public DriverHandler createHandler(DeviceId deviceId, String... credentials) { |
| Driver driver = new TestDriver(); |
| return new DefaultDriverHandler(new DefaultDriverData(driver, id1)); |
| } |
| } |
| |
| @Before |
| public void initializeTest() { |
| manager = new FlowObjectiveManager(); |
| manager.flowObjectiveStore = new TestFlowObjectiveStore(); |
| manager.deviceService = new TestDeviceService(); |
| manager.defaultDriverService = new TestDriversLoader(); |
| manager.driverService = new TestDriverService(); |
| |
| filteringObjectives = new ArrayList<>(); |
| forwardingObjectives = new ArrayList<>(); |
| nextObjectives = new ArrayList<>(); |
| manager.activate(); |
| } |
| |
| @After |
| public void tearDownTest() { |
| manager.deactivate(); |
| manager = null; |
| filteringObjectives.clear(); |
| forwardingObjectives.clear(); |
| nextObjectives.clear(); |
| } |
| |
| /** |
| * Tests adding a forwarding objective. |
| */ |
| @Test |
| public void forwardingObjective() { |
| TrafficSelector selector = DefaultTrafficSelector.emptySelector(); |
| TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); |
| ForwardingObjective forward = |
| DefaultForwardingObjective.builder() |
| .fromApp(NetTestTools.APP_ID) |
| .withFlag(ForwardingObjective.Flag.SPECIFIC) |
| .withSelector(selector) |
| .withTreatment(treatment) |
| .makePermanent() |
| .add(); |
| |
| manager.forward(id1, forward); |
| |
| TestTools.assertAfter(RETRY_MS, () -> |
| assertThat(forwardingObjectives, hasSize(1))); |
| |
| assertThat(forwardingObjectives, hasItem("of:d1")); |
| assertThat(filteringObjectives, hasSize(0)); |
| assertThat(nextObjectives, hasSize(0)); |
| } |
| |
| /** |
| * Tests adding a filtering objective. |
| */ |
| @Test |
| public void filteringObjective() { |
| TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); |
| FilteringObjective filter = |
| DefaultFilteringObjective.builder() |
| .fromApp(NetTestTools.APP_ID) |
| .withMeta(treatment) |
| .makePermanent() |
| .deny() |
| .addCondition(Criteria.matchEthType(12)) |
| .add(); |
| |
| manager.activate(); |
| manager.filter(id1, filter); |
| |
| TestTools.assertAfter(RETRY_MS, () -> |
| assertThat(filteringObjectives, hasSize(1))); |
| |
| assertThat(forwardingObjectives, hasSize(0)); |
| assertThat(filteringObjectives, hasItem("of:d1")); |
| assertThat(nextObjectives, hasSize(0)); |
| } |
| |
| /** |
| * Tests adding a next objective. |
| */ |
| @Test |
| public void nextObjective() { |
| TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); |
| NextObjective next = |
| DefaultNextObjective.builder() |
| .withId(manager.allocateNextId()) |
| .addTreatment(treatment) |
| .withType(NextObjective.Type.BROADCAST) |
| .fromApp(NetTestTools.APP_ID) |
| .makePermanent() |
| .add(); |
| |
| manager.next(id1, next); |
| |
| TestTools.assertAfter(RETRY_MS, () -> |
| assertThat(nextObjectives, hasSize(1))); |
| |
| assertThat(forwardingObjectives, hasSize(0)); |
| assertThat(filteringObjectives, hasSize(0)); |
| assertThat(nextObjectives, hasItem("of:d1")); |
| } |
| |
| /** |
| * Tests adding a pending forwarding objective. |
| * |
| * @throws TestUtilsException if lookup of a field fails |
| */ |
| @Test |
| public void pendingForwardingObjective() throws TestUtilsException { |
| TrafficSelector selector = DefaultTrafficSelector.emptySelector(); |
| TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); |
| |
| ForwardingObjective forward4 = |
| DefaultForwardingObjective.builder() |
| .fromApp(NetTestTools.APP_ID) |
| .withFlag(ForwardingObjective.Flag.SPECIFIC) |
| .withSelector(selector) |
| .withTreatment(treatment) |
| .makePermanent() |
| .nextStep(4) |
| .add(); |
| ForwardingObjective forward5 = |
| DefaultForwardingObjective.builder() |
| .fromApp(NetTestTools.APP_ID) |
| .withFlag(ForwardingObjective.Flag.SPECIFIC) |
| .withSelector(selector) |
| .withTreatment(treatment) |
| .makePermanent() |
| .nextStep(5) |
| .add(); |
| |
| // multiple pending forwards should be combined |
| manager.forward(id1, forward4); |
| manager.forward(id1, forward4); |
| manager.forward(id1, forward5); |
| |
| |
| // 1 should be complete, 1 pending |
| TestTools.assertAfter(RETRY_MS, () -> |
| assertThat(forwardingObjectives, hasSize(1))); |
| |
| assertThat(forwardingObjectives, hasItem("of:d1")); |
| assertThat(filteringObjectives, hasSize(0)); |
| assertThat(nextObjectives, hasSize(0)); |
| |
| // Now send events to trigger the objective still in the queue |
| ObjectiveEvent event1 = new ObjectiveEvent(ObjectiveEvent.Type.ADD, 4); |
| FlowObjectiveStoreDelegate delegate = TestUtils.getField(manager, "delegate"); |
| delegate.notify(event1); |
| |
| // all should be processed now |
| TestTools.assertAfter(RETRY_MS, () -> |
| assertThat(forwardingObjectives, hasSize(2))); |
| assertThat(forwardingObjectives, hasItem("of:d1")); |
| assertThat(filteringObjectives, hasSize(0)); |
| assertThat(nextObjectives, hasSize(0)); |
| } |
| |
| /** |
| * Tests receipt of a device up event. |
| * |
| * @throws TestUtilsException if lookup of a field fails |
| */ |
| @Test |
| public void deviceUpEvent() throws TestUtilsException { |
| TrafficSelector selector = DefaultTrafficSelector.emptySelector(); |
| TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); |
| |
| DeviceEvent event = new DeviceEvent(DeviceEvent.Type.DEVICE_ADDED, d2); |
| DeviceListener listener = TestUtils.getField(manager, "deviceListener"); |
| assertThat(listener, notNullValue()); |
| |
| listener.event(event); |
| |
| ForwardingObjective forward = |
| DefaultForwardingObjective.builder() |
| .fromApp(NetTestTools.APP_ID) |
| .withFlag(ForwardingObjective.Flag.SPECIFIC) |
| .withSelector(selector) |
| .withTreatment(treatment) |
| .makePermanent() |
| .add(); |
| manager.forward(id2, forward); |
| |
| // new device should have an objective now |
| TestTools.assertAfter(RETRY_MS, () -> |
| assertThat(forwardingObjectives, hasSize(1))); |
| |
| assertThat(forwardingObjectives, hasItem("of:d2")); |
| assertThat(filteringObjectives, hasSize(0)); |
| assertThat(nextObjectives, hasSize(0)); |
| } |
| } |