Jonathan Hart

Implemented VLAN-to-VLAN routing support for SDN-IP.

SDN-IP can now support peering and routing between hosts that are connected
on VLANs.

Changes include:
 * Updated NetworkConfigReader app to read (optional) VLAN configuration
 * Updated VlanId to support the 'VLAN present' value - in a match this means
   that a VLAN tag must be present, but it can contain any value.
 * Updated SDN-IP to set destination VLAN tag values if appropriate
 * Updated FlowModBuilder and FlowEntryBuilder to support 'VLAN present' value
 * Slew of test updates.

Change-Id: Ief48cede5c1fd50e1efa851da5a97fb4a8edda29
Showing 22 changed files with 443 additions and 159 deletions
......@@ -27,6 +27,7 @@ public class AddressEntry {
private long portNumber;
private List<String> ipAddresses;
private String macAddress;
private Short vlan;
public String getDpid() {
return dpid;
......@@ -63,4 +64,13 @@ public class AddressEntry {
public void setMacAddress(String macAddress) {
this.macAddress = macAddress;
}
public Short getVlan() {
return vlan;
}
@JsonProperty("vlan")
public void setVlan(short vlan) {
this.vlan = vlan;
}
}
......
......@@ -28,15 +28,16 @@ import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
import org.onosproject.net.host.HostAdminService;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.host.PortAddresses;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.slf4j.Logger;
import com.fasterxml.jackson.databind.ObjectMapper;
......@@ -115,7 +116,8 @@ public class NetworkConfigReader {
try {
String[] splits = strIp.split("/");
if (splits.length != 2) {
throw new IllegalArgumentException("Invalid IP address and prefix length format");
throw new IllegalArgumentException(
"Invalid IP address and prefix length format");
}
// NOTE: IpPrefix will mask-out the bits after the prefix length.
IpPrefix subnet = IpPrefix.valueOf(strIp);
......@@ -138,8 +140,21 @@ public class NetworkConfigReader {
}
}
VlanId vlan = null;
if (entry.getVlan() == null) {
vlan = VlanId.NONE;
} else {
try {
vlan = VlanId.vlanId(entry.getVlan());
} catch (IllegalArgumentException e) {
log.warn("Bad format for VLAN id in config: {}",
entry.getVlan());
vlan = VlanId.NONE;
}
}
PortAddresses addresses = new PortAddresses(cp,
interfaceIpAddresses, macAddress);
interfaceIpAddresses, macAddress, vlan);
hostAdminService.bindAddressesToPort(addresses);
}
}
......
......@@ -4,13 +4,15 @@
"dpid" : "00:00:00:00:00:00:00:a3",
"port" : "1",
"ips" : ["192.168.10.101/24"],
"mac" : "00:00:00:00:00:01"
"mac" : "00:00:00:00:00:01",
"vlan" : "1"
},
{
"dpid" : "00:00:00:00:00:00:00:a5",
"port" : "1",
"ips" : ["192.168.20.101/24"],
"mac" : "00:00:00:00:00:01"
"mac" : "00:00:00:00:00:01",
"vlan" : "2"
},
{
"dpid" : "00:00:00:00:00:00:00:a2",
......
......@@ -30,10 +30,11 @@ import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.lang3.tuple.Pair;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Host;
......@@ -272,7 +273,7 @@ public class Router implements RouteListener {
* or IPv6.
*
* @param prefix the prefix to use
* @return true if the rotue was found and removed, otherwise false
* @return true if the route was found and removed, otherwise false
*/
boolean removeRibRoute(IpPrefix prefix) {
if (prefix.version() == Ip4Address.VERSION) {
......@@ -455,25 +456,26 @@ public class Router implements RouteListener {
}
// Match the destination IP prefix at the first hop
TrafficSelector selector;
TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
if (prefix.version() == Ip4Address.VERSION) {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(prefix)
.build();
selector.matchEthType(Ethernet.TYPE_IPV4);
} else {
selector = DefaultTrafficSelector.builder()
.matchEthType(Ethernet.TYPE_IPV6)
.matchIPDst(prefix)
.build();
selector.matchEthType(Ethernet.TYPE_IPV6);
}
selector.matchIPDst(prefix);
// Rewrite the destination MAC address
TrafficTreatment treatment = DefaultTrafficTreatment.builder()
.setEthDst(nextHopMacAddress)
.build();
TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
.setEthDst(nextHopMacAddress);
if (!egressInterface.vlan().equals(VlanId.NONE)) {
treatment.setVlanId(egressInterface.vlan());
// If we set VLAN ID, we have to make sure a VLAN tag exists.
// TODO support no VLAN -> VLAN routing
selector.matchVlanId(VlanId.ANY);
}
return new MultiPointToSinglePointIntent(appId, selector, treatment,
return new MultiPointToSinglePointIntent(appId, selector.build(),
treatment.build(),
ingressPorts, egressPort);
}
......
......@@ -19,6 +19,7 @@ import java.util.Objects;
import java.util.Set;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.host.PortAddresses;
......@@ -34,6 +35,7 @@ public class Interface {
private final ConnectPoint connectPoint;
private final Set<InterfaceIpAddress> ipAddresses;
private final MacAddress macAddress;
private final VlanId vlan;
/**
* Creates an Interface based on a connection point, a set of interface
......@@ -45,10 +47,11 @@ public class Interface {
*/
public Interface(ConnectPoint connectPoint,
Set<InterfaceIpAddress> ipAddresses,
MacAddress macAddress) {
MacAddress macAddress, VlanId vlan) {
this.connectPoint = connectPoint;
this.ipAddresses = Sets.newHashSet(ipAddresses);
this.macAddress = macAddress;
this.vlan = vlan;
}
/**
......@@ -60,6 +63,7 @@ public class Interface {
connectPoint = portAddresses.connectPoint();
ipAddresses = Sets.newHashSet(portAddresses.ipAddresses());
macAddress = portAddresses.mac();
vlan = portAddresses.vlan();
}
/**
......@@ -76,18 +80,27 @@ public class Interface {
*
* @return the set of interface IP addresses
*/
public Set<InterfaceIpAddress> ipAddresses() {
public Set<InterfaceIpAddress> ipAddresses() {
return ipAddresses;
}
/**
* Retrieves the MAC address that is assigned to the interface.
*
* @return the MAC address
*/
public MacAddress mac() {
return macAddress;
}
/**
* Retrieves the MAC address that is assigned to the interface.
*
* @return the MAC address
*/
public MacAddress mac() {
return macAddress;
}
/**
* Retrieves the VLAN ID that is assigned to the interface.
*
* @return the VLAN ID
*/
public VlanId vlan() {
return vlan;
}
@Override
public boolean equals(Object other) {
......@@ -99,12 +112,13 @@ public class Interface {
return connectPoint.equals(otherInterface.connectPoint) &&
ipAddresses.equals(otherInterface.ipAddresses) &&
macAddress.equals(otherInterface.macAddress);
macAddress.equals(otherInterface.macAddress) &&
vlan.equals(otherInterface.vlan);
}
@Override
public int hashCode() {
return Objects.hash(connectPoint, ipAddresses, macAddress);
return Objects.hash(connectPoint, ipAddresses, macAddress, vlan);
}
@Override
......@@ -113,6 +127,7 @@ public class Interface {
.add("connectPoint", connectPoint)
.add("ipAddresses", ipAddresses)
.add("macAddress", macAddress)
.add("vlan", vlan)
.toString();
}
}
......
......@@ -29,6 +29,10 @@ import java.util.Set;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
import org.onosproject.net.PortNumber;
......@@ -36,9 +40,6 @@ import org.onosproject.net.host.HostService;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.host.PortAddresses;
import org.onosproject.sdnip.config.Interface;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
......@@ -76,7 +77,8 @@ public class HostToInterfaceAdaptorTest {
IpPrefix.valueOf("192.168.1.0/24"));
createPortAddressesAndInterface(CP1,
Sets.newHashSet(ia11),
MacAddress.valueOf("00:00:00:00:00:01"));
MacAddress.valueOf("00:00:00:00:00:01"),
VlanId.NONE);
// Two addresses in the same subnet
InterfaceIpAddress ia21 =
......@@ -87,7 +89,8 @@ public class HostToInterfaceAdaptorTest {
IpPrefix.valueOf("192.168.2.0/24"));
createPortAddressesAndInterface(CP2,
Sets.newHashSet(ia21, ia22),
MacAddress.valueOf("00:00:00:00:00:02"));
MacAddress.valueOf("00:00:00:00:00:02"),
VlanId.vlanId((short) 4));
// Two addresses in different subnets
InterfaceIpAddress ia31 =
......@@ -98,7 +101,8 @@ public class HostToInterfaceAdaptorTest {
IpPrefix.valueOf("192.168.4.0/24"));
createPortAddressesAndInterface(CP3,
Sets.newHashSet(ia31, ia41),
MacAddress.valueOf("00:00:00:00:00:03"));
MacAddress.valueOf("00:00:00:00:00:03"),
VlanId.NONE);
expect(hostService.getAddressBindings()).andReturn(portAddresses).anyTimes();
......@@ -114,16 +118,17 @@ public class HostToInterfaceAdaptorTest {
* @param cp the connect point
* @param ipAddresses the set of interface IP addresses
* @param mac the MAC address
* @param vlan the VLAN ID
*/
private void createPortAddressesAndInterface(
ConnectPoint cp, Set<InterfaceIpAddress> ipAddresses,
MacAddress mac) {
PortAddresses pa = new PortAddresses(cp, ipAddresses, mac);
MacAddress mac, VlanId vlan) {
PortAddresses pa = new PortAddresses(cp, ipAddresses, mac, vlan);
portAddresses.add(pa);
expect(hostService.getAddressBindingsForPort(cp)).andReturn(
Collections.singleton(pa)).anyTimes();
Interface intf = new Interface(cp, ipAddresses, mac);
Interface intf = new Interface(cp, ipAddresses, mac, vlan);
interfaces.put(cp, intf);
}
......
......@@ -36,6 +36,13 @@ import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.junit.TestUtils.TestUtilsException;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultHost;
......@@ -59,13 +66,6 @@ import org.onosproject.net.intent.IntentState;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.sdnip.config.Interface;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.collect.Sets;
import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
......@@ -135,7 +135,8 @@ public class IntentSyncTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.10.101"),
IpPrefix.valueOf("192.168.10.0/24")));
Interface sw1Eth1 = new Interface(SW1_ETH1,
interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"));
interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"),
VlanId.NONE);
interfaces.add(sw1Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
......@@ -143,7 +144,8 @@ public class IntentSyncTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.20.101"),
IpPrefix.valueOf("192.168.20.0/24")));
Interface sw2Eth1 = new Interface(SW2_ETH1,
interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"));
interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"),
VlanId.NONE);
interfaces.add(sw2Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
......@@ -151,7 +153,8 @@ public class IntentSyncTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.30.101"),
IpPrefix.valueOf("192.168.30.0/24")));
Interface sw3Eth1 = new Interface(SW3_ETH1,
interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"));
interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"),
VlanId.NONE);
interfaces.add(sw3Eth1);
expect(interfaceService.getInterface(SW1_ETH1)).andReturn(
......
......@@ -38,6 +38,7 @@ import org.onlab.packet.IPv4;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
......@@ -189,7 +190,8 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
IpPrefix.valueOf("192.168.10.0/24"));
Interface intfsw1eth1 = new Interface(s1Eth1,
Collections.singleton(ia1),
MacAddress.valueOf("00:00:00:00:00:01"));
MacAddress.valueOf("00:00:00:00:00:01"),
VlanId.NONE);
configuredInterfaces.put(interfaceSw1Eth1, intfsw1eth1);
String interfaceSw2Eth1 = "s2-eth1";
......@@ -198,7 +200,8 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest {
IpPrefix.valueOf("192.168.20.0/24"));
Interface intfsw2eth1 = new Interface(s2Eth1,
Collections.singleton(ia2),
MacAddress.valueOf("00:00:00:00:00:02"));
MacAddress.valueOf("00:00:00:00:00:02"),
VlanId.NONE);
configuredInterfaces.put(interfaceSw2Eth1, intfsw2eth1);
interfaceService = createMock(InterfaceService.class);
......
......@@ -35,6 +35,13 @@ import org.junit.Before;
import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.junit.TestUtils.TestUtilsException;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DefaultHost;
......@@ -50,24 +57,17 @@ import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.HostEvent;
import org.onosproject.net.host.HostService;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.intent.AbstractIntentTest;
import org.onosproject.net.intent.Intent;
import org.onosproject.net.intent.IntentOperations;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.AbstractIntentTest;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.sdnip.IntentSynchronizer.IntentKey;
import org.onosproject.sdnip.Router.InternalHostListener;
import org.onosproject.sdnip.config.BgpPeer;
import org.onosproject.sdnip.config.Interface;
import org.onosproject.sdnip.config.SdnIpConfigurationService;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.collect.Sets;
import com.googlecode.concurrenttrees.radix.node.concrete.DefaultByteArrayNodeFactory;
......@@ -168,7 +168,8 @@ public class RouterAsyncArpTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.10.101"),
IpPrefix.valueOf("192.168.10.0/24")));
Interface sw1Eth1 = new Interface(SW1_ETH1,
interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"));
interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"),
VlanId.NONE);
interfaces.add(sw1Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
......@@ -176,7 +177,8 @@ public class RouterAsyncArpTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.20.101"),
IpPrefix.valueOf("192.168.20.0/24")));
Interface sw2Eth1 = new Interface(SW2_ETH1,
interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"));
interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"),
VlanId.NONE);
interfaces.add(sw2Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
......@@ -184,7 +186,8 @@ public class RouterAsyncArpTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.30.101"),
IpPrefix.valueOf("192.168.30.0/24")));
Interface sw3Eth1 = new Interface(SW3_ETH1,
interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"));
interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"),
VlanId.NONE);
interfaces.add(sw3Eth1);
expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
......
......@@ -36,10 +36,10 @@ import org.junit.Test;
import org.onlab.junit.TestUtils;
import org.onlab.junit.TestUtils.TestUtilsException;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
......@@ -95,6 +95,10 @@ public class RouterTest extends AbstractIntentTest {
DeviceId.deviceId("of:0000000000000003"),
PortNumber.portNumber(1));
private static final ConnectPoint SW4_ETH1 = new ConnectPoint(
DeviceId.deviceId("of:0000000000000004"),
PortNumber.portNumber(1));
private static final ApplicationId APPID = new ApplicationId() {
@Override
public short id() {
......@@ -146,6 +150,10 @@ public class RouterTest extends AbstractIntentTest {
peers.put(IpAddress.valueOf(peer2Sw2Eth1),
new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1));
String peer1Sw4Eth1 = "192.168.40.1";
peers.put(IpAddress.valueOf(peer1Sw4Eth1),
new BgpPeer("00:00:00:00:00:00:00:04", 1, peer1Sw4Eth1));
sdnIpConfigService = createMock(SdnIpConfigurationService.class);
expect(sdnIpConfigService.getBgpPeers()).andReturn(peers).anyTimes();
replay(sdnIpConfigService);
......@@ -166,7 +174,8 @@ public class RouterTest extends AbstractIntentTest {
IpPrefix.valueOf("192.168.10.0/24"));
Interface sw1Eth1 = new Interface(SW1_ETH1,
Sets.newHashSet(ia1),
MacAddress.valueOf("00:00:00:00:00:01"));
MacAddress.valueOf("00:00:00:00:00:01"),
VlanId.NONE);
expect(interfaceService.getInterface(SW1_ETH1)).andReturn(sw1Eth1).anyTimes();
interfaces.add(sw1Eth1);
......@@ -176,7 +185,8 @@ public class RouterTest extends AbstractIntentTest {
IpPrefix.valueOf("192.168.20.0/24"));
Interface sw2Eth1 = new Interface(SW2_ETH1,
Sets.newHashSet(ia2),
MacAddress.valueOf("00:00:00:00:00:02"));
MacAddress.valueOf("00:00:00:00:00:02"),
VlanId.NONE);
expect(interfaceService.getInterface(SW2_ETH1)).andReturn(sw2Eth1).anyTimes();
interfaces.add(sw2Eth1);
......@@ -186,11 +196,23 @@ public class RouterTest extends AbstractIntentTest {
IpPrefix.valueOf("192.168.30.0/24"));
Interface sw3Eth1 = new Interface(SW3_ETH1,
Sets.newHashSet(ia3),
MacAddress.valueOf("00:00:00:00:00:03"));
MacAddress.valueOf("00:00:00:00:00:03"),
VlanId.NONE);
expect(interfaceService.getInterface(SW3_ETH1)).andReturn(sw3Eth1).anyTimes();
interfaces.add(sw3Eth1);
InterfaceIpAddress ia4 =
new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"),
IpPrefix.valueOf("192.168.40.0/24"));
Interface sw4Eth1 = new Interface(SW4_ETH1,
Sets.newHashSet(ia4),
MacAddress.valueOf("00:00:00:00:00:04"),
VlanId.vlanId((short) 1));
expect(interfaceService.getInterface(SW4_ETH1)).andReturn(sw4Eth1).anyTimes();
interfaces.add(sw4Eth1);
expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes();
replay(interfaceService);
......@@ -228,6 +250,18 @@ public class RouterTest extends AbstractIntentTest {
hostService.startMonitoringIp(host2Address);
expectLastCall().anyTimes();
// Next hop on a VLAN
IpAddress host3Address = IpAddress.valueOf("192.168.40.1");
Host host3 = new DefaultHost(ProviderId.NONE, HostId.NONE,
MacAddress.valueOf("00:00:00:00:00:03"), VlanId.vlanId((short) 1),
new HostLocation(SW4_ETH1, 1),
Sets.newHashSet(host3Address));
expect(hostService.getHostsByIp(host3Address))
.andReturn(Sets.newHashSet(host3)).anyTimes();
hostService.startMonitoringIp(host3Address);
expectLastCall().anyTimes();
replay(hostService);
}
......@@ -255,6 +289,7 @@ public class RouterTest extends AbstractIntentTest {
Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
ingressPoints.add(SW2_ETH1);
ingressPoints.add(SW3_ETH1);
ingressPoints.add(SW4_ETH1);
MultiPointToSinglePointIntent intent =
new MultiPointToSinglePointIntent(APPID,
......@@ -290,6 +325,66 @@ public class RouterTest extends AbstractIntentTest {
}
/**
* This method tests adding a route entry.
*/
@Test
public void testRouteAddWithVlan() throws TestUtilsException {
// Construct a route entry
RouteEntry routeEntry = new RouteEntry(
Ip4Prefix.valueOf("3.3.3.0/24"),
Ip4Address.valueOf("192.168.40.1"));
// Construct a MultiPointToSinglePointIntent intent
TrafficSelector.Builder selectorBuilder =
DefaultTrafficSelector.builder();
selectorBuilder.matchEthType(Ethernet.TYPE_IPV4)
.matchIPDst(routeEntry.prefix())
.matchVlanId(VlanId.ANY);
TrafficTreatment.Builder treatmentBuilder =
DefaultTrafficTreatment.builder();
treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:03"))
.setVlanId(VlanId.vlanId((short) 1));
Set<ConnectPoint> ingressPoints = new HashSet<ConnectPoint>();
ingressPoints.add(SW1_ETH1);
ingressPoints.add(SW2_ETH1);
ingressPoints.add(SW3_ETH1);
MultiPointToSinglePointIntent intent =
new MultiPointToSinglePointIntent(APPID,
selectorBuilder.build(), treatmentBuilder.build(),
ingressPoints, SW4_ETH1);
// Set up test expectation
reset(intentService);
// Setup the expected intents
IntentOperations.Builder builder = IntentOperations.builder(APPID);
builder.addSubmitOperation(intent);
intentService.execute(TestIntentServiceHelper.eqExceptId(
builder.build()));
replay(intentService);
// Call the processRouteUpdates() method in Router class
intentSynchronizer.leaderChanged(true);
TestUtils.setField(intentSynchronizer, "isActivatedLeader", true);
RouteUpdate routeUpdate = new RouteUpdate(RouteUpdate.Type.UPDATE,
routeEntry);
router.processRouteUpdates(Collections.<RouteUpdate>singletonList(routeUpdate));
// Verify
assertEquals(router.getRoutes4().size(), 1);
assertTrue(router.getRoutes4().contains(routeEntry));
assertEquals(intentSynchronizer.getRouteIntents().size(), 1);
Intent firstIntent =
intentSynchronizer.getRouteIntents().iterator().next();
IntentKey firstIntentKey = new IntentKey(firstIntent);
IntentKey intentKey = new IntentKey(intent);
assertTrue(firstIntentKey.equals(intentKey));
verify(intentService);
}
/**
* This method tests updating a route entry.
*
* @throws TestUtilsException
......@@ -321,6 +416,7 @@ public class RouterTest extends AbstractIntentTest {
Set<ConnectPoint> ingressPointsNew = new HashSet<ConnectPoint>();
ingressPointsNew.add(SW1_ETH1);
ingressPointsNew.add(SW3_ETH1);
ingressPointsNew.add(SW4_ETH1);
MultiPointToSinglePointIntent intentNew =
new MultiPointToSinglePointIntent(APPID,
......
......@@ -42,6 +42,13 @@ import org.junit.experimental.categories.Category;
import org.onlab.junit.IntegrationTest;
import org.onlab.junit.TestUtils;
import org.onlab.junit.TestUtils.TestUtilsException;
import org.onlab.packet.Ethernet;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.core.ApplicationId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.DeviceId;
......@@ -52,18 +59,12 @@ import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.TrafficTreatment;
import org.onosproject.net.host.HostService;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.intent.AbstractIntentTest;
import org.onosproject.net.intent.IntentService;
import org.onosproject.net.intent.MultiPointToSinglePointIntent;
import org.onosproject.net.intent.AbstractIntentTest;
import org.onosproject.sdnip.config.BgpPeer;
import org.onosproject.sdnip.config.Interface;
import org.onosproject.sdnip.config.SdnIpConfigurationService;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.MacAddress;
import com.google.common.collect.Sets;
......@@ -148,7 +149,8 @@ public class SdnIpTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.10.101"),
IpPrefix.valueOf("192.168.10.0/24")));
Interface sw1Eth1 = new Interface(SW1_ETH1,
interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"));
interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"),
VlanId.NONE);
interfaces.add(sw1Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet();
......@@ -156,7 +158,8 @@ public class SdnIpTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.20.101"),
IpPrefix.valueOf("192.168.20.0/24")));
Interface sw2Eth1 = new Interface(SW2_ETH1,
interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"));
interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"),
VlanId.NONE);
interfaces.add(sw2Eth1);
Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet();
......@@ -164,7 +167,8 @@ public class SdnIpTest extends AbstractIntentTest {
IpAddress.valueOf("192.168.30.101"),
IpPrefix.valueOf("192.168.30.0/24")));
Interface sw3Eth1 = new Interface(SW3_ETH1,
interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"));
interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"),
VlanId.NONE);
interfaces.add(sw3Eth1);
expect(interfaceService.getInterface(SW1_ETH1)).andReturn(
......
......@@ -15,6 +15,8 @@
*/
package org.onosproject.sdnip;
import static org.easymock.EasyMock.reportMatcher;
import java.util.LinkedList;
import java.util.List;
......@@ -26,8 +28,6 @@ import org.onosproject.net.intent.IntentOperation;
import org.onosproject.net.intent.IntentOperations;
import org.onosproject.sdnip.IntentSynchronizer.IntentKey;
import static org.easymock.EasyMock.reportMatcher;
/**
* Helper class for testing operations submitted to the IntentService.
*/
......@@ -187,7 +187,7 @@ public final class TestIntentServiceHelper {
* @param submitIntents the SUBMIT intents
* @param withdrawIntentIds the WITHDRAW intents IDs
* @param replaceIntents the REPLACE intents
* @param updateIntents the UPDATE intens
* @param updateIntents the UPDATE intents
*/
private void extractIntents(IntentOperations intentOperations,
List<IntentKey> submitIntents,
......
......@@ -36,7 +36,7 @@ import com.google.common.collect.Lists;
public class AddressBindingsListCommand extends AbstractShellCommand {
private static final String FORMAT =
"port=%s/%s, ip(s)=%s, mac=%s";
"port=%s/%s, ip(s)=%s, mac=%s, vlan=%s";
@Override
protected void execute() {
......@@ -49,7 +49,7 @@ public class AddressBindingsListCommand extends AbstractShellCommand {
for (PortAddresses pa : addresses) {
print(FORMAT, pa.connectPoint().deviceId(), pa.connectPoint().port(),
printIpAddresses(pa.ipAddresses()), pa.mac());
printIpAddresses(pa.ipAddresses()), pa.mac(), pa.vlan());
}
}
......
......@@ -20,8 +20,9 @@ import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import org.onosproject.net.ConnectPoint;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import com.google.common.base.MoreObjects;
......@@ -33,6 +34,7 @@ public class PortAddresses {
private final ConnectPoint connectPoint;
private final Set<InterfaceIpAddress> ipAddresses;
private final MacAddress macAddress;
private final VlanId vlan;
/**
* Constructs a PortAddresses object for the given connection point, with a
......@@ -42,14 +44,16 @@ public class PortAddresses {
* @param connectPoint the connection point these addresses are for
* @param ipAddresses a set of interface IP addresses
* @param mac a MAC address
* @param vlan a VLAN ID
*/
public PortAddresses(ConnectPoint connectPoint,
Set<InterfaceIpAddress> ipAddresses, MacAddress mac) {
Set<InterfaceIpAddress> ipAddresses, MacAddress mac, VlanId vlan) {
this.connectPoint = connectPoint;
this.ipAddresses = (ipAddresses == null) ?
Collections.<InterfaceIpAddress>emptySet()
: new HashSet<>(ipAddresses);
this.macAddress = mac;
this.vlan = vlan;
}
/**
......@@ -79,6 +83,15 @@ public class PortAddresses {
return macAddress;
}
/**
* Returns the VLAN ID.
*
* @return the VLAN ID
*/
public VlanId vlan() {
return vlan;
}
@Override
public boolean equals(Object other) {
if (this == other) {
......@@ -93,12 +106,13 @@ public class PortAddresses {
return Objects.equals(this.connectPoint, otherPa.connectPoint)
&& Objects.equals(this.ipAddresses, otherPa.ipAddresses)
&& Objects.equals(this.macAddress, otherPa.macAddress);
&& Objects.equals(this.macAddress, otherPa.macAddress)
&& Objects.equals(this.vlan, otherPa.vlan);
}
@Override
public int hashCode() {
return Objects.hash(connectPoint, ipAddresses, macAddress);
return Objects.hash(connectPoint, ipAddresses, macAddress, vlan);
}
@Override
......@@ -107,6 +121,7 @@ public class PortAddresses {
.add("connect-point", connectPoint)
.add("ip-addresses", ipAddresses)
.add("mac-address", macAddress)
.add("vlan", vlan)
.toString();
}
}
......
......@@ -15,17 +15,14 @@
*/
package org.onosproject.net.host.impl;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
import org.jboss.netty.util.Timeout;
import org.jboss.netty.util.TimerTask;
import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.util.Timer;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
......@@ -43,11 +40,15 @@ import org.onosproject.net.packet.DefaultOutboundPacket;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketService;
import org.onosproject.net.provider.ProviderId;
import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IpAddress;
import org.onlab.packet.MacAddress;
import org.onlab.util.Timer;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.TimeUnit;
/**
* Monitors hosts on the dataplane to detect changes in host data.
......@@ -182,7 +183,8 @@ public class HostMonitor implements TimerTask {
for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
if (ia.subnetAddress().contains(targetIp)) {
sendProbe(device.id(), port, targetIp,
ia.ipAddress(), portAddresses.mac());
ia.ipAddress(), portAddresses.mac(),
portAddresses.vlan());
}
}
}
......@@ -191,8 +193,8 @@ public class HostMonitor implements TimerTask {
}
private void sendProbe(DeviceId deviceId, Port port, IpAddress targetIp,
IpAddress sourceIp, MacAddress sourceMac) {
Ethernet arpPacket = buildArpRequest(targetIp, sourceIp, sourceMac);
IpAddress sourceIp, MacAddress sourceMac, VlanId vlan) {
Ethernet arpPacket = buildArpRequest(targetIp, sourceIp, sourceMac, vlan);
List<Instruction> instructions = new ArrayList<>();
instructions.add(Instructions.createOutput(port.number()));
......@@ -209,7 +211,7 @@ public class HostMonitor implements TimerTask {
}
private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
MacAddress sourceMac) {
MacAddress sourceMac, VlanId vlan) {
ARP arp = new ARP();
arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
......@@ -229,6 +231,10 @@ public class HostMonitor implements TimerTask {
.setSourceMACAddress(sourceMac)
.setPayload(arp);
if (!vlan.equals(VlanId.NONE)) {
ethernet.setVlanID(vlan.toShort());
}
return ethernet;
}
}
......
......@@ -15,16 +15,9 @@
*/
package org.onosproject.net.proxyarp.impl;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Deactivate;
......@@ -62,9 +55,15 @@ import org.onosproject.net.packet.PacketService;
import org.onosproject.net.proxyarp.ProxyArpService;
import org.slf4j.Logger;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.slf4j.LoggerFactory.getLogger;
@Component(immediate = true)
@Service
......@@ -131,6 +130,8 @@ public class ProxyArpManager implements ProxyArpService {
checkArgument(arp.getOpCode() == ARP.OP_REQUEST, NOT_ARP_REQUEST);
checkNotNull(inPort);
VlanId vlan = VlanId.vlanId(eth.getVlanID());
// If the request came from outside the network, only reply if it was
// for one of our external addresses.
if (isOutsidePort(inPort)) {
......@@ -159,7 +160,8 @@ public class ProxyArpManager implements ProxyArpService {
boolean matched = false;
for (PortAddresses pa : sourceAddresses) {
for (InterfaceIpAddress ia : pa.ipAddresses()) {
if (ia.ipAddress().equals(source)) {
if (ia.ipAddress().equals(source) &&
pa.vlan().equals(vlan)) {
matched = true;
sendTo(eth, pa.connectPoint());
}
......@@ -173,7 +175,6 @@ public class ProxyArpManager implements ProxyArpService {
// Continue with normal proxy ARP case
VlanId vlan = VlanId.vlanId(eth.getVlanID());
Set<Host> hosts = hostService.getHostsByIp(
Ip4Address.valueOf(arp.getTargetProtocolAddress()));
......
......@@ -31,6 +31,10 @@ import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onosproject.event.Event;
import org.onosproject.event.impl.TestEventDispatcher;
import org.onosproject.net.ConnectPoint;
......@@ -51,10 +55,6 @@ import org.onosproject.net.host.PortAddresses;
import org.onosproject.net.provider.AbstractProvider;
import org.onosproject.net.provider.ProviderId;
import org.onosproject.store.trivial.impl.SimpleHostStore;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
......@@ -231,7 +231,7 @@ public class HostManagerTest {
@Test
public void bindAddressesToPort() {
PortAddresses add1 =
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
mgr.bindAddressesToPort(add1);
Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
......@@ -241,7 +241,8 @@ public class HostManagerTest {
// Add some more addresses and check that they're added correctly
PortAddresses add2 =
new PortAddresses(CP1, Sets.newHashSet(IA3), null);
new PortAddresses(CP1, Sets.newHashSet(IA3), null,
VlanId.vlanId((short) 2));
mgr.bindAddressesToPort(add2);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
......@@ -250,7 +251,7 @@ public class HostManagerTest {
assertTrue(storedAddresses.contains(add1));
assertTrue(storedAddresses.contains(add2));
PortAddresses add3 = new PortAddresses(CP1, null, MAC2);
PortAddresses add3 = new PortAddresses(CP1, null, MAC2, VlanId.NONE);
mgr.bindAddressesToPort(add3);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
......@@ -264,7 +265,7 @@ public class HostManagerTest {
@Test
public void unbindAddressesFromPort() {
PortAddresses add1 =
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
mgr.bindAddressesToPort(add1);
Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
......@@ -273,7 +274,7 @@ public class HostManagerTest {
assertTrue(storedAddresses.contains(add1));
PortAddresses rem1 =
new PortAddresses(CP1, Sets.newHashSet(IA1), null);
new PortAddresses(CP1, Sets.newHashSet(IA1), null, VlanId.NONE);
mgr.unbindAddressesFromPort(rem1);
storedAddresses = mgr.getAddressBindingsForPort(CP1);
......@@ -292,7 +293,7 @@ public class HostManagerTest {
@Test
public void clearAddresses() {
PortAddresses add1 =
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
mgr.bindAddressesToPort(add1);
Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
......@@ -309,7 +310,7 @@ public class HostManagerTest {
@Test
public void getAddressBindingsForPort() {
PortAddresses add1 =
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
mgr.bindAddressesToPort(add1);
Set<PortAddresses> storedAddresses = mgr.getAddressBindingsForPort(CP1);
......@@ -325,7 +326,7 @@ public class HostManagerTest {
assertTrue(storedAddresses.isEmpty());
PortAddresses add1 =
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1);
new PortAddresses(CP1, Sets.newHashSet(IA1, IA2), MAC1, VlanId.NONE);
mgr.bindAddressesToPort(add1);
......@@ -334,7 +335,7 @@ public class HostManagerTest {
assertTrue(storedAddresses.size() == 1);
PortAddresses add2 =
new PortAddresses(CP2, Sets.newHashSet(IA3), MAC2);
new PortAddresses(CP2, Sets.newHashSet(IA3), MAC2, VlanId.NONE);
mgr.bindAddressesToPort(add2);
......
......@@ -37,6 +37,7 @@ import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onosproject.core.ApplicationId;
import org.onlab.packet.VlanId;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
......@@ -130,7 +131,7 @@ public class HostMonitorTest {
ConnectPoint cp = new ConnectPoint(devId, portNum);
PortAddresses pa =
new PortAddresses(cp, Collections.singleton(IA1), sourceMac);
new PortAddresses(cp, Collections.singleton(IA1), sourceMac, VlanId.NONE);
expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
.andReturn(Collections.<Host>emptySet()).anyTimes();
......@@ -165,6 +166,76 @@ public class HostMonitorTest {
final byte[] pktData = new byte[packet.data().remaining()];
packet.data().get(pktData);
eth.deserialize(pktData, 0, pktData.length);
assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
ARP arp = (ARP) eth.getPayload();
assertArrayEquals(SOURCE_ADDR.toOctets(),
arp.getSenderProtocolAddress());
assertArrayEquals(sourceMac.toBytes(),
arp.getSenderHardwareAddress());
assertArrayEquals(TARGET_IP_ADDR.toOctets(),
arp.getTargetProtocolAddress());
}
@Test
public void testMonitorHostDoesNotExistWithVlan() throws Exception {
HostManager hostManager = createMock(HostManager.class);
DeviceId devId = DeviceId.deviceId("fake");
short vlan = 5;
Device device = createMock(Device.class);
expect(device.id()).andReturn(devId).anyTimes();
replay(device);
PortNumber portNum = PortNumber.portNumber(1L);
Port port = createMock(Port.class);
expect(port.number()).andReturn(portNum).anyTimes();
replay(port);
TestDeviceService deviceService = new TestDeviceService();
deviceService.addDevice(device, Collections.singleton(port));
ConnectPoint cp = new ConnectPoint(devId, portNum);
PortAddresses pa =
new PortAddresses(cp, Collections.singleton(IA1), sourceMac,
VlanId.vlanId(vlan));
expect(hostManager.getHostsByIp(TARGET_IP_ADDR))
.andReturn(Collections.<Host>emptySet()).anyTimes();
expect(hostManager.getAddressBindingsForPort(cp))
.andReturn(Collections.singleton(pa)).anyTimes();
replay(hostManager);
TestPacketService packetService = new TestPacketService();
// Run the test
hostMonitor = new HostMonitor(deviceService, packetService, hostManager);
hostMonitor.addMonitoringFor(TARGET_IP_ADDR);
hostMonitor.run(null);
// Check that a packet was sent to our PacketService and that it has
// the properties we expect
assertEquals(1, packetService.packets.size());
OutboundPacket packet = packetService.packets.get(0);
// Check the output port is correct
assertEquals(1, packet.treatment().instructions().size());
Instruction instruction = packet.treatment().instructions().get(0);
assertTrue(instruction instanceof OutputInstruction);
OutputInstruction oi = (OutputInstruction) instruction;
assertEquals(portNum, oi.port());
// Check the output packet is correct (well the important bits anyway)
Ethernet eth = new Ethernet();
final byte[] pktData = new byte[packet.data().remaining()];
packet.data().get(pktData);
eth.deserialize(pktData, 0, pktData.length);
assertEquals(vlan, eth.getVlanID());
ARP arp = (ARP) eth.getPayload();
assertArrayEquals(SOURCE_ADDR.toOctets(),
arp.getSenderProtocolAddress());
......
......@@ -216,10 +216,12 @@ public class ProxyArpManagerTest {
InterfaceIpAddress ia2 = new InterfaceIpAddress(addr2, prefix2);
PortAddresses pa1 =
new PortAddresses(cp, Sets.newHashSet(ia1),
MacAddress.valueOf(2 * i - 1));
MacAddress.valueOf(2 * i - 1),
VlanId.vlanId((short) 1));
PortAddresses pa2 =
new PortAddresses(cp, Sets.newHashSet(ia2),
MacAddress.valueOf(2 * i));
MacAddress.valueOf(2 * i),
VlanId.NONE);
addresses.add(pa1);
addresses.add(pa2);
......@@ -269,7 +271,7 @@ public class ProxyArpManagerTest {
}
/**
* Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
* Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
* destination host is known.
* Verifies the correct ARP reply is sent out the correct port.
*/
......@@ -297,7 +299,7 @@ public class ProxyArpManagerTest {
}
/**
* Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
* Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
* destination host is not known.
* Verifies the ARP request is flooded out the correct edge ports.
*/
......@@ -320,7 +322,7 @@ public class ProxyArpManagerTest {
}
/**
* Tests {@link ProxyArpManager#reply(Ethernet)} in the case where the
* Tests {@link ProxyArpManager#reply(Ethernet, ConnectPoint)} in the case where the
* destination host is known for that IP address, but is not on the same
* VLAN as the source host.
* Verifies the ARP request is flooded out the correct edge ports.
......@@ -421,7 +423,7 @@ public class ProxyArpManagerTest {
}
/**
* Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
* Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
* destination host is known.
* Verifies the correct ARP request is sent out the correct port.
*/
......@@ -444,7 +446,7 @@ public class ProxyArpManagerTest {
}
/**
* Tests {@link ProxyArpManager#forward(Ethernet)} in the case where the
* Tests {@link ProxyArpManager#forward(Ethernet, ConnectPoint)} in the case where the
* destination host is not known.
* Verifies the correct ARP request is flooded out the correct edge ports.
*/
......
......@@ -15,10 +15,7 @@
*/
package org.onosproject.provider.of.flow.impl;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.List;
import com.google.common.collect.Lists;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.Ip6Prefix;
......@@ -63,7 +60,9 @@ import org.projectfloodlight.openflow.types.OFVlanVidMatch;
import org.projectfloodlight.openflow.types.VlanPcp;
import org.slf4j.Logger;
import com.google.common.collect.Lists;
import java.util.List;
import static org.slf4j.LoggerFactory.getLogger;
public class FlowEntryBuilder {
private final Logger log = getLogger(getClass());
......@@ -380,8 +379,19 @@ public class FlowEntryBuilder {
builder.matchVlanPcp(vlanPcp);
break;
case VLAN_VID:
VlanId vlanId = VlanId.vlanId(match.get(MatchField.VLAN_VID).getVlan());
builder.matchVlanId(vlanId);
VlanId vlanId = null;
if (match.isPartiallyMasked(MatchField.VLAN_VID)) {
Masked<OFVlanVidMatch> masked = match.getMasked(MatchField.VLAN_VID);
if (masked.getValue().equals(OFVlanVidMatch.PRESENT)
&& masked.getMask().equals(OFVlanVidMatch.PRESENT)) {
vlanId = VlanId.ANY;
}
} else {
vlanId = VlanId.vlanId(match.get(MatchField.VLAN_VID).getVlan());
}
if (vlanId != null) {
builder.matchVlanId(vlanId);
}
break;
case TCP_DST:
builder.matchTcpDst((short) match.get(MatchField.TCP_DST).getPort());
......
......@@ -15,10 +15,11 @@
*/
package org.onosproject.provider.of.flow.impl;
import static org.slf4j.LoggerFactory.getLogger;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.onlab.packet.Ip6Address;
import org.onlab.packet.Ip6Prefix;
import org.onlab.packet.VlanId;
import org.onosproject.net.flow.FlowRule;
import org.onosproject.net.flow.TrafficSelector;
import org.onosproject.net.flow.criteria.Criteria;
......@@ -26,16 +27,14 @@ import org.onosproject.net.flow.criteria.Criteria.EthCriterion;
import org.onosproject.net.flow.criteria.Criteria.EthTypeCriterion;
import org.onosproject.net.flow.criteria.Criteria.IPCriterion;
import org.onosproject.net.flow.criteria.Criteria.IPProtocolCriterion;
import org.onosproject.net.flow.criteria.Criteria.Icmpv6CodeCriterion;
import org.onosproject.net.flow.criteria.Criteria.Icmpv6TypeCriterion;
import org.onosproject.net.flow.criteria.Criteria.LambdaCriterion;
import org.onosproject.net.flow.criteria.Criteria.PortCriterion;
import org.onosproject.net.flow.criteria.Criteria.TcpPortCriterion;
import org.onosproject.net.flow.criteria.Criteria.VlanIdCriterion;
import org.onosproject.net.flow.criteria.Criteria.VlanPcpCriterion;
import org.onosproject.net.flow.criteria.Criteria.Icmpv6TypeCriterion;
import org.onosproject.net.flow.criteria.Criteria.Icmpv6CodeCriterion;
import org.onosproject.net.flow.criteria.Criterion;
import org.onlab.packet.Ip4Address;
import org.onlab.packet.Ip4Prefix;
import org.projectfloodlight.openflow.protocol.OFFactory;
import org.projectfloodlight.openflow.protocol.OFFlowAdd;
import org.projectfloodlight.openflow.protocol.OFFlowDelete;
......@@ -60,6 +59,8 @@ import org.slf4j.Logger;
import java.util.Optional;
import static org.slf4j.LoggerFactory.getLogger;
/**
* Builder for OpenFlow flow mods based on FlowRules.
*/
......@@ -199,8 +200,14 @@ public abstract class FlowModBuilder {
break;
case VLAN_VID:
VlanIdCriterion vid = (VlanIdCriterion) c;
mBuilder.setExact(MatchField.VLAN_VID,
OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(vid.vlanId().toShort())));
if (vid.vlanId().equals(VlanId.ANY)) {
mBuilder.setMasked(MatchField.VLAN_VID, OFVlanVidMatch.PRESENT,
OFVlanVidMatch.PRESENT);
} else {
mBuilder.setExact(MatchField.VLAN_VID,
OFVlanVidMatch.ofVlanVid(VlanVid.ofVlan(vid.vlanId().toShort())));
}
break;
case TCP_DST:
tp = (TcpPortCriterion) c;
......
......@@ -25,7 +25,13 @@ public class VlanId {
// Based on convention used elsewhere? Check and change if needed
public static final short UNTAGGED = (short) 0xffff;
// In a traffic selector, this means that a VLAN ID must be present, but
// can have any value. We use the same value as OpenFlow, but this is not
// required.
public static final short ANY_VALUE = (short) 0x1000;
public static final VlanId NONE = VlanId.vlanId(UNTAGGED);
public static final VlanId ANY = VlanId.vlanId(ANY_VALUE);
// A VLAN ID is actually 12 bits of a VLAN tag.
public static final short MAX_VLAN = 4095;
......@@ -47,6 +53,10 @@ public class VlanId {
return new VlanId();
}
if (value == ANY_VALUE) {
return new VlanId(ANY_VALUE);
}
if (value > MAX_VLAN) {
throw new IllegalArgumentException(
"value exceeds allowed maximum VLAN ID value (4095)");
......@@ -83,6 +93,9 @@ public class VlanId {
@Override
public String toString() {
if (this.value == ANY_VALUE) {
return "Any";
}
return String.valueOf(this.value);
}
}
......