blob: c157a54fbca8244a6dd53973bd61b79925344a49 [file] [log] [blame]
/*
* Copyright 2016-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.provider;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.graph.ScalarWeight;
import org.onlab.graph.Weight;
import org.onosproject.core.ApplicationId;
import org.onosproject.core.CoreServiceAdapter;
import org.onosproject.core.DefaultApplicationId;
import org.onosproject.incubator.net.virtual.DefaultVirtualDevice;
import org.onosproject.incubator.net.virtual.DefaultVirtualNetwork;
import org.onosproject.incubator.net.virtual.DefaultVirtualPort;
import org.onosproject.incubator.net.virtual.NetworkId;
import org.onosproject.incubator.net.virtual.TenantId;
import org.onosproject.incubator.net.virtual.VirtualDevice;
import org.onosproject.incubator.net.virtual.VirtualLink;
import org.onosproject.incubator.net.virtual.VirtualNetwork;
import org.onosproject.incubator.net.virtual.VirtualNetworkAdminServiceAdapter;
import org.onosproject.incubator.net.virtual.VirtualPort;
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.Path;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.flow.DefaultFlowEntry;
import org.onosproject.net.flow.DefaultFlowRule;
import org.onosproject.net.flow.DefaultTrafficSelector;
import org.onosproject.net.flow.DefaultTrafficTreatment;
import org.onosproject.net.flow.FlowEntry;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.FlowRuleServiceAdapter;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.L2ModificationInstruction;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.net.topology.LinkWeigher;
import org.onosproject.net.topology.Topology;
import org.onosproject.net.topology.TopologyServiceAdapter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import static org.junit.Assert.assertEquals;
public class DefaultVirtualFlowRuleProviderTest {
private static final ProviderId PID = new ProviderId("of", "foo");
private static final DeviceId DID1 = DeviceId.deviceId("of:001");
private static final DeviceId DID2 = DeviceId.deviceId("of:002");
private static final PortNumber PORT_NUM1 = PortNumber.portNumber(1);
private static final PortNumber PORT_NUM2 = PortNumber.portNumber(2);
private static final DefaultAnnotations ANNOTATIONS =
DefaultAnnotations.builder().set("foo", "bar").build();
private static final Device DEV1 =
new DefaultDevice(PID, DID1, Device.Type.SWITCH, "", "", "", "", null);
private static final Device DEV2 =
new DefaultDevice(PID, DID2, Device.Type.SWITCH, "", "", "", "", null);
private static final Port PORT11 =
new DefaultPort(DEV1, PORT_NUM1, true, ANNOTATIONS);
private static final Port PORT12 =
new DefaultPort(DEV1, PORT_NUM2, true, ANNOTATIONS);
private static final Port PORT21 =
new DefaultPort(DEV2, PORT_NUM1, true, ANNOTATIONS);
private static final Port PORT22 =
new DefaultPort(DEV2, PORT_NUM2, true, ANNOTATIONS);
private static final ConnectPoint CP11 = new ConnectPoint(DID1, PORT_NUM1);
private static final ConnectPoint CP12 = new ConnectPoint(DID1, PORT_NUM2);
private static final ConnectPoint CP21 = new ConnectPoint(DID2, PORT_NUM1);
private static final ConnectPoint CP22 = new ConnectPoint(DID2, PORT_NUM2);
private static final Link LINK1 = DefaultLink.builder()
.src(CP12).dst(CP21).providerId(PID).type(Link.Type.DIRECT).build();
private static final NetworkId VNET_ID = NetworkId.networkId(1);
private static final DeviceId VDID = DeviceId.deviceId("of:100");
private static final VirtualNetwork VNET = new DefaultVirtualNetwork(
VNET_ID, TenantId.tenantId("t1"));
private static final VirtualDevice VDEV =
new DefaultVirtualDevice(VNET_ID, VDID);
private static final VirtualPort VPORT1 =
new DefaultVirtualPort(VNET_ID, VDEV, PORT_NUM1, CP11);
private static final VirtualPort VPORT2 =
new DefaultVirtualPort(VNET_ID, VDEV, PORT_NUM2, CP22);
private static final int TIMEOUT = 10;
protected DefaultVirtualFlowRuleProvider virtualProvider;
private ApplicationId vAppId;
@Before
public void setUp() {
virtualProvider = new DefaultVirtualFlowRuleProvider();
virtualProvider.deviceService = new TestDeviceService();
virtualProvider.coreService = new TestCoreService();
virtualProvider.vnService =
new TestVirtualNetworkAdminService();
virtualProvider.topologyService = new TestTopologyService();
virtualProvider.flowRuleService = new TestFlowRuleService();
virtualProvider.providerRegistryService = new VirtualProviderManager();
virtualProvider.activate();
vAppId = new TestApplicationId(0, "Virtual App");
}
@After
public void tearDown() {
virtualProvider.deactivate();
virtualProvider.deviceService = null;
virtualProvider.coreService = null;
}
@Test
public void devirtualizeFlowRuleWithInPort() {
TrafficSelector ts = DefaultTrafficSelector.builder()
.matchInPort(PORT_NUM1).build();
TrafficTreatment tr = DefaultTrafficTreatment.builder()
.setOutput(PORT_NUM2).build();
FlowRule r1 = DefaultFlowRule.builder()
.forDevice(VDID)
.withSelector(ts)
.withTreatment(tr)
.withPriority(10)
.fromApp(vAppId)
.makeTemporary(TIMEOUT)
.build();
virtualProvider.applyFlowRule(VNET_ID, r1);
assertEquals("2 rules should exist", 2,
virtualProvider.flowRuleService.getFlowRuleCount());
Set<FlowEntry> phyRules = new HashSet<>();
for (FlowEntry i : virtualProvider.flowRuleService.getFlowEntries(DID1)) {
phyRules.add(i);
}
for (FlowEntry i : virtualProvider.flowRuleService.getFlowEntries(DID2)) {
phyRules.add(i);
}
FlowRule in = null;
FlowRule out = null;
for (FlowRule rule : phyRules) {
L2ModificationInstruction i = (L2ModificationInstruction)
rule.treatment().allInstructions().get(0);
if (i.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
in = rule;
} else {
out = rule;
}
}
assertEquals(DID1, in.deviceId());
assertEquals(DID2, out.deviceId());
}
@Test
public void devirtualizeFlowRuleWithoutInPort() {
TrafficSelector ts = DefaultTrafficSelector.builder().build();
TrafficTreatment tr = DefaultTrafficTreatment.builder()
.setOutput(PORT_NUM2).build();
FlowRule r1 = DefaultFlowRule.builder()
.forDevice(VDID)
.withSelector(ts)
.withTreatment(tr)
.withPriority(10)
.fromApp(vAppId)
.makeTemporary(TIMEOUT)
.build();
virtualProvider.applyFlowRule(VNET_ID, r1);
assertEquals("3 rules should exist", 3,
virtualProvider.flowRuleService.getFlowRuleCount());
FlowRule inFromDID1 = null;
FlowRule inFromDID2 = null;
FlowRule out = null;
Set<FlowEntry> phyRules = new HashSet<>();
for (FlowEntry i : virtualProvider.flowRuleService.getFlowEntries(DID1)) {
phyRules.add(i);
}
for (FlowEntry i : virtualProvider.flowRuleService.getFlowEntries(DID2)) {
phyRules.add(i);
}
for (FlowRule rule : phyRules) {
for (Instruction inst : rule.treatment().allInstructions()) {
if (inst.type() == Instruction.Type.L2MODIFICATION) {
L2ModificationInstruction i = (L2ModificationInstruction) inst;
if (i.subtype() == L2ModificationInstruction.L2SubType.VLAN_PUSH) {
inFromDID1 = rule;
break;
} else {
out = rule;
break;
}
} else {
inFromDID2 = rule;
break;
}
}
}
assertEquals(DID1, inFromDID1.deviceId());
assertEquals(DID2, inFromDID2.deviceId());
assertEquals(DID2, out.deviceId());
}
@Test
public void removeVirtualizeFlowRule() {
TrafficSelector ts = DefaultTrafficSelector.builder().build();
TrafficTreatment tr = DefaultTrafficTreatment.builder()
.setOutput(PORT_NUM2).build();
FlowRule r1 = DefaultFlowRule.builder()
.forDevice(VDID)
.withSelector(ts)
.withTreatment(tr)
.withPriority(10)
.fromApp(vAppId)
.makeTemporary(TIMEOUT)
.build();
virtualProvider.removeFlowRule(VNET_ID, r1);
assertEquals("0 rules should exist", 0,
virtualProvider.flowRuleService.getFlowRuleCount());
}
private static class TestDeviceService extends DeviceServiceAdapter {
@Override
public int getDeviceCount() {
return 2;
}
@Override
public Iterable<Device> getDevices() {
return ImmutableList.of(DEV1, DEV2);
}
@Override
public Iterable<Device> getAvailableDevices() {
return getDevices();
}
@Override
public Device getDevice(DeviceId deviceId) {
return deviceId.equals(DID2) ? DEV2 : DEV1;
}
}
private static class TestCoreService extends CoreServiceAdapter {
@Override
public ApplicationId registerApplication(String name) {
return new TestApplicationId(1, name);
}
}
private static class TestApplicationId extends DefaultApplicationId {
public TestApplicationId(int id, String name) {
super(id, name);
}
}
private class TestVirtualNetworkAdminService
extends VirtualNetworkAdminServiceAdapter {
@Override
public Set<VirtualDevice> getVirtualDevices(NetworkId networkId) {
return ImmutableSet.of(VDEV);
}
@Override
public Set<VirtualLink> getVirtualLinks(NetworkId networkId) {
return new HashSet<>();
}
@Override
public Set<VirtualPort> getVirtualPorts(NetworkId networkId,
DeviceId deviceId) {
return ImmutableSet.of(VPORT1, VPORT2);
}
@Override
public ApplicationId getVirtualNetworkApplicationId(NetworkId networkId) {
return vAppId;
}
}
private static class TestTopologyService extends TopologyServiceAdapter {
Weight oneHundred = ScalarWeight.toWeight(100);
@Override
public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst) {
DefaultPath path = new DefaultPath(PID, ImmutableList.of(LINK1),
oneHundred, ANNOTATIONS);
return ImmutableSet.of(path);
}
@Override
public Set<Path> getPaths(Topology topology, DeviceId src, DeviceId dst,
LinkWeigher weigher) {
DefaultPath path = new DefaultPath(PID, ImmutableList.of(LINK1),
oneHundred, ANNOTATIONS);
return ImmutableSet.of(path);
}
}
private static class TestFlowRuleService extends FlowRuleServiceAdapter {
static Set<FlowRule> ruleCollection = new HashSet<>();
@Override
public int getFlowRuleCount() {
return ruleCollection.size();
}
@Override
public Iterable<FlowEntry> getFlowEntries(DeviceId deviceId) {
return ruleCollection.stream()
.filter(r -> r.deviceId().equals(deviceId))
.map(DefaultFlowEntry::new)
.collect(Collectors.toSet());
}
@Override
public void applyFlowRules(FlowRule... flowRules) {
ruleCollection.addAll(Arrays.asList(flowRules));
}
@Override
public void removeFlowRules(FlowRule... flowRules) {
Set<FlowRule> candidates = new HashSet<>();
for (FlowRule rule : flowRules) {
ruleCollection.stream()
.filter(r -> r.exactMatch(rule))
.forEach(candidates::add);
}
ruleCollection.removeAll(candidates);
}
}
}