/* * Copyright 2015-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.dhcp.impl; import com.google.common.collect.ImmutableSet; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.onlab.packet.DHCP; import org.onlab.packet.DHCPOption; import org.onlab.packet.DHCPPacketType; import org.onlab.packet.Ethernet; import org.onlab.packet.IPv4; import org.onlab.packet.Ip4Address; import org.onlab.packet.IpAddress; import org.onlab.packet.MacAddress; import org.onlab.packet.UDP; import org.onosproject.cfg.ComponentConfigAdapter; import org.onosproject.core.CoreServiceAdapter; import org.onosproject.dhcp.DhcpStore; import org.onosproject.dhcp.IpAssignment; import org.onosproject.net.Host; import org.onosproject.net.HostId; import org.onosproject.net.config.NetworkConfigRegistryAdapter; 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.packet.DefaultInboundPacket; import org.onosproject.net.packet.DefaultPacketContext; import org.onosproject.net.packet.InboundPacket; import org.onosproject.net.packet.OutboundPacket; import org.onosproject.net.packet.PacketContext; import org.onosproject.net.packet.PacketProcessor; import org.onosproject.net.packet.PacketServiceAdapter; import org.onosproject.net.provider.AbstractProvider; import org.onosproject.net.provider.AbstractProviderService; import org.onosproject.net.provider.ProviderId; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.onosproject.net.NetTestTools.connectPoint; /** * Set of tests of the ONOS application component. */ public class DhcpManagerTest { private DhcpManager dhcpXManager; protected PacketProcessor packetProcessor; protected HostProviderService hostProviderService; private static final HostId CLIENT1_HOST = HostId.hostId(MacAddress.valueOf("1a:1a:1a:1a:1a:1a")); private static final String EXPECTED_IP = "10.2.0.2"; private static final Ip4Address BROADCAST = Ip4Address.valueOf("255.255.255.255"); private static final int TRANSACTION_ID = 1000; private static final ProviderId PID = new ProviderId("of", "foo"); @Before public void setUp() { dhcpXManager = new DhcpManager(); dhcpXManager.cfgService = new TestNetworkConfigRegistry(); dhcpXManager.packetService = new TestPacketService(); dhcpXManager.coreService = new TestCoreService(); dhcpXManager.dhcpStore = new TestDhcpStore(); hostProviderService = new TestHostProviderService(new TestHostProvider()); dhcpXManager.hostProviderService = hostProviderService; dhcpXManager.hostProviderRegistry = new TestHostRegistry(); dhcpXManager.componentConfigService = new TestComponentConfig(); dhcpXManager.activate(); } @After public void tearDown() { dhcpXManager.deactivate(); } /** * Tests the response to a DHCP Discover Packet. */ @Test public void testDiscover() { Ethernet reply = constructDhcpPacket(DHCPPacketType.DHCPDISCOVER); sendPacket(reply); } /** * Tests the response to a DHCP Request Packet. */ @Test public void testRequest() { Ethernet reply = constructDhcpPacket(DHCPPacketType.DHCPREQUEST); sendPacket(reply); } /** * Sends an Ethernet packet to the process method of the Packet Processor. * @param reply Ethernet packet */ private void sendPacket(Ethernet reply) { final ByteBuffer byteBuffer = ByteBuffer.wrap(reply.serialize()); InboundPacket inPacket = new DefaultInboundPacket(connectPoint("1", 1), reply, byteBuffer); PacketContext context = new TestPacketContext(127L, inPacket, null, false); packetProcessor.process(context); } /** * Constructs an Ethernet packet containing a DHCP Payload. * @param packetType DHCP Message Type * @return Ethernet packet */ private Ethernet constructDhcpPacket(DHCPPacketType packetType) { // Ethernet Frame. Ethernet ethReply = new Ethernet(); ethReply.setSourceMACAddress(CLIENT1_HOST.mac()); ethReply.setDestinationMACAddress(MacAddress.BROADCAST); ethReply.setEtherType(Ethernet.TYPE_IPV4); ethReply.setVlanID((short) 2); // IP Packet IPv4 ipv4Reply = new IPv4(); ipv4Reply.setSourceAddress(0); ipv4Reply.setDestinationAddress(BROADCAST.toInt()); ipv4Reply.setTtl((byte) 127); // UDP Datagram. UDP udpReply = new UDP(); udpReply.setSourcePort((byte) UDP.DHCP_CLIENT_PORT); udpReply.setDestinationPort((byte) UDP.DHCP_SERVER_PORT); // DHCP Payload. DHCP dhcpReply = new DHCP(); dhcpReply.setOpCode(DHCP.OPCODE_REQUEST); dhcpReply.setYourIPAddress(0); dhcpReply.setServerIPAddress(0); dhcpReply.setTransactionId(TRANSACTION_ID); dhcpReply.setClientHardwareAddress(CLIENT1_HOST.mac().toBytes()); dhcpReply.setHardwareType(DHCP.HWTYPE_ETHERNET); dhcpReply.setHardwareAddressLength((byte) 6); // DHCP Options. DHCPOption option = new DHCPOption(); List<DHCPOption> optionList = new ArrayList<>(); // DHCP Message Type. option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue()); option.setLength((byte) 1); byte[] optionData = {(byte) packetType.getValue()}; option.setData(optionData); optionList.add(option); // DHCP Requested IP. option = new DHCPOption(); option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue()); option.setLength((byte) 4); optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets(); option.setData(optionData); optionList.add(option); // End Option. option = new DHCPOption(); option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue()); option.setLength((byte) 1); optionList.add(option); dhcpReply.setOptions(optionList); udpReply.setPayload(dhcpReply); ipv4Reply.setPayload(udpReply); ethReply.setPayload(ipv4Reply); return ethReply; } /** * Validates the contents of the packet sent by the DHCP Manager. * @param packet Ethernet packet received */ private void validatePacket(Ethernet packet) { DHCP dhcpPacket = (DHCP) packet.getPayload().getPayload().getPayload(); assertEquals(MacAddress.valueOf(dhcpPacket.getClientHardwareAddress()), CLIENT1_HOST.mac()); assertEquals(Ip4Address.valueOf(dhcpPacket.getYourIPAddress()), Ip4Address.valueOf(EXPECTED_IP)); assertEquals(dhcpPacket.getTransactionId(), TRANSACTION_ID); } /** * Mocks the DHCPStore. */ private final class TestDhcpStore implements DhcpStore { public void populateIPPoolfromRange(Ip4Address startIP, Ip4Address endIP) { } public Ip4Address suggestIP(HostId hostId, Ip4Address requestedIP) { return Ip4Address.valueOf(EXPECTED_IP); } public boolean assignIP(HostId hostId, IpAssignment ipAssignment) { return true; } public void setDefaultTimeoutForPurge(int timeInSeconds) { } public Ip4Address releaseIP(HostId hostId) { return null; } public Map<HostId, IpAssignment> listAssignedMapping() { return listAllMapping(); } public Map<HostId, IpAssignment> listAllMapping() { Map<HostId, IpAssignment> map = new HashMap<>(); IpAssignment assignment = IpAssignment.builder() .ipAddress(Ip4Address.valueOf(EXPECTED_IP)) .assignmentStatus(IpAssignment.AssignmentStatus.Option_Assigned) .leasePeriod(300) .timestamp(new Date()) .build(); map.put(CLIENT1_HOST, assignment); return map; } public boolean assignStaticIP(MacAddress macID, IpAssignment ipAssignment) { return true; } public boolean removeStaticIP(MacAddress macID) { return true; } public Iterable<Ip4Address> getAvailableIPs() { List<Ip4Address> ipList = new ArrayList<>(); ipList.add(Ip4Address.valueOf(EXPECTED_IP)); return ImmutableSet.copyOf(ipList); } public IpAssignment getIpAssignmentFromAllocationMap(HostId hostId) { return null; } } /** * Mocks the DefaultPacket context. */ private final class TestPacketContext extends DefaultPacketContext { private TestPacketContext(long time, InboundPacket inPkt, OutboundPacket outPkt, boolean block) { super(time, inPkt, outPkt, block); } @Override public void send() { // We don't send anything out. } } /** * Keeps a reference to the PacketProcessor and verifies the OutboundPackets. */ private class TestPacketService extends PacketServiceAdapter { @Override public void addProcessor(PacketProcessor processor, int priority) { packetProcessor = processor; } @Override public void emit(OutboundPacket packet) { try { Ethernet eth = Ethernet.deserializer().deserialize(packet.data().array(), 0, packet.data().array().length); validatePacket(eth); } catch (Exception e) { fail(e.getMessage()); } } } /** * Mocks the CoreService. */ private class TestCoreService extends CoreServiceAdapter { } /** * Mocks the NetworkConfigRegistry. */ private class TestNetworkConfigRegistry extends NetworkConfigRegistryAdapter { } /** * Mocks the ComponentConfigRegistry. */ private class TestComponentConfig extends ComponentConfigAdapter { } /** * Mocks the HostProviderService. */ private class TestHostProviderService extends AbstractProviderService<HostProvider> implements HostProviderService { protected TestHostProviderService(HostProvider provider) { super(provider); } @Override public void hostDetected(HostId hostId, HostDescription hostDescription, boolean replaceIps) { } @Override public void hostVanished(HostId hostId) { } @Override public void removeIpFromHost(HostId hostId, IpAddress ipAddress) { } } /** * Mocks the HostProvider. */ private static class TestHostProvider extends AbstractProvider implements HostProvider { protected TestHostProvider() { super(PID); } @Override public ProviderId id() { return PID; } @Override public void triggerProbe(Host host) { } } /** * Mocks the HostProviderRegistry. */ private class TestHostRegistry implements HostProviderRegistry { @Override public HostProviderService register(HostProvider provider) { return hostProviderService; } @Override public void unregister(HostProvider provider) { } @Override public Set<ProviderId> getProviders() { return null; } } }