blob: d492e39f569a0ea3446d1a97219997cf84e97a49 [file] [log] [blame]
/*
* Copyright 2014-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.net.host.impl;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.onlab.packet.ARP;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv6;
import org.onlab.packet.IpAddress;
import org.onlab.packet.IpPrefix;
import org.onlab.packet.MacAddress;
import org.onlab.packet.VlanId;
import org.onlab.packet.ndp.NeighborSolicitation;
import org.onosproject.net.intf.Interface;
import org.onosproject.net.intf.InterfaceService;
import org.onosproject.net.ConnectPoint;
import org.onosproject.net.Device;
import org.onosproject.net.DeviceId;
import org.onosproject.net.Host;
import org.onosproject.net.Port;
import org.onosproject.net.PortNumber;
import org.onosproject.net.device.DeviceServiceAdapter;
import org.onosproject.net.edge.EdgePortService;
import org.onosproject.net.flow.instructions.Instruction;
import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
import org.onosproject.net.host.HostProvider;
import org.onosproject.net.host.InterfaceIpAddress;
import org.onosproject.net.packet.OutboundPacket;
import org.onosproject.net.packet.PacketServiceAdapter;
import org.onosproject.net.provider.ProviderId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.verify;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class HostMonitorTest {
private static final IpAddress TARGET_IPV4_ADDR =
IpAddress.valueOf("10.0.0.1");
private static final IpAddress SOURCE_IPV4_ADDR =
IpAddress.valueOf("10.0.0.99");
private static final InterfaceIpAddress IA1 =
new InterfaceIpAddress(SOURCE_IPV4_ADDR, IpPrefix.valueOf("10.0.0.0/24"));
private MacAddress sourceMac = MacAddress.valueOf(1L);
private static final IpAddress TARGET_IPV6_ADDR =
IpAddress.valueOf("1000::1");
private static final IpAddress SOURCE_IPV6_ADDR =
IpAddress.valueOf("1000::f");
private static final InterfaceIpAddress IA2 =
new InterfaceIpAddress(SOURCE_IPV6_ADDR, IpPrefix.valueOf("1000::/64"));
private MacAddress sourceMac2 = MacAddress.valueOf(2L);
private EdgePortService edgePortService;
private HostMonitor hostMonitor;
@Before
public void setUp() {
edgePortService = createMock(EdgePortService.class);
expect(edgePortService.isEdgePoint(anyObject(ConnectPoint.class)))
.andReturn(true).anyTimes();
replay(edgePortService);
}
@After
public void shutdown() {
hostMonitor.shutdown();
}
@Test
public void testMonitorIpv4HostExists() throws Exception {
testMonitorHostExists(TARGET_IPV4_ADDR);
}
@Test
public void testMonitorIpv6HostExists() throws Exception {
testMonitorHostExists(TARGET_IPV6_ADDR);
}
private void testMonitorHostExists(IpAddress hostIp) throws Exception {
ProviderId id = new ProviderId("fake://", "id");
Host host = createMock(Host.class);
expect(host.providerId()).andReturn(id).anyTimes();
replay(host);
HostManager hostManager = createMock(HostManager.class);
expect(hostManager.getHostsByIp(hostIp))
.andReturn(Collections.singleton(host))
.anyTimes();
replay(hostManager);
HostProvider hostProvider = createMock(HostProvider.class);
expect(hostProvider.id()).andReturn(id).anyTimes();
hostProvider.triggerProbe(host);
expectLastCall().times(2);
replay(hostProvider);
hostMonitor = new HostMonitor(null, hostManager, null, edgePortService, null);
hostMonitor.registerHostProvider(hostProvider);
hostMonitor.addMonitoringFor(hostIp);
hostMonitor.run();
verify(hostProvider);
}
@Test
public void testMonitorIpv4HostDoesNotExist() throws Exception {
HostManager hostManager = createMock(HostManager.class);
DeviceId devId = DeviceId.deviceId("fake");
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();
expect(port.isEnabled()).andReturn(true).anyTimes();
replay(port);
TestDeviceService deviceService = new TestDeviceService();
deviceService.addDevice(device, Collections.singleton(port));
ConnectPoint cp = new ConnectPoint(devId, portNum);
expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR))
.andReturn(Collections.emptySet()).anyTimes();
replay(hostManager);
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterfaces(TARGET_IPV4_ADDR))
.andReturn(Collections.singleton(new Interface(Interface.NO_INTERFACE_NAME,
cp, Collections.singletonList(IA1), sourceMac, VlanId.NONE)))
.anyTimes();
replay(interfaceService);
TestPacketService packetService = new TestPacketService();
// Run the test
hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService, deviceService);
hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR);
hostMonitor.run();
// Check that a packet was sent to our PacketService and that it has
// the properties we expect
assertEquals(2, packetService.packets.size());
OutboundPacket packet = packetService.packets.get(0);
// Check the output port is correct
assertEquals(1, packet.treatment().immediate().size());
Instruction instruction = packet.treatment().immediate().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)
final byte[] pktData = new byte[packet.data().remaining()];
packet.data().get(pktData);
Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
ARP arp = (ARP) eth.getPayload();
assertArrayEquals(SOURCE_IPV4_ADDR.toOctets(),
arp.getSenderProtocolAddress());
assertArrayEquals(sourceMac.toBytes(),
arp.getSenderHardwareAddress());
assertArrayEquals(TARGET_IPV4_ADDR.toOctets(),
arp.getTargetProtocolAddress());
}
@Test
public void testMonitorIpv6HostDoesNotExist() throws Exception {
HostManager hostManager = createMock(HostManager.class);
DeviceId devId = DeviceId.deviceId("fake");
Device device = createMock(Device.class);
expect(device.id()).andReturn(devId).anyTimes();
replay(device);
PortNumber portNum = PortNumber.portNumber(2L);
Port port = createMock(Port.class);
expect(port.number()).andReturn(portNum).anyTimes();
expect(port.isEnabled()).andReturn(true).anyTimes();
replay(port);
TestDeviceService deviceService = new TestDeviceService();
deviceService.addDevice(device, Collections.singleton(port));
ConnectPoint cp = new ConnectPoint(devId, portNum);
expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR))
.andReturn(Collections.emptySet()).anyTimes();
replay(hostManager);
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterfaces(TARGET_IPV6_ADDR))
.andReturn(Collections.singleton(new Interface(Interface.NO_INTERFACE_NAME, cp,
Collections.singletonList(IA2), sourceMac2, VlanId.NONE)))
.anyTimes();
replay(interfaceService);
TestPacketService packetService = new TestPacketService();
// Run the test
hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService, deviceService);
hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR);
hostMonitor.run();
// Check that a packet was sent to our PacketService and that it has
// the properties we expect
assertEquals(2, packetService.packets.size());
OutboundPacket packet = packetService.packets.get(0);
// Check the output port is correct
assertEquals(1, packet.treatment().immediate().size());
Instruction instruction = packet.treatment().immediate().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)
final byte[] pktData = new byte[packet.data().remaining()];
packet.data().get(pktData);
Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
assertEquals(Ethernet.VLAN_UNTAGGED, eth.getVlanID());
IPv6 ipv6 = (IPv6) eth.getPayload();
assertArrayEquals(SOURCE_IPV6_ADDR.toOctets(), ipv6.getSourceAddress());
NeighborSolicitation ns =
(NeighborSolicitation) ipv6.getPayload().getPayload();
assertArrayEquals(sourceMac2.toBytes(), ns.getOptions().get(0).data());
assertArrayEquals(TARGET_IPV6_ADDR.toOctets(), ns.getTargetAddress());
}
@Test
public void testMonitorIpv4HostDoesNotExistWithVlan() 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();
expect(port.isEnabled()).andReturn(true).anyTimes();
replay(port);
TestDeviceService deviceService = new TestDeviceService();
deviceService.addDevice(device, Collections.singleton(port));
ConnectPoint cp = new ConnectPoint(devId, portNum);
expect(hostManager.getHostsByIp(TARGET_IPV4_ADDR))
.andReturn(Collections.emptySet()).anyTimes();
replay(hostManager);
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterfaces(TARGET_IPV4_ADDR))
.andReturn(Collections.singleton(new Interface(Interface.NO_INTERFACE_NAME, cp,
Collections.singletonList(IA1), sourceMac, VlanId.vlanId(vlan))))
.anyTimes();
replay(interfaceService);
TestPacketService packetService = new TestPacketService();
// Run the test
hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService, deviceService);
hostMonitor.addMonitoringFor(TARGET_IPV4_ADDR);
hostMonitor.run();
// Check that a packet was sent to our PacketService and that it has
// the properties we expect
assertEquals(2, packetService.packets.size());
OutboundPacket packet = packetService.packets.get(0);
// Check the output port is correct
assertEquals(1, packet.treatment().immediate().size());
Instruction instruction = packet.treatment().immediate().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)
final byte[] pktData = new byte[packet.data().remaining()];
packet.data().get(pktData);
Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
assertEquals(vlan, eth.getVlanID());
ARP arp = (ARP) eth.getPayload();
assertArrayEquals(SOURCE_IPV4_ADDR.toOctets(),
arp.getSenderProtocolAddress());
assertArrayEquals(sourceMac.toBytes(),
arp.getSenderHardwareAddress());
assertArrayEquals(TARGET_IPV4_ADDR.toOctets(),
arp.getTargetProtocolAddress());
}
@Test
public void testMonitorIpv6HostDoesNotExistWithVlan() 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();
expect(port.isEnabled()).andReturn(true).anyTimes();
replay(port);
TestDeviceService deviceService = new TestDeviceService();
deviceService.addDevice(device, Collections.singleton(port));
ConnectPoint cp = new ConnectPoint(devId, portNum);
expect(hostManager.getHostsByIp(TARGET_IPV6_ADDR))
.andReturn(Collections.emptySet()).anyTimes();
replay(hostManager);
InterfaceService interfaceService = createMock(InterfaceService.class);
expect(interfaceService.getMatchingInterfaces(TARGET_IPV6_ADDR))
.andReturn(Collections.singleton(new Interface(Interface.NO_INTERFACE_NAME, cp,
Collections.singletonList(IA2), sourceMac2, VlanId.vlanId(vlan))))
.anyTimes();
replay(interfaceService);
TestPacketService packetService = new TestPacketService();
// Run the test
hostMonitor = new HostMonitor(packetService, hostManager, interfaceService, edgePortService, deviceService);
hostMonitor.addMonitoringFor(TARGET_IPV6_ADDR);
hostMonitor.run();
// Check that a packet was sent to our PacketService and that it has
// the properties we expect
assertEquals(2, packetService.packets.size());
OutboundPacket packet = packetService.packets.get(0);
// Check the output port is correct
assertEquals(1, packet.treatment().immediate().size());
Instruction instruction = packet.treatment().immediate().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)
final byte[] pktData = new byte[packet.data().remaining()];
packet.data().get(pktData);
Ethernet eth = Ethernet.deserializer().deserialize(pktData, 0, pktData.length);
assertEquals(vlan, eth.getVlanID());
IPv6 ipv6 = (IPv6) eth.getPayload();
assertArrayEquals(SOURCE_IPV6_ADDR.toOctets(), ipv6.getSourceAddress());
NeighborSolicitation ns =
(NeighborSolicitation) ipv6.getPayload().getPayload();
assertArrayEquals(sourceMac2.toBytes(), ns.getOptions().get(0).data());
assertArrayEquals(TARGET_IPV6_ADDR.toOctets(), ns.getTargetAddress());
}
class TestPacketService extends PacketServiceAdapter {
List<OutboundPacket> packets = new ArrayList<>();
@Override
public void emit(OutboundPacket packet) {
packets.add(packet);
}
}
class TestDeviceService extends DeviceServiceAdapter {
List<Device> devices = Lists.newArrayList();
Multimap<DeviceId, Port> devicePorts = HashMultimap.create();
void addDevice(Device device, Set<Port> ports) {
devices.add(device);
for (Port p : ports) {
devicePorts.put(device.id(), p);
}
}
@Override
public Iterable<Device> getDevices() {
return devices;
}
@Override
public List<Port> getPorts(DeviceId deviceId) {
List<Port> ports = Lists.newArrayList();
for (Port p : devicePorts.get(deviceId)) {
ports.add(p);
}
return ports;
}
@Override
public Port getPort(ConnectPoint cp) {
return devicePorts.get(cp.deviceId()).stream()
.filter(p -> p.number().equals(cp.port()))
.findAny().orElse(null);
}
}
}