/* * Copyright 2014-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.provider.host.impl; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.util.concurrent.MoreExecutors; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.onlab.osgi.ComponentContextAdapter; import org.onlab.packet.ARP; import org.onlab.packet.ChassisId; import org.onlab.packet.DHCP; import org.onlab.packet.DHCPOption; import org.onlab.packet.DHCPPacketType; import org.onlab.packet.Ethernet; import org.onlab.packet.ICMP6; import org.onlab.packet.IPv4; import org.onlab.packet.IPv6; import org.onlab.packet.Ip6Address; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; import org.onlab.packet.UDP; import org.onlab.packet.VlanId; import org.onlab.packet.ndp.NeighborAdvertisement; import org.onlab.packet.ndp.NeighborSolicitation; import org.onlab.packet.ndp.RouterAdvertisement; import org.onlab.packet.ndp.RouterSolicitation; import org.onosproject.cfg.ComponentConfigAdapter; import org.onosproject.core.ApplicationId; import org.onosproject.core.CoreService; import org.onosproject.core.DefaultApplicationId; import org.onosproject.net.ConnectPoint; import org.onosproject.net.DefaultDevice; import org.onosproject.net.DefaultHost; import org.onosproject.net.DefaultPort; import org.onosproject.net.Device; import org.onosproject.net.DeviceId; import org.onosproject.net.Host; import org.onosproject.net.HostId; import org.onosproject.net.HostLocation; import org.onosproject.net.device.DeviceEvent; import org.onosproject.net.device.DeviceListener; import org.onosproject.net.device.DeviceServiceAdapter; import org.onosproject.net.host.HostDescription; import org.onosproject.net.host.HostProvider; import org.onosproject.net.host.HostProviderRegistry; import org.onosproject.net.host.HostProviderService; import org.onosproject.net.host.HostServiceAdapter; import org.onosproject.net.packet.DefaultInboundPacket; import org.onosproject.net.packet.InboundPacket; import org.onosproject.net.packet.PacketContextAdapter; import org.onosproject.net.packet.PacketProcessor; import org.onosproject.net.packet.PacketServiceAdapter; import org.onosproject.net.provider.AbstractProviderService; import org.onosproject.net.provider.ProviderId; import org.onosproject.net.topology.Topology; import org.onosproject.net.topology.TopologyServiceAdapter; import java.nio.ByteBuffer; import java.util.Collections; import java.util.Dictionary; import java.util.Hashtable; import java.util.List; import java.util.Set; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.onlab.packet.VlanId.vlanId; import static org.onosproject.net.Device.Type.SWITCH; import static org.onosproject.net.DeviceId.deviceId; import static org.onosproject.net.HostId.hostId; import static org.onosproject.net.PortNumber.portNumber; import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED; import static org.onosproject.net.device.DeviceEvent.Type.DEVICE_REMOVED; import static org.onosproject.net.device.DeviceEvent.Type.PORT_UPDATED; public class HostLocationProviderTest { private static final ProviderId PROVIDER_ID = new ProviderId("of", "org.onosproject.provider.host"); private static final Integer INPORT = 10; private static final Integer INPORT2 = 11; private static final String DEV1 = "of:1"; private static final String DEV2 = "of:2"; private static final String DEV3 = "of:3"; private static final String DEV4 = "of:4"; private static final String DEV5 = "of:5"; private static final String DEV6 = "of:6"; private static final VlanId VLAN = vlanId(); // IPv4 Host private static final MacAddress MAC = MacAddress.valueOf("00:00:11:00:00:01"); private static final MacAddress BCMAC = MacAddress.valueOf("ff:ff:ff:ff:ff:ff"); private static final byte[] IP = new byte[]{10, 0, 0, 1}; private static final IpAddress IP_ADDRESS = IpAddress.valueOf(IpAddress.Version.INET, IP); private static final HostLocation LOCATION = new HostLocation(deviceId(DEV1), portNumber(INPORT), 0L); private static final DefaultHost HOST = new DefaultHost(PROVIDER_ID, hostId(MAC), MAC, VLAN, LOCATION, ImmutableSet.of(IP_ADDRESS)); // IPv6 Host private static final MacAddress MAC2 = MacAddress.valueOf("00:00:22:00:00:02"); private static final MacAddress BCMAC2 = MacAddress.valueOf("33:33:00:00:00:01"); private static final byte[] IP2 = Ip6Address.valueOf("1000::1").toOctets(); private static final IpAddress IP_ADDRESS2 = IpAddress.valueOf(IpAddress.Version.INET6, IP2); private static final HostLocation LOCATION2 = new HostLocation(deviceId(DEV4), portNumber(INPORT), 0L); private static final DefaultHost HOST2 = new DefaultHost(PROVIDER_ID, hostId(MAC2), MAC2, VLAN, LOCATION2, ImmutableSet.of(IP_ADDRESS2)); // DHCP Server private static final MacAddress MAC3 = MacAddress.valueOf("00:00:33:00:00:03"); private static final byte[] IP3 = new byte[]{10, 0, 0, 2}; private static final IpAddress IP_ADDRESS3 = IpAddress.valueOf(IpAddress.Version.INET, IP3); private static final HostLocation LOCATION3 = new HostLocation(deviceId(DEV1), portNumber(INPORT2), 0L); private static final DefaultHost HOST3 = new DefaultHost(PROVIDER_ID, hostId(MAC3), MAC3, VLAN, LOCATION3, ImmutableSet.of(IP_ADDRESS3)); private static final ComponentContextAdapter CTX_FOR_REMOVE = new ComponentContextAdapter() { @Override public Dictionary getProperties() { Hashtable<String, String> props = new Hashtable<>(); props.put("hostRemovalEnabled", "true"); return props; } }; public static final ComponentContextAdapter CTX_FOR_NO_REMOVE = new ComponentContextAdapter() { @Override public Dictionary getProperties() { return new Hashtable(); } }; private final HostLocationProvider provider = new HostLocationProvider(); private final TestHostRegistry hostRegistry = new TestHostRegistry(); private final TestTopologyService topoService = new TestTopologyService(); private final TestDeviceService deviceService = new TestDeviceService(); private final TestHostService hostService = new TestHostService(); private final TestPacketService packetService = new TestPacketService(); private PacketProcessor testProcessor; private CoreService coreService; private TestHostProviderService providerService; private ApplicationId appId = new DefaultApplicationId(100, "org.onosproject.provider.host"); @Before public void setUp() { coreService = createMock(CoreService.class); expect(coreService.registerApplication(appId.name())) .andReturn(appId).anyTimes(); replay(coreService); provider.cfgService = new ComponentConfigAdapter(); provider.coreService = coreService; provider.providerRegistry = hostRegistry; provider.topologyService = topoService; provider.packetService = packetService; provider.deviceService = deviceService; provider.hostService = hostService; provider.activate(CTX_FOR_NO_REMOVE); provider.eventHandler = MoreExecutors.newDirectExecutorService(); } @Test public void basics() { assertNotNull("registration expected", providerService); assertEquals("incorrect provider", provider, providerService.provider()); } @Test public void events() { // New host. Expect one additional host description. testProcessor.process(new TestArpPacketContext(DEV1)); assertThat("New host expected", providerService.descriptions.size(), is(1)); // The host moved to new switch. Expect one additional host description. // The second host description should have a different location. testProcessor.process(new TestArpPacketContext(DEV2)); assertThat("Host motion expected", providerService.descriptions.size(), is(2)); HostLocation loc1 = providerService.descriptions.get(0).location(); HostLocation loc2 = providerService.descriptions.get(1).location(); assertNotEquals("Host location should be different", loc1, loc2); // The host was misheard on a spine. Expect no additional host description. testProcessor.process(new TestArpPacketContext(DEV3)); assertThat("Host misheard on spine switch", providerService.descriptions.size(), is(2)); providerService.clear(); // New host. Expect one additional host description. testProcessor.process(new TestNaPacketContext(DEV4)); assertThat("New host expected", providerService.descriptions.size(), is(1)); // The host moved to new switch. Expect one additional host description. // The second host description should have a different location. testProcessor.process(new TestNaPacketContext(DEV5)); assertThat("Host motion expected", providerService.descriptions.size(), is(2)); loc1 = providerService.descriptions.get(0).location(); loc2 = providerService.descriptions.get(1).location(); assertNotEquals("Host location should be different", loc1, loc2); // The host was misheard on a spine. Expect no additional host description. testProcessor.process(new TestNaPacketContext(DEV6)); assertThat("Host misheard on spine switch", providerService.descriptions.size(), is(2)); } @Test public void removeHostByDeviceRemove() { provider.modified(CTX_FOR_REMOVE); testProcessor.process(new TestArpPacketContext(DEV1)); testProcessor.process(new TestNaPacketContext(DEV4)); Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH, "m", "h", "s", "n", new ChassisId(0L)); deviceService.listener.event(new DeviceEvent(DEVICE_REMOVED, device)); assertEquals("incorrect remove count", 2, providerService.removeCount); device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH, "m", "h", "s", "n", new ChassisId(0L)); deviceService.listener.event(new DeviceEvent(DEVICE_REMOVED, device)); assertEquals("incorrect remove count", 3, providerService.removeCount); } @Test public void removeHostByDeviceOffline() { provider.modified(CTX_FOR_REMOVE); testProcessor.process(new TestArpPacketContext(DEV1)); testProcessor.process(new TestArpPacketContext(DEV4)); Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH, "m", "h", "s", "n", new ChassisId(0L)); deviceService.listener.event(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device)); assertEquals("incorrect remove count", 2, providerService.removeCount); device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH, "m", "h", "s", "n", new ChassisId(0L)); deviceService.listener.event(new DeviceEvent(DEVICE_AVAILABILITY_CHANGED, device)); assertEquals("incorrect remove count", 3, providerService.removeCount); } @Test public void removeHostByDevicePortDown() { provider.modified(CTX_FOR_REMOVE); testProcessor.process(new TestArpPacketContext(DEV1)); testProcessor.process(new TestArpPacketContext(DEV4)); Device device = new DefaultDevice(ProviderId.NONE, deviceId(DEV1), SWITCH, "m", "h", "s", "n", new ChassisId(0L)); deviceService.listener.event(new DeviceEvent(PORT_UPDATED, device, new DefaultPort(device, portNumber(INPORT), false))); assertEquals("incorrect remove count", 1, providerService.removeCount); device = new DefaultDevice(ProviderId.NONE, deviceId(DEV4), SWITCH, "m", "h", "s", "n", new ChassisId(0L)); deviceService.listener.event(new DeviceEvent(PORT_UPDATED, device, new DefaultPort(device, portNumber(INPORT), false))); assertEquals("incorrect remove count", 2, providerService.removeCount); } /** * When receiving ARP, updates location and IP. */ @Test public void receiveArp() { testProcessor.process(new TestArpPacketContext(DEV1)); assertThat("receiveArp. One host description expected", providerService.descriptions.size(), is(1)); HostDescription descr = providerService.descriptions.get(0); assertThat(descr.location(), is(LOCATION)); assertThat(descr.hwAddress(), is(MAC)); assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS)); assertThat(descr.vlan(), is(VLAN)); } /** * When receiving IPv4, updates location only. */ @Test public void receiveIpv4() { testProcessor.process(new TestIpv4PacketContext(DEV1)); assertThat("receiveIpv4. One host description expected", providerService.descriptions.size(), is(1)); HostDescription descr = providerService.descriptions.get(0); assertThat(descr.location(), is(LOCATION)); assertThat(descr.hwAddress(), is(MAC)); assertThat(descr.ipAddress().size(), is(0)); assertThat(descr.vlan(), is(VLAN)); } /** * When receiving DHCP REQUEST, update MAC, location of client. * When receiving DHCP ACK, update MAC, location of server and IP of client. */ @Test public void receiveDhcp() { // DHCP Request testProcessor.process(new TestDhcpRequestPacketContext(DEV1)); assertThat("receiveDhcpRequest. One host description expected", providerService.descriptions.size(), is(1)); // Should learn the MAC and location of DHCP client HostDescription descr = providerService.descriptions.get(0); assertThat(descr.location(), is(LOCATION)); assertThat(descr.hwAddress(), is(MAC)); assertThat(descr.ipAddress().size(), is(0)); assertThat(descr.vlan(), is(VLAN)); // DHCP Ack testProcessor.process(new TestDhcpAckPacketContext(DEV1)); assertThat("receiveDhcpAck. Two additional host descriptions expected", providerService.descriptions.size(), is(3)); // Should learn the IP of DHCP client HostDescription descr2 = providerService.descriptions.get(1); assertThat(descr2.location(), is(LOCATION)); assertThat(descr2.hwAddress(), is(MAC)); assertThat(descr2.ipAddress().size(), is(1)); assertTrue(descr2.ipAddress().contains(IP_ADDRESS)); assertThat(descr2.vlan(), is(VLAN)); // Should also learn the MAC, location of DHCP server HostDescription descr3 = providerService.descriptions.get(2); assertThat(descr3.location(), is(LOCATION3)); assertThat(descr3.hwAddress(), is(MAC3)); assertThat(descr3.ipAddress().size(), is(0)); assertThat(descr3.vlan(), is(VLAN)); } /** * When receiving NeighborAdvertisement, updates location and IP. */ @Test public void receiveNa() { testProcessor.process(new TestNaPacketContext(DEV4)); assertThat("receiveNa. One host description expected", providerService.descriptions.size(), is(1)); HostDescription descr = providerService.descriptions.get(0); assertThat(descr.location(), is(LOCATION2)); assertThat(descr.hwAddress(), is(MAC2)); assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS2)); assertThat(descr.vlan(), is(VLAN)); } /** * When receiving NeighborSolicitation, updates location and IP. */ @Test public void receiveNs() { testProcessor.process(new TestNsPacketContext(DEV4)); assertThat("receiveNs. One host description expected", providerService.descriptions.size(), is(1)); HostDescription descr = providerService.descriptions.get(0); assertThat(descr.location(), is(LOCATION2)); assertThat(descr.hwAddress(), is(MAC2)); assertThat(descr.ipAddress().toArray()[0], is(IP_ADDRESS2)); assertThat(descr.vlan(), is(VLAN)); } /** * When receiving RouterAdvertisement, ignores it. */ @Test public void receivesRa() { testProcessor.process(new TestRAPacketContext(DEV4)); assertThat("receivesRa. No host description expected", providerService.descriptions.size(), is(0)); } /** * When receiving RouterSolicitation, ignores it. */ @Test public void receiveRs() { testProcessor.process(new TestRSPacketContext(DEV4)); assertThat("receiveRs. No host description expected", providerService.descriptions.size(), is(0)); } /** * When receiving Duplicate Address Detection (DAD), ignores it. */ @Test public void receiveDad() { testProcessor.process(new TestDadPacketContext(DEV4)); assertThat("receiveDad. No host description expected", providerService.descriptions.size(), is(0)); } /** * When receiving IPv6 multicast packet, ignores it. */ @Test public void receiveIpv6Multicast() { testProcessor.process(new TestIpv6McastPacketContext(DEV4)); assertThat("receiveIpv6Multicast. No host description expected", providerService.descriptions.size(), is(0)); } /** * When receiving IPv6 unicast packet, updates location only. */ @Test public void receiveIpv6Unicast() { testProcessor.process(new TestIpv6PacketContext(DEV4)); assertThat("receiveIpv6Unicast. One host description expected", providerService.descriptions.size(), is(1)); HostDescription descr = providerService.descriptions.get(0); assertThat(descr.location(), is(LOCATION2)); assertThat(descr.hwAddress(), is(MAC2)); assertThat(descr.ipAddress().size(), is(0)); assertThat(descr.vlan(), is(VLAN)); } @After public void tearDown() { provider.deactivate(); provider.coreService = null; provider.providerRegistry = null; } private class TestHostRegistry implements HostProviderRegistry { @Override public HostProviderService register(HostProvider provider) { providerService = new TestHostProviderService(provider); return providerService; } @Override public void unregister(HostProvider provider) { } @Override public Set<ProviderId> getProviders() { return null; } } private class TestHostProviderService extends AbstractProviderService<HostProvider> implements HostProviderService { List<HostDescription> descriptions = Lists.newArrayList(); int removeCount; public void clear() { descriptions.clear(); removeCount = 0; } protected TestHostProviderService(HostProvider provider) { super(provider); } @Override public void hostDetected(HostId hostId, HostDescription hostDescription, boolean replaceIps) { descriptions.add(hostDescription); } @Override public void hostVanished(HostId hostId) { removeCount++; } @Override public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { } } private class TestPacketService extends PacketServiceAdapter { @Override public void addProcessor(PacketProcessor processor, int priority) { testProcessor = processor; } } private class TestTopologyService extends TopologyServiceAdapter { @Override public boolean isInfrastructure(Topology topology, ConnectPoint connectPoint) { //simulate DPID3 as an infrastructure switch if ((connectPoint.deviceId()).equals(deviceId(DEV3)) || connectPoint.deviceId().equals(deviceId(DEV6))) { return true; } return false; } } /** * Generates ARP packet. */ private class TestArpPacketContext extends PacketContextAdapter { private final String deviceId; public TestArpPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { ARP arp = new ARP(); arp.setSenderProtocolAddress(IP) .setSenderHardwareAddress(MAC.toBytes()) .setTargetHardwareAddress(BCMAC.toBytes()) .setTargetProtocolAddress(IP); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_ARP) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC.toBytes()) .setDestinationMACAddress(BCMAC) .setPayload(arp); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates IPv4 Unicast packet. */ private class TestIpv4PacketContext extends PacketContextAdapter { private final String deviceId; public TestIpv4PacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { IPv4 ipv4 = new IPv4(); ipv4.setDestinationAddress("10.0.0.1"); ipv4.setSourceAddress(IP_ADDRESS.toString()); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV4) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC) .setDestinationMACAddress(MacAddress.valueOf("00:00:00:00:00:01")) .setPayload(ipv4); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates DHCP REQUEST packet. */ private class TestDhcpRequestPacketContext extends PacketContextAdapter { private final String deviceId; public TestDhcpRequestPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { byte[] dhcpMsgType = new byte[1]; dhcpMsgType[0] = (byte) DHCPPacketType.DHCPREQUEST.getValue(); DHCPOption dhcpOption = new DHCPOption(); dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()); dhcpOption.setData(dhcpMsgType); dhcpOption.setLength((byte) 1); DHCP dhcp = new DHCP(); dhcp.setOptions(Collections.singletonList(dhcpOption)); dhcp.setClientHardwareAddress(MAC.toBytes()); UDP udp = new UDP(); udp.setPayload(dhcp); udp.setSourcePort(UDP.DHCP_CLIENT_PORT); udp.setDestinationPort(UDP.DHCP_SERVER_PORT); IPv4 ipv4 = new IPv4(); ipv4.setPayload(udp); ipv4.setDestinationAddress(IP_ADDRESS3.toString()); ipv4.setSourceAddress(IP_ADDRESS.toString()); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV4) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC) .setDestinationMACAddress(MAC3) .setPayload(ipv4); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates DHCP ACK packet. */ private class TestDhcpAckPacketContext extends PacketContextAdapter { private final String deviceId; public TestDhcpAckPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { byte[] dhcpMsgType = new byte[1]; dhcpMsgType[0] = (byte) DHCPPacketType.DHCPACK.getValue(); DHCPOption dhcpOption = new DHCPOption(); dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()); dhcpOption.setData(dhcpMsgType); dhcpOption.setLength((byte) 1); DHCP dhcp = new DHCP(); dhcp.setOptions(Collections.singletonList(dhcpOption)); dhcp.setClientHardwareAddress(MAC.toBytes()); dhcp.setYourIPAddress(IP_ADDRESS.getIp4Address().toInt()); UDP udp = new UDP(); udp.setPayload(dhcp); udp.setSourcePort(UDP.DHCP_SERVER_PORT); udp.setDestinationPort(UDP.DHCP_CLIENT_PORT); IPv4 ipv4 = new IPv4(); ipv4.setPayload(udp); ipv4.setDestinationAddress(IP_ADDRESS.toString()); ipv4.setSourceAddress(IP_ADDRESS3.toString()); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV4) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC3) .setDestinationMACAddress(MAC) .setPayload(ipv4); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT2)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates NeighborAdvertisement packet. */ private class TestNaPacketContext extends PacketContextAdapter { private final String deviceId; public TestNaPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { NeighborAdvertisement na = new NeighborAdvertisement(); ICMP6 icmp6 = new ICMP6(); icmp6.setPayload(na); IPv6 ipv6 = new IPv6(); ipv6.setPayload(icmp6); ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets()); ipv6.setSourceAddress(IP2); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV6) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC2.toBytes()) .setDestinationMACAddress(BCMAC2) .setPayload(ipv6); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates NeighborSolicitation packet. */ private class TestNsPacketContext extends PacketContextAdapter { private final String deviceId; public TestNsPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { NeighborSolicitation ns = new NeighborSolicitation(); ICMP6 icmp6 = new ICMP6(); icmp6.setPayload(ns); IPv6 ipv6 = new IPv6(); ipv6.setPayload(icmp6); ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1:ff00:0000").toOctets()); ipv6.setSourceAddress(IP2); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV6) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC2.toBytes()) .setDestinationMACAddress(BCMAC2) .setPayload(ipv6); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates Duplicate Address Detection packet. */ private class TestDadPacketContext extends PacketContextAdapter { private final String deviceId; public TestDadPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { NeighborSolicitation ns = new NeighborSolicitation(); ICMP6 icmp6 = new ICMP6(); icmp6.setPayload(ns); IPv6 ipv6 = new IPv6(); ipv6.setPayload(icmp6); ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets()); ipv6.setSourceAddress(Ip6Address.valueOf("::").toOctets()); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV6) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC2.toBytes()) .setDestinationMACAddress(BCMAC2) .setPayload(ipv6); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates Router Solicitation packet. */ private class TestRSPacketContext extends PacketContextAdapter { private final String deviceId; public TestRSPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { RouterSolicitation ns = new RouterSolicitation(); ICMP6 icmp6 = new ICMP6(); icmp6.setPayload(ns); IPv6 ipv6 = new IPv6(); ipv6.setPayload(icmp6); ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::2").toOctets()); ipv6.setSourceAddress(Ip6Address.valueOf("::").toOctets()); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV6) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC2.toBytes()) .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:02")) .setPayload(ipv6); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates Router Advertisement packet. */ private class TestRAPacketContext extends PacketContextAdapter { private final String deviceId; public TestRAPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { RouterAdvertisement ns = new RouterAdvertisement(); ICMP6 icmp6 = new ICMP6(); icmp6.setPayload(ns); IPv6 ipv6 = new IPv6(); ipv6.setPayload(icmp6); ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets()); ipv6.setSourceAddress(IP2); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV6) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC2.toBytes()) .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:01")) .setPayload(ipv6); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates IPv6 Multicast packet. */ private class TestIpv6McastPacketContext extends PacketContextAdapter { private final String deviceId; public TestIpv6McastPacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { IPv6 ipv6 = new IPv6(); ipv6.setDestinationAddress(Ip6Address.valueOf("ff02::1").toOctets()); ipv6.setSourceAddress(IP2); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV6) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC2.toBytes()) .setDestinationMACAddress(MacAddress.valueOf("33:33:00:00:00:01")) .setPayload(ipv6); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } /** * Generates IPv6 Unicast packet. */ private class TestIpv6PacketContext extends PacketContextAdapter { private final String deviceId; public TestIpv6PacketContext(String deviceId) { super(0, null, null, false); this.deviceId = deviceId; } @Override public InboundPacket inPacket() { IPv6 ipv6 = new IPv6(); ipv6.setDestinationAddress(Ip6Address.valueOf("1000::1").toOctets()); ipv6.setSourceAddress(IP2); Ethernet eth = new Ethernet(); eth.setEtherType(Ethernet.TYPE_IPV6) .setVlanID(VLAN.toShort()) .setSourceMACAddress(MAC2) .setDestinationMACAddress(MacAddress.valueOf("00:00:00:00:00:01")) .setPayload(ipv6); ConnectPoint receivedFrom = new ConnectPoint(deviceId(deviceId), portNumber(INPORT)); return new DefaultInboundPacket(receivedFrom, eth, ByteBuffer.wrap(eth.serialize())); } } private class TestDeviceService extends DeviceServiceAdapter { private DeviceListener listener; @Override public void addListener(DeviceListener listener) { this.listener = listener; } @Override public Iterable<Device> getDevices() { return Collections.emptyList(); } } private class TestHostService extends HostServiceAdapter { @Override public Set<Host> getConnectedHosts(ConnectPoint connectPoint) { ConnectPoint cp1 = new ConnectPoint(deviceId(DEV1), portNumber(INPORT)); ConnectPoint cp2 = new ConnectPoint(deviceId(DEV4), portNumber(INPORT)); ConnectPoint cp3 = new ConnectPoint(deviceId(DEV1), portNumber(INPORT2)); if (connectPoint.equals(cp1)) { return ImmutableSet.of(HOST); } else if (connectPoint.equals(cp2)) { return ImmutableSet.of(HOST2); } else if (connectPoint.equals(cp3)) { return ImmutableSet.of(HOST3); } else { return ImmutableSet.of(); } } @Override public Set<Host> getConnectedHosts(DeviceId deviceId) { if (deviceId.equals(deviceId(DEV1))) { return ImmutableSet.of(HOST, HOST3); } else if (deviceId.equals(deviceId(DEV4))) { return ImmutableSet.of(HOST2); } else { return ImmutableSet.of(); } } @Override public Host getHost(HostId hostId) { if (hostId.equals(HostId.hostId(MAC, VLAN))) { return HOST; } else if (hostId.equals(HostId.hostId(MAC2, VLAN))) { return HOST2; } else if (hostId.equals(HostId.hostId(MAC3, VLAN))) { return HOST3; } return null; } } }