/* * 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.Sets; import org.junit.Before; import org.junit.Test; import org.onlab.packet.ChassisId; import org.onosproject.TestApplicationId; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.net.AbstractProjectableModel; import org.onosproject.net.Annotations; import org.onosproject.net.CltSignalType; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DefaultAnnotations; import org.onosproject.net.DefaultDevice; import org.onosproject.net.DefaultLink; import org.onosproject.net.DefaultPath; import org.onosproject.net.DefaultPort; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Link; import org.onosproject.net.OduSignalId; import org.onosproject.net.OduSignalType; import org.onosproject.net.OduSignalUtils; import org.onosproject.net.OtuSignalType; import org.onosproject.net.Path; import org.onosproject.net.Port; import org.onosproject.net.PortNumber; import org.onosproject.net.TributarySlot; import org.onosproject.net.device.DeviceServiceAdapter; import org.onosproject.net.driver.DriverService; import org.onosproject.net.driver.DriverServiceAdapter; 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.Key; import org.onosproject.net.intent.OpticalOduIntent; import org.onosproject.net.optical.OduCltPort; import org.onosproject.net.optical.OtuPort; import org.onosproject.net.optical.impl.DefaultOduCltPort; import org.onosproject.net.optical.impl.DefaultOtuPort; import org.onosproject.net.provider.ProviderId; import org.onosproject.net.resource.MockResourceService; import org.onosproject.net.topology.LinkWeight; import org.onosproject.net.topology.Topology; import org.onosproject.net.topology.TopologyServiceAdapter; import java.util.Arrays; 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.OTN; import static org.onosproject.net.DeviceId.deviceId; import static org.onosproject.net.Link.Type.OPTICAL; import static org.onosproject.net.NetTestTools.APP_ID; import static org.onosproject.net.NetTestTools.PID; public class OpticalOduIntentCompilerTest extends AbstractIntentTest { private static final String DEV1 = "of:1"; private static final String DEV2 = "of:2"; private static final String DEV3 = "of:3"; 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 OpticalOduIntentCompiler sut; private final ApplicationId appId = new TestApplicationId("test"); private static Device device1 = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), OTN, "m", "h", "s", "n", new ChassisId(0L)); private static Device device2 = new DefaultDevice(ProviderId.NONE, deviceId(DEV2), OTN, "m", "h", "s", "n", new ChassisId(1L)); private static Device device3 = new DefaultDevice(ProviderId.NONE, deviceId(DEV3), OTN, "m", "h", "s", "n", new ChassisId(2L)); 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 D3P2 = new DefaultOduCltPort(new DefaultPort(device3, PortNumber.portNumber(2), true, annotations1), CltSignalType.CLT_1GBE); // Otu ports with signalType=ODU2 private static final OtuPort D1P2 = new DefaultOtuPort(new DefaultPort(device1, PortNumber.portNumber(2), true, annotations2), OtuSignalType.OTU2); private static final OtuPort D2P1 = new DefaultOtuPort(new DefaultPort(device2, PortNumber.portNumber(1), true, annotations2), OtuSignalType.OTU2); private static final OtuPort D2P2 = new DefaultOtuPort(new DefaultPort(device2, PortNumber.portNumber(2), true, annotations2), OtuSignalType.OTU2); private static final OtuPort D3P1 = new DefaultOtuPort(new DefaultPort(device3, PortNumber.portNumber(1), true, annotations2), OtuSignalType.OTU2); // 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 D3P3 = new DefaultOduCltPort(new DefaultPort(device3, PortNumber.portNumber(3), true, annotations1), CltSignalType.CLT_10GBE); // OduCltPort ConnectPoints private final ConnectPoint d1p1 = new ConnectPoint(device1.id(), D1P1.number()); private final ConnectPoint d1p3 = new ConnectPoint(device1.id(), D1P3.number()); private final ConnectPoint d3p2 = new ConnectPoint(device3.id(), D3P2.number()); private final ConnectPoint d3p3 = new ConnectPoint(device3.id(), D3P3.number()); // OtuPort ConnectPoints private final ConnectPoint d1p2 = new ConnectPoint(device1.id(), D1P2.number()); private final ConnectPoint d2p1 = new ConnectPoint(device2.id(), D2P1.number()); private final ConnectPoint d2p2 = new ConnectPoint(device2.id(), D2P2.number()); private final ConnectPoint d3p1 = new ConnectPoint(device3.id(), D3P1.number()); private final List<Link> links = Arrays.asList( DefaultLink.builder().providerId(PID).src(d1p2).dst(d2p1).type(OPTICAL).build(), DefaultLink.builder().providerId(PID).src(d2p2).dst(d3p1).type(OPTICAL).build() ); private final Path path = new DefaultPath(PID, links, 3); private OpticalOduIntent intent; /** * Mocks the topology service to give paths in the test. */ private class MockTopologyService extends TopologyServiceAdapter { Set<Path> paths = Sets.newHashSet(path); @Override public Topology currentTopology() { return null; } @Override public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst, LinkWeight weight) { return paths; } } /** * 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); } if (deviceId.equals(deviceId(DEV3))) { return ImmutableList.of((Port) D3P1, (Port) D3P2, (Port) D3P3); } 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; default: return null; } } if (deviceId.equals(deviceId(DEV3))) { switch (portNumber.toString()) { case "1": return D3P1; case "2": return D3P2; case "3": return D3P3; default: return null; } } return null; } } private static class MockDriverService extends DriverServiceAdapter implements DriverService { // TODO override to return appropriate driver, // with DefaultOpticalDevice support, etc. } @Before public void setUp() { AbstractProjectableModel.setDriverService(null, new MockDriverService()); sut = new OpticalOduIntentCompiler(); 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.topologyService = new MockTopologyService(); super.setUp(); intentExtensionService = createMock(IntentExtensionService.class); intentExtensionService.registerCompiler(OpticalOduIntent.class, sut); intentExtensionService.unregisterCompiler(OpticalOduIntent.class); sut.intentManager = intentExtensionService; replay(coreService, intentExtensionService); } /** * Tests compile of OpticalOduIntent with allocation of TributarySlots. * Compile two ODUCLT ports (with CLT_1GBE), over OTU ports (with OTU2): * - only one TributarySlot is used */ @Test public void test1GbeMultiplexOverOdu2() { intent = OpticalOduIntent.builder() .appId(APP_ID) .key(KEY1) .src(d1p1) .dst(d3p2) .signalType(D1P1.signalType()) .bidirectional(false) .build(); sut.activate(); 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(); // 1st Device FlowRule rule1 = rules.stream() .filter(x -> x.deviceId().equals(device1.id())) .findFirst() .get(); // validate SRC selector TrafficSelector.Builder selectorBuilder1 = DefaultTrafficSelector.builder(); selectorBuilder1.matchInPort(d1p1.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(OduSignalType.ODU2, slots); treatmentBuilder1.add(Instructions.modL1OduSignalId(oduSignalId)); treatmentBuilder1.setOutput(d1p2.port()); assertThat(rule1.treatment(), is(treatmentBuilder1.build())); // 2nd Device FlowRule rule2 = rules.stream() .filter(x -> x.deviceId().equals(device2.id())) .findFirst() .get(); // validate SRC selector TrafficSelector.Builder selectorBuilder2 = DefaultTrafficSelector.builder(); selectorBuilder2.matchInPort(d2p1.port()); selectorBuilder2.add(Criteria.matchOduSignalType(OduSignalType.ODU0)); selectorBuilder2.add(Criteria.matchOduSignalId(oduSignalId)); assertThat(rule2.selector(), is(selectorBuilder2.build())); // validate SRC treatment (with OduSignalId, where 1 TributarySlot is used) TrafficTreatment.Builder treatmentBuilder2 = DefaultTrafficTreatment.builder(); treatmentBuilder2.add(Instructions.modL1OduSignalId(oduSignalId)); treatmentBuilder2.setOutput(d2p2.port()); assertThat(rule2.treatment(), is(treatmentBuilder2.build())); // 3rd Device FlowRule rule3 = rules.stream() .filter(x -> x.deviceId().equals(device3.id())) .findFirst() .get(); // validate DST selector (with OduSignalId, where the same TributarySlot is used) TrafficSelector.Builder selectorBuilder3 = DefaultTrafficSelector.builder(); selectorBuilder3.matchInPort(d3p1.port()); selectorBuilder3.add(Criteria.matchOduSignalType(OduSignalType.ODU0)); selectorBuilder3.add(Criteria.matchOduSignalId(oduSignalId)); assertThat(rule3.selector(), is(selectorBuilder3.build())); // validate DST treatment assertThat(rule3.treatment(), is( DefaultTrafficTreatment.builder().setOutput(d3p2.port()).build() )); rules.forEach(rule -> assertEquals("FlowRule priority is incorrect", intent.priority(), rule.priority())); sut.deactivate(); } /** * Tests compile of OpticalOduIntent with allocation of TributarySlots. * Compile two ODUCLT ports (with CLT_10GBE), over OTU ports (with OTU2): * - All TributarySlots are used */ @Test public void test10GbeMultiplexOverOdu2() { intent = OpticalOduIntent.builder() .appId(APP_ID) .key(KEY1) .src(d1p3) .dst(d3p3) .signalType(D1P3.signalType()) .bidirectional(false) .build(); sut.activate(); 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(); // 1st Device FlowRule rule1 = rules.stream() .filter(x -> x.deviceId().equals(device1.id())) .findFirst() .get(); // validate SRC selector TrafficSelector.Builder selectorBuilder1 = DefaultTrafficSelector.builder(); selectorBuilder1.matchInPort(d1p3.port()); selectorBuilder1.add(Criteria.matchOduSignalType(OduSignalType.ODU2)); assertThat(rule1.selector(), is(selectorBuilder1.build())); // validate SRC treatment (without OduSignalId - all TributarySlots are used) TrafficTreatment.Builder treatmentBuilder1 = DefaultTrafficTreatment.builder(); treatmentBuilder1.setOutput(d1p2.port()); assertThat(rule1.treatment(), is(treatmentBuilder1.build())); // 2nd Device FlowRule rule2 = rules.stream() .filter(x -> x.deviceId().equals(device2.id())) .findFirst() .get(); // validate SRC selector TrafficSelector.Builder selectorBuilder2 = DefaultTrafficSelector.builder(); selectorBuilder2.matchInPort(d2p1.port()); selectorBuilder2.add(Criteria.matchOduSignalType(OduSignalType.ODU2)); assertThat(rule2.selector(), is(selectorBuilder2.build())); // validate SRC treatment (without OduSignalId - all TributarySlots are used) TrafficTreatment.Builder treatmentBuilder2 = DefaultTrafficTreatment.builder(); treatmentBuilder2.setOutput(d2p2.port()); assertThat(rule2.treatment(), is(treatmentBuilder2.build())); // 3rd Device FlowRule rule3 = rules.stream() .filter(x -> x.deviceId().equals(device3.id())) .findFirst() .get(); // validate DST selector (without OduSignalId - all TributarySlots are used) TrafficSelector.Builder selectorBuilder3 = DefaultTrafficSelector.builder(); selectorBuilder3.matchInPort(d3p1.port()); selectorBuilder3.add(Criteria.matchOduSignalType(OduSignalType.ODU2)); assertThat(rule3.selector(), is(selectorBuilder3.build())); // validate DST treatment assertThat(rule3.treatment(), is( DefaultTrafficTreatment.builder().setOutput(d3p3.port()).build() )); rules.forEach(rule -> assertEquals("FlowRule priority is incorrect", intent.priority(), rule.priority())); sut.deactivate(); } }