/* * 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.optical.intent.impl.compiler; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import org.easymock.EasyMock; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.onlab.packet.ChassisId; import org.onosproject.TestApplicationId; import org.onosproject.cfg.ComponentConfigService; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.AbstractProjectableModel; import org.onosproject.net.Annotations; import org.onosproject.net.ChannelSpacing; import org.onosproject.net.CltSignalType; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DefaultDevice; import org.onosproject.net.DefaultPort; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.OchSignal; import org.onosproject.net.OduSignalId; import org.onosproject.net.OduSignalType; import org.onosproject.net.OduSignalUtils; import org.onosproject.net.Port; import org.onosproject.net.PortNumber; import org.onosproject.net.TributarySlot; import org.onosproject.net.behaviour.TributarySlotQuery; import org.onosproject.net.device.DeviceServiceAdapter; import org.onosproject.net.driver.Behaviour; import org.onosproject.net.driver.DefaultDriver; import org.onosproject.net.driver.Driver; import org.onosproject.net.driver.DriverHandler; import org.onosproject.net.driver.DriverService; import org.onosproject.net.driver.DriverServiceAdapter; import org.onosproject.net.driver.TestBehaviourImpl; import org.onosproject.net.driver.TestBehaviourTwoImpl; import org.onosproject.net.flow.DefaultTrafficSelector; import org.onosproject.net.flow.DefaultTrafficTreatment; import org.onosproject.net.flow.FlowRule; import org.onosproject.net.flow.TrafficSelector; import org.onosproject.net.flow.TrafficTreatment; import org.onosproject.net.flow.criteria.Criteria; import org.onosproject.net.flow.instructions.Instructions; import org.onosproject.net.intent.AbstractIntentTest; import org.onosproject.net.intent.FlowRuleIntent; import org.onosproject.net.intent.Intent; import org.onosproject.net.intent.IntentExtensionService; import org.onosproject.net.intent.IntentId; import org.onosproject.net.intent.IntentServiceAdapter; import org.onosproject.net.intent.IntentSetMultimap; import org.onosproject.net.intent.Key; import org.onosproject.net.intent.OpticalCircuitIntent; import org.onosproject.net.optical.OchPort; import org.onosproject.net.optical.OduCltPort; import org.onosproject.net.optical.impl.DefaultOchPort; import org.onosproject.net.optical.impl.DefaultOduCltPort; import org.onosproject.net.provider.ProviderId; import org.onosproject.net.resource.MockResourceService; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; import static org.easymock.EasyMock.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertEquals; import static org.onosproject.net.AnnotationKeys.PORT_NAME; import static org.onosproject.net.AnnotationKeys.STATIC_PORT; import static org.onosproject.net.Device.Type.ROADM; import static org.onosproject.net.DeviceId.deviceId; import static org.onosproject.net.NetTestTools.APP_ID; public class OpticalCircuitIntentCompilerTest extends AbstractIntentTest { private static final String DEV1 = "of:1"; private static final String DEV2 = "of:2"; static final Key KEY1 = Key.of(5L, APP_ID); private static final String STATIC_TRUE = "true"; private static final String PNAME = "p2"; private CoreService coreService; private IntentExtensionService intentExtensionService; private OpticalCircuitIntentCompiler sut; private final ApplicationId appId = new TestApplicationId("test"); private static Device device1 = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), ROADM, "m", "h", "s", "n", new ChassisId(0L)); private static Device device2 = new DefaultDevice(ProviderId.NONE, deviceId(DEV2), ROADM, "m", "h", "s", "n", new ChassisId(1L)); private static Annotations annotations1 = DefaultAnnotations.builder().set(STATIC_PORT, STATIC_TRUE).build(); private static Annotations annotations2 = DefaultAnnotations.builder().set(PORT_NAME, PNAME).build(); // OduClt ports with signalType=1GBE private static final OduCltPort D1P1 = new DefaultOduCltPort(new DefaultPort(device1, PortNumber.portNumber(1), true, annotations1), CltSignalType.CLT_1GBE); private static final OduCltPort D2P1 = new DefaultOduCltPort(new DefaultPort(device2, PortNumber.portNumber(1), true, annotations1), CltSignalType.CLT_1GBE); // Och ports with signalType=ODU2 private static final OchPort D1P2 = new DefaultOchPort(new DefaultPort(device1, PortNumber.portNumber(2), true, annotations2), OduSignalType.ODU2, true, OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1)); private static final OchPort D2P2 = new DefaultOchPort(new DefaultPort(device2, PortNumber.portNumber(2), true, annotations2), OduSignalType.ODU2, true, OchSignal.newDwdmSlot(ChannelSpacing.CHL_50GHZ, 1)); // OduClt ports with signalType=10GBE private static final OduCltPort D1P3 = new DefaultOduCltPort(new DefaultPort(device1, PortNumber.portNumber(3), true, annotations1), CltSignalType.CLT_10GBE); private static final OduCltPort D2P3 = new DefaultOduCltPort(new DefaultPort(device2, PortNumber.portNumber(3), true, annotations1), CltSignalType.CLT_10GBE); private OpticalCircuitIntent intent; /** * Mocks the device service so that devices and ports appear available in the test. */ private static class MockDeviceService extends DeviceServiceAdapter { @Override public boolean isAvailable(DeviceId deviceId) { return true; } @Override public List<Port> getPorts(DeviceId deviceId) { if (deviceId.equals(deviceId(DEV1))) { return ImmutableList.of((Port) D1P1, (Port) D1P2, (Port) D1P3); } if (deviceId.equals(deviceId(DEV2))) { return ImmutableList.of((Port) D2P1, (Port) D2P2, (Port) D2P3); } return Collections.emptyList(); } @Override public Port getPort(DeviceId deviceId, PortNumber portNumber) { if (deviceId.equals(deviceId(DEV1))) { switch (portNumber.toString()) { case "1": return D1P1; case "2": return D1P2; case "3": return D1P3; default: return null; } } if (deviceId.equals(deviceId(DEV2))) { switch (portNumber.toString()) { case "1": return D2P1; case "2": return D2P2; case "3": return D2P3; default: return null; } } return null; } } /** * Mocks the driver service so it will appear supporting TributarySlotQuery Behaviour in the test. */ private static class MockDriverServiceWithTs implements DriverService { @Override public Driver getDriver(String driverName) { // TODO Auto-generated method stub return null; } @Override public Set<Driver> getDrivers() { // TODO Auto-generated method stub return null; } @Override public Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour) { // TODO Auto-generated method stub return null; } @Override public Driver getDriver(String mfr, String hw, String sw) { // TODO Auto-generated method stub return null; } @Override public Driver getDriver(DeviceId deviceId) { DefaultDriver ddp = new DefaultDriver("foo.base", new ArrayList<>(), "Circus", "lux", "1.2a", ImmutableMap.of(Behaviour.class, TestBehaviourImpl.class, TributarySlotQuery.class, TestBehaviourTwoImpl.class), ImmutableMap.of("foo", "bar")); return ddp; } @Override public DriverHandler createHandler(DeviceId deviceId, String... credentials) { // TODO Auto-generated method stub return null; } } /** * Mocks the driver service so it will appear not-supporting TributarySlotQuery Behaviour in the test. */ private static class MockDriverServiceNoTs implements DriverService { @Override public Driver getDriver(String driverName) { // TODO Auto-generated method stub return null; } @Override public Set<Driver> getDrivers() { // TODO Auto-generated method stub return null; } @Override public Set<Driver> getDrivers(Class<? extends Behaviour> withBehaviour) { // TODO Auto-generated method stub return null; } @Override public Driver getDriver(String mfr, String hw, String sw) { // TODO Auto-generated method stub return null; } @Override public Driver getDriver(DeviceId deviceId) { DefaultDriver ddp = new DefaultDriver("foo.base", new ArrayList<>(), "Circus", "lux", "1.2a", ImmutableMap.of(Behaviour.class, TestBehaviourImpl.class), ImmutableMap.of("foo", "bar")); return ddp; } @Override public DriverHandler createHandler(DeviceId deviceId, String... credentials) { // TODO Auto-generated method stub return null; } } private static class MockIntentSetMultimap implements IntentSetMultimap { @Override public boolean allocateMapping(IntentId keyIntentId, IntentId valIntentId) { // TODO Auto-generated method stub return false; } @Override public Set<IntentId> getMapping(IntentId intentId) { // TODO Auto-generated method stub return null; } @Override public void releaseMapping(IntentId intentId) { // TODO Auto-generated method stub } } /** * Represents a fake IntentService class that easily allows to store and * retrieve intents without implementing the IntentService logic. */ private class TestIntentService extends IntentServiceAdapter { private Set<Intent> intents; public TestIntentService() { intents = Sets.newHashSet(); } @Override public void submit(Intent intent) { intents.add(intent); } @Override public long getIntentCount() { return intents.size(); } @Override public Iterable<Intent> getIntents() { return intents; } @Override public Intent getIntent(Key intentKey) { for (Intent intent : intents) { if (intent.key().equals(intentKey)) { return intent; } } return null; } } @BeforeClass public static void setUpClass() { AbstractProjectableModel.setDriverService("key", new DriverServiceAdapter()); } @Before public void setUp() { sut = new OpticalCircuitIntentCompiler(); coreService = createMock(CoreService.class); expect(coreService.registerApplication("org.onosproject.net.intent")) .andReturn(appId); sut.coreService = coreService; sut.deviceService = new MockDeviceService(); sut.resourceService = new MockResourceService(); sut.intentService = new TestIntentService(); sut.intentSetMultimap = new MockIntentSetMultimap(); super.setUp(); intentExtensionService = createMock(IntentExtensionService.class); intentExtensionService.registerCompiler(OpticalCircuitIntent.class, sut); intentExtensionService.unregisterCompiler(OpticalCircuitIntent.class); sut.intentManager = intentExtensionService; replay(coreService, intentExtensionService); // mocking ComponentConfigService ComponentConfigService mockConfigService = EasyMock.createMock(ComponentConfigService.class); expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of()); mockConfigService.registerProperties(sut.getClass()); expectLastCall(); mockConfigService.unregisterProperties(sut.getClass(), false); expectLastCall(); expect(mockConfigService.getProperties(anyObject())).andReturn(ImmutableSet.of()); sut.cfgService = mockConfigService; replay(mockConfigService); } /** * Tests compile of OpticalCircuitIntent with allocation of TributarySlots. * Compile two ODUCLT ports (with CLT_1GBE), over OCH ports (with ODU2): * - only one TributarySlot is used */ @Test public void test1GbeMultiplexOverOdu2() { // Use driver with TributarySlotQuery Behaviour sut.driverService = new MockDriverServiceWithTs(); ConnectPoint oduCltSrcCP = new ConnectPoint(device1.id(), D1P1.number()); ConnectPoint oduCltDstCP = new ConnectPoint(device2.id(), D2P1.number()); ConnectPoint ochSrcCP = new ConnectPoint(device1.id(), D1P2.number()); ConnectPoint ochDstCP = new ConnectPoint(device2.id(), D2P2.number()); intent = OpticalCircuitIntent.builder() .appId(APP_ID) .key(KEY1) .src(oduCltSrcCP) .dst(oduCltDstCP) .signalType(D1P1.signalType()) .bidirectional(false) .build(); sut.activate(null); List<Intent> compiled = sut.compile(intent, Collections.emptyList()); assertThat(compiled, hasSize(1)); assertThat("key is inherited", compiled.stream().map(Intent::key).collect(Collectors.toList()), everyItem(is(intent.key()))); Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); FlowRule rule1 = rules.stream() .filter(x -> x.deviceId().equals(device1.id())) .findFirst() .get(); // validate SRC selector TrafficSelector.Builder selectorBuilder1 = DefaultTrafficSelector.builder(); selectorBuilder1.matchInPort(oduCltSrcCP.port()); selectorBuilder1.add(Criteria.matchOduSignalType(OduSignalType.ODU0)); assertThat(rule1.selector(), is(selectorBuilder1.build())); // validate SRC treatment (with OduSignalId, where 1 TributarySlot is used) TrafficTreatment.Builder treatmentBuilder1 = DefaultTrafficTreatment.builder(); Set<TributarySlot> slots = new HashSet<>(); slots.add(TributarySlot.of(1)); OduSignalId oduSignalId = OduSignalUtils.buildOduSignalId(D1P2.signalType(), slots); treatmentBuilder1.add(Instructions.modL1OduSignalId(oduSignalId)); treatmentBuilder1.setOutput(ochSrcCP.port()); assertThat(rule1.treatment(), is(treatmentBuilder1.build())); FlowRule rule2 = rules.stream() .filter(x -> x.deviceId().equals(device2.id())) .findFirst() .get(); // validate DST selector (with OduSignalId, where the same TributarySlot is used) TrafficSelector.Builder selectorBuilder2 = DefaultTrafficSelector.builder(); selectorBuilder2.matchInPort(ochDstCP.port()); selectorBuilder2.add(Criteria.matchOduSignalType(OduSignalType.ODU0)); selectorBuilder2.add(Criteria.matchOduSignalId(oduSignalId)); assertThat(rule2.selector(), is(selectorBuilder2.build())); // validate DST treatment assertThat(rule2.treatment(), is( DefaultTrafficTreatment.builder().setOutput(oduCltDstCP.port()).build() )); rules.forEach(rule -> assertEquals("FlowRule priority is incorrect", intent.priority(), rule.priority())); sut.deactivate(); } /** * Tests compile of OpticalCircuitIntent with allocation of TributarySlots. * Compile two ODUCLT ports (with CLT_10GBE), over OCH ports (with ODU2): * - All TributarySlots are used */ @Test public void test10GbeMultiplexOverOdu2() { // Use driver with TributarySlotQuery Behaviour sut.driverService = new MockDriverServiceWithTs(); ConnectPoint oduCltSrcCP = new ConnectPoint(device1.id(), D1P3.number()); ConnectPoint oduCltDstCP = new ConnectPoint(device2.id(), D2P3.number()); ConnectPoint ochSrcCP = new ConnectPoint(device1.id(), D1P2.number()); ConnectPoint ochDstCP = new ConnectPoint(device2.id(), D2P2.number()); intent = OpticalCircuitIntent.builder() .appId(APP_ID) .key(KEY1) .src(oduCltSrcCP) .dst(oduCltDstCP) .signalType(D1P3.signalType()) .bidirectional(false) .build(); sut.activate(null); List<Intent> compiled = sut.compile(intent, Collections.emptyList()); assertThat(compiled, hasSize(1)); assertThat("key is inherited", compiled.stream().map(Intent::key).collect(Collectors.toList()), everyItem(is(intent.key()))); Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); FlowRule rule1 = rules.stream() .filter(x -> x.deviceId().equals(device1.id())) .findFirst() .get(); // validate SRC selector TrafficSelector.Builder selectorBuilder1 = DefaultTrafficSelector.builder(); selectorBuilder1.matchInPort(oduCltSrcCP.port()); selectorBuilder1.add(Criteria.matchOduSignalType(OduSignalType.ODU2)); assertThat(rule1.selector(), is(selectorBuilder1.build())); // validate SRC treatment (without OduSignalId, i.e. All TributarySlots are used) TrafficTreatment.Builder treatmentBuilder1 = DefaultTrafficTreatment.builder(); treatmentBuilder1.setOutput(ochSrcCP.port()); assertThat(rule1.treatment(), is(treatmentBuilder1.build())); FlowRule rule2 = rules.stream() .filter(x -> x.deviceId().equals(device2.id())) .findFirst() .get(); // validate DST selector (without OduSignalId, i.e. All TributarySlots are used) TrafficSelector.Builder selectorBuilder2 = DefaultTrafficSelector.builder(); selectorBuilder2.matchInPort(ochDstCP.port()); selectorBuilder2.add(Criteria.matchOduSignalType(OduSignalType.ODU2)); assertThat(rule2.selector(), is(selectorBuilder2.build())); // validate DST treatment assertThat(rule2.treatment(), is( DefaultTrafficTreatment.builder().setOutput(oduCltDstCP.port()).build() )); rules.forEach(rule -> assertEquals("FlowRule priority is incorrect", intent.priority(), rule.priority())); sut.deactivate(); } /** * Tests compile of OpticalCircuitIntent without allocation of TributarySlots. * Compile two ODUCLT ports (with CLT_10GBE), over OCH ports (with ODU2): * - No TributarySlots are used */ @Test public void test10GbeNoMuxOverOdu2() { // Use driver without support for TributarySlotQuery Behaviour sut.driverService = new MockDriverServiceNoTs(); ConnectPoint oduCltSrcCP = new ConnectPoint(device1.id(), D1P3.number()); ConnectPoint oduCltDstCP = new ConnectPoint(device2.id(), D2P3.number()); ConnectPoint ochSrcCP = new ConnectPoint(device1.id(), D1P2.number()); ConnectPoint ochDstCP = new ConnectPoint(device2.id(), D2P2.number()); intent = OpticalCircuitIntent.builder() .appId(APP_ID) .key(KEY1) .src(oduCltSrcCP) .dst(oduCltDstCP) .signalType(D1P3.signalType()) .bidirectional(false) .build(); sut.activate(null); List<Intent> compiled = sut.compile(intent, Collections.emptyList()); assertThat(compiled, hasSize(1)); assertThat("key is inherited", compiled.stream().map(Intent::key).collect(Collectors.toList()), everyItem(is(intent.key()))); Collection<FlowRule> rules = ((FlowRuleIntent) compiled.get(0)).flowRules(); FlowRule rule1 = rules.stream() .filter(x -> x.deviceId().equals(device1.id())) .findFirst() .get(); // validate SRC selector TrafficSelector.Builder selectorBuilder1 = DefaultTrafficSelector.builder(); selectorBuilder1.matchInPort(oduCltSrcCP.port()); assertThat(rule1.selector(), is(selectorBuilder1.build())); // validate SRC treatment (without OduSignalType and OduSignalId: i.e. No TributarySlots are used) TrafficTreatment.Builder treatmentBuilder1 = DefaultTrafficTreatment.builder(); treatmentBuilder1.setOutput(ochSrcCP.port()); assertThat(rule1.treatment(), is(treatmentBuilder1.build())); FlowRule rule2 = rules.stream() .filter(x -> x.deviceId().equals(device2.id())) .findFirst() .get(); // validate DST selector (without OduSignalType and OduSignalId: i.e. No TributarySlots are used) TrafficSelector.Builder selectorBuilder2 = DefaultTrafficSelector.builder(); selectorBuilder2.matchInPort(ochDstCP.port()); assertThat(rule2.selector(), is(selectorBuilder2.build())); // validate DST treatment assertThat(rule2.treatment(), is( DefaultTrafficTreatment.builder().setOutput(oduCltDstCP.port()).build() )); rules.forEach(rule -> assertEquals("FlowRule priority is incorrect", intent.priority(), rule.priority())); sut.deactivate(); } }