DHCP util refactor
Move options to packet.dhcp package
Deprecated DHCPPacketType, add MsgType to DHCP class
Change-Id: I85ce7fa5e6f3fdc916fbbeba9a4e10e75064a054
diff --git a/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java b/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
index dd21838..7190aea 100644
--- a/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
+++ b/apps/dhcp/app/src/main/java/org/onosproject/dhcp/impl/DhcpManager.java
@@ -28,8 +28,7 @@
import org.apache.felix.scr.annotations.Service;
import org.onlab.packet.ARP;
import org.onlab.packet.DHCP;
-import org.onlab.packet.DHCPOption;
-import org.onlab.packet.DHCPPacketType;
+import org.onlab.packet.dhcp.DhcpOption;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
@@ -89,9 +88,6 @@
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_DHCPServerIp;
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_RequestedIP;
-import static org.onlab.packet.DHCPPacketType.DHCPACK;
-import static org.onlab.packet.DHCPPacketType.DHCPNAK;
-import static org.onlab.packet.DHCPPacketType.DHCPOFFER;
import static org.onlab.packet.MacAddress.valueOf;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_Requested;
@@ -344,7 +340,7 @@
dhcpReply.setClientHardwareAddress(dhcpPacket.getClientHardwareAddress());
dhcpReply.setTransactionId(dhcpPacket.getTransactionId());
- if (outgoingMessageType != DHCPPacketType.DHCPNAK.getValue()) {
+ if (outgoingMessageType != DHCP.MsgType.DHCPNAK.getValue()) {
dhcpReply.setYourIPAddress(ipOffered.toInt());
dhcpReply.setServerIPAddress(dhcpServerReply.toInt());
if (dhcpPacket.getGatewayIPAddress() == 0) {
@@ -355,8 +351,8 @@
dhcpReply.setHardwareAddressLength((byte) 6);
// DHCP Options.
- DHCPOption option = new DHCPOption();
- List<DHCPOption> optionList = new ArrayList<>();
+ DhcpOption option = new DhcpOption();
+ List<DhcpOption> optionList = new ArrayList<>();
// DHCP Message Type.
option.setCode(OptionCode_MessageType.getValue());
@@ -366,15 +362,15 @@
optionList.add(option);
// DHCP Server Identifier.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(OptionCode_DHCPServerIp.getValue());
option.setLength((byte) 4);
option.setData(dhcpServerReply.toOctets());
optionList.add(option);
- if (outgoingMessageType != DHCPPacketType.DHCPNAK.getValue()) {
+ if (outgoingMessageType != DHCP.MsgType.DHCPNAK.getValue()) {
// IP Address Lease Time.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_LeaseTime.getValue());
option.setLength((byte) 4);
option.setData(ByteBuffer.allocate(4)
@@ -382,28 +378,28 @@
optionList.add(option);
// IP Address Renewal Time.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_RenewalTime.getValue());
option.setLength((byte) 4);
option.setData(ByteBuffer.allocate(4).putInt(renewalTime).array());
optionList.add(option);
// IP Address Rebinding Time.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OPtionCode_RebindingTime.getValue());
option.setLength((byte) 4);
option.setData(ByteBuffer.allocate(4).putInt(rebindingTime).array());
optionList.add(option);
// Subnet Mask.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_SubnetMask.getValue());
option.setLength((byte) 4);
option.setData(subnetMaskReply.toOctets());
optionList.add(option);
// Broadcast Address.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_BroadcastAddress.getValue());
option.setLength((byte) 4);
option.setData(broadcastReply.toOctets());
@@ -411,7 +407,7 @@
// Router Address.
if (routerAddressReply.isPresent()) {
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_RouterAddress.getValue());
option.setLength((byte) 4);
option.setData(routerAddressReply.get().toOctets());
@@ -420,7 +416,7 @@
// DNS Server Address.
if (domainServerReply.isPresent()) {
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_DomainServer.getValue());
option.setLength((byte) 4);
option.setData(domainServerReply.get().toOctets());
@@ -429,7 +425,7 @@
}
// End Option.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
option.setLength((byte) 1);
optionList.add(option);
@@ -472,16 +468,16 @@
}
Ethernet packet = context.inPacket().parsed();
- DHCPPacketType incomingPacketType = null;
+ DHCP.MsgType incomingPacketType = null;
boolean flagIfRequestedIP = false;
boolean flagIfServerIP = false;
Ip4Address requestedIP = Ip4Address.valueOf("0.0.0.0");
Ip4Address serverIP = Ip4Address.valueOf("0.0.0.0");
- for (DHCPOption option : dhcpPayload.getOptions()) {
+ for (DhcpOption option : dhcpPayload.getOptions()) {
if (option.getCode() == OptionCode_MessageType.getValue()) {
byte[] data = option.getData();
- incomingPacketType = DHCPPacketType.getType(data[0]);
+ incomingPacketType = DHCP.MsgType.getType(data[0]);
}
if (option.getCode() == OptionCode_RequestedIP.getValue()) {
byte[] data = option.getData();
@@ -500,7 +496,7 @@
return;
}
- DHCPPacketType outgoingPacketType;
+ DHCP.MsgType outgoingPacketType;
MacAddress clientMac = new MacAddress(dhcpPayload.getClientHardwareAddress());
VlanId vlanId = VlanId.vlanId(packet.getVlanID());
HostId hostId = HostId.hostId(clientMac, vlanId);
@@ -513,7 +509,7 @@
Ethernet ethReply = buildReply(
packet,
ipOffered,
- (byte) DHCPOFFER.getValue());
+ (byte) DHCP.MsgType.DHCPOFFER.getValue());
sendReply(context, ethReply);
}
break;
@@ -536,10 +532,10 @@
.assignmentStatus(Option_Requested).build();
if (dhcpStore.assignIP(hostId, ipAssignment)) {
- outgoingPacketType = DHCPACK;
+ outgoingPacketType = DHCP.MsgType.DHCPACK;
discoverHost(context, requestedIP);
} else {
- outgoingPacketType = DHCPNAK;
+ outgoingPacketType = DHCP.MsgType.DHCPNAK;
}
Ethernet ethReply = buildReply(packet, requestedIP, (byte) outgoingPacketType.getValue());
diff --git a/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java b/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java
index 934e601..104d931 100644
--- a/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java
+++ b/apps/dhcp/app/src/test/java/org/onosproject/dhcp/impl/DhcpManagerTest.java
@@ -20,8 +20,7 @@
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.dhcp.DhcpOption;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
@@ -109,7 +108,7 @@
*/
@Test
public void testDiscover() {
- Ethernet reply = constructDhcpPacket(DHCPPacketType.DHCPDISCOVER);
+ Ethernet reply = constructDhcpPacket(DHCP.MsgType.DHCPDISCOVER);
sendPacket(reply);
}
@@ -118,7 +117,7 @@
*/
@Test
public void testRequest() {
- Ethernet reply = constructDhcpPacket(DHCPPacketType.DHCPREQUEST);
+ Ethernet reply = constructDhcpPacket(DHCP.MsgType.DHCPREQUEST);
sendPacket(reply);
}
@@ -141,7 +140,7 @@
* @param packetType DHCP Message Type
* @return Ethernet packet
*/
- private Ethernet constructDhcpPacket(DHCPPacketType packetType) {
+ private Ethernet constructDhcpPacket(DHCP.MsgType packetType) {
// Ethernet Frame.
Ethernet ethReply = new Ethernet();
@@ -174,8 +173,8 @@
dhcpReply.setHardwareAddressLength((byte) 6);
// DHCP Options.
- DHCPOption option = new DHCPOption();
- List<DHCPOption> optionList = new ArrayList<>();
+ DhcpOption option = new DhcpOption();
+ List<DhcpOption> optionList = new ArrayList<>();
// DHCP Message Type.
option.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
@@ -185,7 +184,7 @@
optionList.add(option);
// DHCP Requested IP.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_RequestedIP.getValue());
option.setLength((byte) 4);
optionData = Ip4Address.valueOf(EXPECTED_IP).toOctets();
@@ -193,7 +192,7 @@
optionList.add(option);
// End Option.
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP.DHCPOptionCode.OptionCode_END.getValue());
option.setLength((byte) 1);
optionList.add(option);
diff --git a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
index 40003eb..778f778 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
@@ -28,8 +28,7 @@
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ARP;
import org.onlab.packet.DHCP;
-import org.onlab.packet.DHCPOption;
-import org.onlab.packet.DHCPPacketType;
+import org.onlab.packet.dhcp.DhcpOption;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
@@ -421,11 +420,11 @@
}
Ethernet packet = context.inPacket().parsed();
- DHCPPacketType incomingPacketType = null;
- for (DHCPOption option : dhcpPayload.getOptions()) {
+ DHCP.MsgType incomingPacketType = null;
+ for (DhcpOption option : dhcpPayload.getOptions()) {
if (option.getCode() == OptionCode_MessageType.getValue()) {
byte[] data = option.getData();
- incomingPacketType = DHCPPacketType.getType(data[0]);
+ incomingPacketType = DHCP.MsgType.getType(data[0]);
}
}
diff --git a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
index d87326d8..8271644 100644
--- a/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
+++ b/apps/openstacknetworking/src/main/java/org/onosproject/openstacknetworking/impl/OpenstackSwitchingDhcpHandler.java
@@ -25,8 +25,7 @@
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.DHCP;
-import org.onlab.packet.DHCPOption;
-import org.onlab.packet.DHCPPacketType;
+import org.onlab.packet.dhcp.DhcpOption;
import org.onlab.packet.Ethernet;
import org.onlab.packet.IPv4;
import org.onlab.packet.Ip4Address;
@@ -63,8 +62,8 @@
import java.util.List;
import static org.onlab.packet.DHCP.DHCPOptionCode.*;
-import static org.onlab.packet.DHCPPacketType.DHCPACK;
-import static org.onlab.packet.DHCPPacketType.DHCPOFFER;
+import static org.onlab.packet.DHCP.MsgType.DHCPACK;
+import static org.onlab.packet.DHCP.MsgType.DHCPOFFER;
import static org.onosproject.openstacknetworking.api.Constants.DEFAULT_GATEWAY_MAC_STR;
import static org.slf4j.LoggerFactory.getLogger;
@@ -192,7 +191,7 @@
return;
}
- DHCPPacketType inPacketType = getPacketType(dhcpPacket);
+ DHCP.MsgType inPacketType = getPacketType(dhcpPacket);
if (inPacketType == null || dhcpPacket.getClientHardwareAddress() == null) {
log.trace("Malformed DHCP packet received, ignore it");
return;
@@ -235,14 +234,14 @@
}
}
- private DHCPPacketType getPacketType(DHCP dhcpPacket) {
- DHCPOption optType = dhcpPacket.getOption(OptionCode_MessageType);
+ private DHCP.MsgType getPacketType(DHCP dhcpPacket) {
+ DhcpOption optType = dhcpPacket.getOption(OptionCode_MessageType);
if (optType == null) {
log.trace("DHCP packet with no message type, ignore it");
return null;
}
- DHCPPacketType inPacketType = DHCPPacketType.getType(optType.getData()[0]);
+ DHCP.MsgType inPacketType = DHCP.MsgType.getType(optType.getData()[0]);
if (inPacketType == null) {
log.trace("DHCP packet with no packet type, ignore it");
}
@@ -318,9 +317,9 @@
dhcpReply.setServerIPAddress(gatewayIp.toInt());
dhcpReply.setClientHardwareAddress(request.getClientHardwareAddress());
- List<DHCPOption> options = Lists.newArrayList();
+ List<DhcpOption> options = Lists.newArrayList();
// message type
- DHCPOption option = new DHCPOption();
+ DhcpOption option = new DhcpOption();
option.setCode(OptionCode_MessageType.getValue());
option.setLength((byte) 1);
byte[] optionData = {msgType};
@@ -328,14 +327,14 @@
options.add(option);
// server identifier
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(OptionCode_DHCPServerIp.getValue());
option.setLength((byte) 4);
option.setData(gatewayIp.toOctets());
options.add(option);
// lease time
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(OptionCode_LeaseTime.getValue());
option.setLength((byte) 4);
option.setData(DHCP_DATA_LEASE_INFINITE);
@@ -343,7 +342,7 @@
// subnet mask
Ip4Address subnetMask = Ip4Address.makeMaskPrefix(subnetPrefixLen);
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(OptionCode_SubnetMask.getValue());
option.setLength((byte) 4);
option.setData(subnetMask.toOctets());
@@ -351,35 +350,35 @@
// broadcast address
Ip4Address broadcast = Ip4Address.makeMaskedAddress(yourIp, subnetPrefixLen);
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(OptionCode_BroadcastAddress.getValue());
option.setLength((byte) 4);
option.setData(broadcast.toOctets());
options.add(option);
// domain server
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(OptionCode_DomainServer.getValue());
option.setLength((byte) 4);
option.setData(DEFAULT_DNS.toOctets());
options.add(option);
// TODO fix MTU value to be configurable
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(DHCP_OPTION_MTU);
option.setLength((byte) 2);
option.setData(DHCP_DATA_MTU_DEFAULT);
options.add(option);
// router address
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(OptionCode_RouterAddress.getValue());
option.setLength((byte) 4);
option.setData(gatewayIp.toOctets());
options.add(option);
// end option
- option = new DHCPOption();
+ option = new DhcpOption();
option.setCode(OptionCode_END.getValue());
option.setLength((byte) 1);
options.add(option);
diff --git a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
index 97b49a4..996bd43 100644
--- a/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
+++ b/providers/host/src/main/java/org/onosproject/provider/host/impl/HostLocationProvider.java
@@ -24,7 +24,6 @@
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.onlab.packet.ARP;
import org.onlab.packet.DHCP;
-import org.onlab.packet.DHCPPacketType;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP6;
import org.onlab.packet.IPacket;
@@ -489,7 +488,7 @@
.anyMatch(dhcpOption -> dhcpOption.getCode() ==
DHCP.DHCPOptionCode.OptionCode_MessageType.getValue() &&
dhcpOption.getLength() == 1 &&
- dhcpOption.getData()[0] == DHCPPacketType.DHCPACK.getValue())) {
+ dhcpOption.getData()[0] == DHCP.MsgType.DHCPACK.getValue())) {
MacAddress hostMac = MacAddress.valueOf(dhcp.getClientHardwareAddress());
VlanId hostVlan = VlanId.vlanId(eth.getVlanID());
HostId hostId = HostId.hostId(hostMac, hostVlan);
diff --git a/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java b/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
index b642458..b28ec17 100644
--- a/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
+++ b/providers/host/src/test/java/org/onosproject/provider/host/impl/HostLocationProviderTest.java
@@ -25,8 +25,7 @@
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.dhcp.DhcpOption;
import org.onlab.packet.Ethernet;
import org.onlab.packet.ICMP6;
import org.onlab.packet.IPv4;
@@ -614,9 +613,9 @@
@Override
public InboundPacket inPacket() {
byte[] dhcpMsgType = new byte[1];
- dhcpMsgType[0] = (byte) DHCPPacketType.DHCPREQUEST.getValue();
+ dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPREQUEST.getValue();
- DHCPOption dhcpOption = new DHCPOption();
+ DhcpOption dhcpOption = new DhcpOption();
dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
dhcpOption.setData(dhcpMsgType);
dhcpOption.setLength((byte) 1);
@@ -658,9 +657,9 @@
@Override
public InboundPacket inPacket() {
byte[] dhcpMsgType = new byte[1];
- dhcpMsgType[0] = (byte) DHCPPacketType.DHCPACK.getValue();
+ dhcpMsgType[0] = (byte) DHCP.MsgType.DHCPACK.getValue();
- DHCPOption dhcpOption = new DHCPOption();
+ DhcpOption dhcpOption = new DhcpOption();
dhcpOption.setCode(DHCP.DHCPOptionCode.OptionCode_MessageType.getValue());
dhcpOption.setData(dhcpMsgType);
dhcpOption.setLength((byte) 1);
diff --git a/utils/misc/src/main/java/org/onlab/packet/DHCP.java b/utils/misc/src/main/java/org/onlab/packet/DHCP.java
index 012443e..ed1741e 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/DHCP.java
@@ -18,12 +18,16 @@
package org.onlab.packet;
-import java.io.UnsupportedEncodingException;
+import com.google.common.collect.ImmutableMap;
+import org.onlab.packet.dhcp.DhcpOption;
+import org.onlab.packet.dhcp.DhcpRelayAgentOption;
+
import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.ListIterator;
+import java.util.Map;
import static com.google.common.base.Preconditions.checkArgument;
import static org.onlab.packet.PacketUtils.checkInput;
@@ -53,20 +57,33 @@
public static final int MIN_HEADER_LENGTH = 240;
public static final byte OPCODE_REQUEST = 0x1;
public static final byte OPCODE_REPLY = 0x2;
-
public static final byte HWTYPE_ETHERNET = 0x1;
+ private static final Map<Byte, Deserializer<? extends DhcpOption>> OPTION_DESERIALIZERS =
+ ImmutableMap.of(DHCPOptionCode.OptionCode_CircuitID.value, DhcpRelayAgentOption.deserializer());
+ private static final int UNSIGNED_BYTE_MASK = 0xff;
+ private static final int BASE_OPTION_LEN = 60;
+ private static final int MIN_DHCP_LEN = 240;
+ private static final int BASE_HW_ADDR_LEN = 16;
+ private static final byte PAD_BYTE = 0;
+ private static final int BASE_SERVER_NAME_LEN = 64;
+ private static final int BASE_BOOT_FILE_NAME_LEN = 128;
+ private static final int MAGIC_COOKIE = 0x63825363;
+
public enum DHCPOptionCode {
- OptionCode_SubnetMask((byte) 1), OptionCode_RouterAddress((byte) 3), OptionCode_DomainServer((byte) 6),
- OptionCode_HostName((byte) 12), OptionCode_DomainName((byte) 15), OptionCode_BroadcastAddress((byte) 28),
- OptionCode_RequestedIP((byte) 50), OptionCode_LeaseTime((byte) 51), OptionCode_MessageType((byte) 53),
+ OptionCode_Pad((byte) 0), OptionCode_SubnetMask((byte) 1),
+ OptionCode_RouterAddress((byte) 3), OptionCode_DomainServer((byte) 6),
+ OptionCode_HostName((byte) 12), OptionCode_DomainName((byte) 15),
+ OptionCode_BroadcastAddress((byte) 28), OptionCode_RequestedIP((byte) 50),
+ OptionCode_LeaseTime((byte) 51), OptionCode_MessageType((byte) 53),
OptionCode_DHCPServerIp((byte) 54), OptionCode_RequestedParameters((byte) 55),
- OptionCode_RenewalTime((byte) 58), OPtionCode_RebindingTime((byte) 59), OptionCode_ClientID((byte) 61),
- OptionCode_CircuitID((byte) 82), OptionCode_END((byte) 255);
+ OptionCode_RenewalTime((byte) 58), OPtionCode_RebindingTime((byte) 59),
+ OptionCode_ClientID((byte) 61), OptionCode_CircuitID((byte) 82),
+ OptionCode_END((byte) 255);
protected byte value;
- private DHCPOptionCode(final byte value) {
+ DHCPOptionCode(final byte value) {
this.value = value;
}
@@ -75,6 +92,65 @@
}
}
+ public enum MsgType {
+ // From RFC 1533
+ DHCPDISCOVER(1), DHCPOFFER(2), DHCPREQUEST(3), DHCPDECLINE(4), DHCPACK(5),
+ DHCPNAK(6), DHCPRELEASE(7),
+
+ // From RFC2132
+ DHCPINFORM(8),
+
+ // From RFC3203
+ DHCPFORCERENEW(9),
+
+ // From RFC4388
+ DHCPLEASEQUERY(10), DHCPLEASEUNASSIGNED(11), DHCPLEASEUNKNOWN(12),
+ DHCPLEASEACTIVE(13);
+
+ protected int value;
+
+ MsgType(final int value) {
+ this.value = value;
+ }
+
+ public int getValue() {
+ return this.value;
+ }
+
+ public static MsgType getType(final int value) {
+ switch (value) {
+ case 1:
+ return DHCPDISCOVER;
+ case 2:
+ return DHCPOFFER;
+ case 3:
+ return DHCPREQUEST;
+ case 4:
+ return DHCPDECLINE;
+ case 5:
+ return DHCPACK;
+ case 6:
+ return DHCPNAK;
+ case 7:
+ return DHCPRELEASE;
+ case 8:
+ return DHCPINFORM;
+ case 9:
+ return DHCPFORCERENEW;
+ case 10:
+ return DHCPLEASEQUERY;
+ case 11:
+ return DHCPLEASEUNASSIGNED;
+ case 12:
+ return DHCPLEASEUNKNOWN;
+ case 13:
+ return DHCPLEASEACTIVE;
+ default:
+ return null;
+ }
+ }
+ }
+
protected byte opCode;
protected byte hardwareType;
protected byte hardwareAddressLength;
@@ -89,7 +165,7 @@
protected byte[] clientHardwareAddress;
protected String serverName;
protected String bootFileName;
- protected List<DHCPOption> options = new ArrayList<DHCPOption>();
+ protected List<DhcpOption> options = new ArrayList<DhcpOption>();
/**
* @return the opCode
@@ -302,9 +378,9 @@
* The option code to get
* @return The value of the option if it exists, null otherwise
*/
- public DHCPOption getOption(final DHCPOptionCode optionCode) {
- for (final DHCPOption opt : this.options) {
- if (opt.code == optionCode.value) {
+ public DhcpOption getOption(final DHCPOptionCode optionCode) {
+ for (final DhcpOption opt : this.options) {
+ if (opt.getCode() == optionCode.getValue()) {
return opt;
}
}
@@ -314,7 +390,7 @@
/**
* @return the options
*/
- public List<DHCPOption> getOptions() {
+ public List<DhcpOption> getOptions() {
return this.options;
}
@@ -323,7 +399,7 @@
* the options to set
* @return this
*/
- public DHCP setOptions(final List<DHCPOption> options) {
+ public DHCP setOptions(final List<DhcpOption> options) {
this.options = options;
return this;
}
@@ -331,16 +407,15 @@
/**
* @return the packetType base on option 53
*/
- public DHCPPacketType getPacketType() {
- final ListIterator<DHCPOption> lit = this.options.listIterator();
- while (lit.hasNext()) {
- final DHCPOption option = lit.next();
- // only care option 53
- if (option.getCode() == 53) {
- return DHCPPacketType.getType(option.getData()[0]);
- }
- }
- return null;
+ public MsgType getPacketType() {
+ return this.options.parallelStream()
+ .filter(op -> op.getCode() == DHCPOptionCode.OptionCode_MessageType.getValue())
+ .map(DhcpOption::getData)
+ .filter(data -> data.length != 0)
+ .map(data -> data[0])
+ .map(MsgType::getType)
+ .findFirst()
+ .orElse(null);
}
/**
@@ -385,19 +460,20 @@
// minimum size 240 including magic cookie, options generally padded to
// 300
int optionsLength = 0;
- for (final DHCPOption option : this.options) {
- if (option.getCode() == 0 || option.getCode() == ((byte) 255)) {
+ for (final DhcpOption option : this.options) {
+ if (option.getCode() == DHCPOptionCode.OptionCode_Pad.getValue() ||
+ option.getCode() == DHCPOptionCode.OptionCode_END.getValue()) {
optionsLength += 1;
} else {
- optionsLength += 2 + (0xff & option.getLength());
+ optionsLength += 2 + (UNSIGNED_BYTE_MASK & option.getLength());
}
}
int optionsPadLength = 0;
- if (optionsLength < 60) {
- optionsPadLength = 60 - optionsLength;
+ if (optionsLength < BASE_OPTION_LEN) {
+ optionsPadLength = BASE_OPTION_LEN - optionsLength;
}
- final byte[] data = new byte[240 + optionsLength + optionsPadLength];
+ final byte[] data = new byte[MIN_DHCP_LEN + optionsLength + optionsPadLength];
final ByteBuffer bb = ByteBuffer.wrap(data);
bb.put(this.opCode);
bb.put(this.hardwareType);
@@ -410,127 +486,44 @@
bb.putInt(this.yourIPAddress);
bb.putInt(this.serverIPAddress);
bb.putInt(this.gatewayIPAddress);
- checkArgument(this.clientHardwareAddress.length <= 16,
+ checkArgument(this.clientHardwareAddress.length <= BASE_HW_ADDR_LEN,
"Hardware address is too long (%s bytes)", this.clientHardwareAddress.length);
bb.put(this.clientHardwareAddress);
- if (this.clientHardwareAddress.length < 16) {
- for (int i = 0; i < 16 - this.clientHardwareAddress.length; ++i) {
- bb.put((byte) 0x0);
+ if (this.clientHardwareAddress.length < BASE_HW_ADDR_LEN) {
+ for (int i = 0; i < BASE_HW_ADDR_LEN - this.clientHardwareAddress.length; ++i) {
+ bb.put(PAD_BYTE);
}
}
- this.writeString(this.serverName, bb, 64);
- this.writeString(this.bootFileName, bb, 128);
+ this.writeString(this.serverName, bb, BASE_SERVER_NAME_LEN);
+ this.writeString(this.bootFileName, bb, BASE_BOOT_FILE_NAME_LEN);
// magic cookie
- bb.put((byte) 0x63);
- bb.put((byte) 0x82);
- bb.put((byte) 0x53);
- bb.put((byte) 0x63);
- for (final DHCPOption option : this.options) {
- dhcpOptionToByteArray(option, bb);
+ bb.putInt(MAGIC_COOKIE);
+ for (final DhcpOption option : this.options) {
+ bb.put(option.serialize());
}
// assume the rest is padded out with zeroes
return data;
}
- public static ByteBuffer dhcpOptionToByteArray(DHCPOption option, ByteBuffer bb) {
- final int code = option.getCode() & 0xff;
- bb.put((byte) code);
- if (code != 0 && code != 255) {
- bb.put(option.getLength());
- bb.put(option.getData());
- }
- return bb;
- }
-
@Override
public IPacket deserialize(final byte[] data, final int offset,
final int length) {
- final ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
- if (bb.remaining() < DHCP.MIN_HEADER_LENGTH) {
- return this;
+ try {
+ return deserializer().deserialize(data, offset, length);
+ } catch (DeserializationException e) {
+ return null;
}
-
- this.opCode = bb.get();
- this.hardwareType = bb.get();
- this.hardwareAddressLength = bb.get();
- this.hops = bb.get();
- this.transactionId = bb.getInt();
- this.seconds = bb.getShort();
- this.flags = bb.getShort();
- this.clientIPAddress = bb.getInt();
- this.yourIPAddress = bb.getInt();
- this.serverIPAddress = bb.getInt();
- this.gatewayIPAddress = bb.getInt();
- final int hardwareAddressLength = 0xff & this.hardwareAddressLength;
- this.clientHardwareAddress = new byte[hardwareAddressLength];
-
- bb.get(this.clientHardwareAddress);
- for (int i = hardwareAddressLength; i < 16; ++i) {
- bb.get();
- }
- this.serverName = this.readString(bb, 64);
- this.bootFileName = this.readString(bb, 128);
- // read the magic cookie
- // magic cookie
- bb.get();
- bb.get();
- bb.get();
- bb.get();
- // read options
- while (bb.hasRemaining()) {
- final DHCPOption option = new DHCPOption();
- int code = 0xff & bb.get(); // convert signed byte to int in range
- // [0,255]
- option.setCode((byte) code);
- if (code == 0) {
- // skip these
- continue;
- } else if (code != 255) {
- if (bb.hasRemaining()) {
- final int l = 0xff & bb.get(); // convert signed byte to
- // int in range [0,255]
- option.setLength((byte) l);
- if (bb.remaining() >= l) {
- final byte[] optionData = new byte[l];
- bb.get(optionData);
- option.setData(optionData);
- } else {
- // Skip the invalid option and set the END option
- code = 0xff;
- option.setCode((byte) code);
- option.setLength((byte) 0);
- }
- } else {
- // Skip the invalid option and set the END option
- code = 0xff;
- option.setCode((byte) code);
- option.setLength((byte) 0);
- }
- }
- this.options.add(option);
- if (code == 255) {
- // remaining bytes are supposed to be 0, but ignore them just in
- // case
- break;
- }
- }
-
- return this;
}
protected void writeString(final String string, final ByteBuffer bb,
final int maxLength) {
if (string == null) {
for (int i = 0; i < maxLength; ++i) {
- bb.put((byte) 0x0);
+ bb.put(PAD_BYTE);
}
} else {
- byte[] bytes = null;
- try {
- bytes = string.getBytes("ascii");
- } catch (final UnsupportedEncodingException e) {
- throw new RuntimeException("Failure encoding server name", e);
- }
+ byte[] bytes;
+ bytes = string.getBytes(StandardCharsets.US_ASCII);
int writeLength = bytes.length;
if (writeLength > maxLength) {
writeLength = maxLength;
@@ -545,12 +538,8 @@
private static String readString(final ByteBuffer bb, final int maxLength) {
final byte[] bytes = new byte[maxLength];
bb.get(bytes);
- String result = null;
- try {
- result = new String(bytes, "ascii").trim();
- } catch (final UnsupportedEncodingException e) {
- throw new RuntimeException("Failure decoding string", e);
- }
+ String result;
+ result = new String(bytes, StandardCharsets.US_ASCII).trim();
return result;
}
@@ -577,56 +566,64 @@
dhcp.yourIPAddress = bb.getInt();
dhcp.serverIPAddress = bb.getInt();
dhcp.gatewayIPAddress = bb.getInt();
- final int hardwareAddressLength = 0xff & dhcp.hardwareAddressLength;
+ final int hardwareAddressLength = UNSIGNED_BYTE_MASK & dhcp.hardwareAddressLength;
dhcp.clientHardwareAddress = new byte[hardwareAddressLength];
bb.get(dhcp.clientHardwareAddress);
- for (int i = hardwareAddressLength; i < 16; ++i) {
+ for (int i = hardwareAddressLength; i < BASE_HW_ADDR_LEN; ++i) {
bb.get();
}
- dhcp.serverName = readString(bb, 64);
- dhcp.bootFileName = readString(bb, 128);
+ dhcp.serverName = readString(bb, BASE_SERVER_NAME_LEN);
+ dhcp.bootFileName = readString(bb, BASE_BOOT_FILE_NAME_LEN);
// read the magic cookie
// magic cookie
- bb.get();
- bb.get();
- bb.get();
- bb.get();
+ bb.getInt();
// read options
boolean foundEndOptionsMarker = false;
while (bb.hasRemaining()) {
- final DHCPOption option = new DHCPOption();
- int code = 0xff & bb.get(); // convert signed byte to int in range
- // [0,255]
- option.setCode((byte) code);
- if (code == 0) {
- // skip these
+ DhcpOption option;
+
+ int pos = bb.position();
+ int optCode = UNSIGNED_BYTE_MASK & bb.array()[pos]; // to unsigned integer
+ int optLen;
+ byte[] optData;
+
+ if (optCode == DHCPOptionCode.OptionCode_Pad.value) {
+ // pad, skip
+ // read option code
+ bb.get();
continue;
- } else if (code != 255) {
- if (bb.hasRemaining()) {
- final int l = 0xff & bb.get(); // convert signed byte to
- // int in range [0,255]
- option.setLength((byte) l);
- if (bb.remaining() >= l) {
- final byte[] optionData = new byte[l];
- bb.get(optionData);
- option.setData(optionData);
- dhcp.options.add(option);
- } else {
- throw new DeserializationException(
- "Buffer underflow while reading DHCP option");
- }
- }
- } else if (code == 255) {
- DHCPOption end = new DHCPOption();
- end.setCode((byte) 255);
- dhcp.options.add(end);
- // remaining bytes are supposed to be 0, but ignore them just in
- // case
+ }
+ if (optCode == (UNSIGNED_BYTE_MASK & DHCPOptionCode.OptionCode_END.value)) {
+ // end of dhcp options or invalid option and set the END option
+ option = new DhcpOption();
+ option.setCode((byte) optCode);
+ dhcp.options.add(option);
foundEndOptionsMarker = true;
break;
}
+
+ if (bb.remaining() < 2) {
+ // No option length
+ throw new DeserializationException("Buffer underflow while reading DHCP option");
+ }
+
+ optLen = UNSIGNED_BYTE_MASK & bb.array()[pos + 1];
+ if (bb.remaining() < DhcpOption.DEFAULT_LEN + optLen) {
+ // Invalid option length
+ throw new DeserializationException("Buffer underflow while reading DHCP option");
+ }
+ optData = new byte[DhcpOption.DEFAULT_LEN + optLen];
+ bb.get(optData);
+ if (OPTION_DESERIALIZERS.containsKey((byte) optCode)) {
+ option = OPTION_DESERIALIZERS.get((byte) optCode).deserialize(optData, 0, optData.length);
+ dhcp.options.add(option);
+ } else {
+ // default option
+ option = DhcpOption.deserializer().deserialize(optData, 0, optData.length);
+ dhcp.options.add(option);
+ }
}
if (!foundEndOptionsMarker) {
diff --git a/utils/misc/src/main/java/org/onlab/packet/DHCP6.java b/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
index b6aa691..6310ec5 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
+++ b/utils/misc/src/main/java/org/onlab/packet/DHCP6.java
@@ -18,6 +18,7 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
+import org.onlab.packet.dhcp.Dhcp6Option;
import java.nio.ByteBuffer;
import java.util.List;
@@ -91,7 +92,7 @@
// general field
private byte msgType; // 1 byte
- private List<DHCP6Option> options;
+ private List<Dhcp6Option> options;
// non-relay field
private int transactionId; // 3 bytes
@@ -111,7 +112,7 @@
@Override
public byte[] serialize() {
int payloadLength = options.stream()
- .mapToInt(DHCP6Option::getLength)
+ .mapToInt(Dhcp6Option::getLength)
.sum();
// 2 bytes code and 2 bytes length
@@ -186,7 +187,7 @@
dhcp6.options = Lists.newArrayList();
while (bb.remaining() >= OPT_CODE_SIZE) {
- DHCP6Option option = new DHCP6Option();
+ Dhcp6Option option = new Dhcp6Option();
short code = bb.getShort();
if (bb.remaining() < OPT_LEN_SIZE) {
throw new DeserializationException(
@@ -235,7 +236,7 @@
*
* @return DHCPv6 options
*/
- public List<DHCP6Option> getOptions() {
+ public List<Dhcp6Option> getOptions() {
return options;
}
@@ -289,7 +290,7 @@
*
* @param options the options
*/
- public void setOptions(List<DHCP6Option> options) {
+ public void setOptions(List<Dhcp6Option> options) {
this.options = options;
}
diff --git a/utils/misc/src/main/java/org/onlab/packet/DHCPOption.java b/utils/misc/src/main/java/org/onlab/packet/DHCPOption.java
deleted file mode 100644
index fa41753..0000000
--- a/utils/misc/src/main/java/org/onlab/packet/DHCPOption.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.onlab.packet;
-
-import java.util.Arrays;
-
-/**
- * Representation of DHCPOption field.
- */
-public class DHCPOption {
- protected byte code;
- protected byte length;
- protected byte[] data;
-
- /**
- * @return the code
- */
- public byte getCode() {
- return this.code;
- }
-
- /**
- * @param code the code to set
- * @return this
- */
- public DHCPOption setCode(final byte code) {
- this.code = code;
- return this;
- }
-
- /**
- * @return the length
- */
- public byte getLength() {
- return this.length;
- }
-
- /**
- * @param length the length to set
- * @return this
- */
- public DHCPOption setLength(final byte length) {
- this.length = length;
- return this;
- }
-
- /**
- * @return the data
- */
- public byte[] getData() {
- return this.data;
- }
-
- /**
- * @param data the data to set
- * @return this
- */
- public DHCPOption setData(final byte[] data) {
- this.data = data;
- return this;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Object#hashCode()
- */
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + this.code;
- result = prime * result + Arrays.hashCode(this.data);
- result = prime * result + this.length;
- return result;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Object#equals(java.lang.Object)
- */
- @Override
- public boolean equals(final Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (!(obj instanceof DHCPOption)) {
- return false;
- }
- final DHCPOption other = (DHCPOption) obj;
- if (this.code != other.code) {
- return false;
- }
- if (!Arrays.equals(this.data, other.data)) {
- return false;
- }
- if (this.length != other.length) {
- return false;
- }
- return true;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Object#toString()
- */
- @Override
- public String toString() {
- return "DHCPOption [code=" + this.code + ", length=" + this.length
- + ", data=" + Arrays.toString(this.data) + "]";
- }
-}
diff --git a/utils/misc/src/main/java/org/onlab/packet/DHCPPacketType.java b/utils/misc/src/main/java/org/onlab/packet/DHCPPacketType.java
index 0447feb..ea78872 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCPPacketType.java
+++ b/utils/misc/src/main/java/org/onlab/packet/DHCPPacketType.java
@@ -18,6 +18,10 @@
package org.onlab.packet;
+/**
+ * @deprecated 1.11 Loon, move into DHCP class.
+ */
+@Deprecated
public enum DHCPPacketType {
// From RFC 1533
DHCPDISCOVER(1), DHCPOFFER(2), DHCPREQUEST(3), DHCPDECLINE(4), DHCPACK(5), DHCPNAK(
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/CircuitId.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/CircuitId.java
new file mode 100644
index 0000000..afa28ec
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/CircuitId.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2017-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.onlab.packet.dhcp;
+
+import com.google.common.collect.Lists;
+import org.onlab.packet.VlanId;
+
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Objects;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * Representation of DHCP option 82 Circuit id.
+ */
+public class CircuitId {
+ private static final String SEPARATOR = ":";
+ private static final String CIRCUIT_ID_FORMAT = "%s" + SEPARATOR + "%s";
+ private String connectPoint;
+ private VlanId vlanId;
+
+ /**
+ * Creates a circuit id by given information.
+ *
+ * @param connectPoint the connect point of circuit id
+ * @param vlanId the vlan id of circuit id
+ */
+ public CircuitId(String connectPoint, VlanId vlanId) {
+ this.connectPoint = connectPoint;
+ this.vlanId = vlanId;
+ }
+
+ /**
+ * Combines connect point with vlan id with separator ':' as circuit id.
+ * e.g. of:0000000000000204/1:100
+ *
+ * @return serialized circuit id for connect point and vlan ID
+ */
+ public byte[] serialize() {
+ return String
+ .format(CIRCUIT_ID_FORMAT, connectPoint, vlanId.toString())
+ .getBytes(StandardCharsets.US_ASCII);
+ }
+
+ /**
+ * Deserialize circuit id from byte string.
+ *
+ * @param circuitId the circuit id byte string
+ * @return a Circuit Id
+ */
+ public static CircuitId deserialize(byte[] circuitId) {
+ String cIdString = new String(circuitId, StandardCharsets.US_ASCII);
+ List<String> split = Lists.newArrayList(cIdString.split(SEPARATOR));
+ checkArgument(split.size() > 1, "Illegal circuit id.");
+ // remove last element (vlan id)
+ String vlanId = split.remove(split.size() - 1);
+ String connectPoint = String.join(SEPARATOR, split);
+ return new CircuitId(connectPoint, VlanId.vlanId(vlanId));
+ }
+
+ /**
+ * Gets the connect point of circuit id.
+ *
+ * @return the connect point
+ */
+ public String connectPoint() {
+ return connectPoint;
+ }
+
+ /**
+ * Gets the vlan id of circuit id.
+ *
+ * @return the vlan id
+ */
+ public VlanId vlanId() {
+ return vlanId;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (!(obj instanceof CircuitId)) {
+ return false;
+ }
+ CircuitId that = (CircuitId) obj;
+ return Objects.equals(this.connectPoint, that.connectPoint) &&
+ Objects.equals(this.vlanId, that.vlanId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(connectPoint, vlanId);
+ }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/DHCP6Option.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
similarity index 96%
rename from utils/misc/src/main/java/org/onlab/packet/DHCP6Option.java
rename to utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
index f70a1c5..dc34075 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCP6Option.java
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/Dhcp6Option.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package org.onlab.packet;
+package org.onlab.packet.dhcp;
/**
* Representation of an DHCPv6 Option.
* Base on RFC-3315.
*/
-public class DHCP6Option {
+public class Dhcp6Option {
private short code;
private short length;
private byte[] data;
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java
new file mode 100644
index 0000000..a1b5923
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpOption.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2017-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.onlab.packet.dhcp;
+
+import org.onlab.packet.BasePacket;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.Deserializer;
+import org.onlab.packet.IPacket;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Objects;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Default DHCP option.
+ */
+public class DhcpOption extends BasePacket {
+ public static final int OPT_CODE_LEN = 1;
+ public static final int DEFAULT_LEN = 2;
+ private final Logger log = getLogger(getClass());
+ protected byte code;
+ protected byte length;
+ protected byte[] data;
+
+ @Override
+ public byte[] serialize() {
+ ByteBuffer byteBuffer;
+ if (data != null) {
+ byteBuffer = ByteBuffer.allocate(DEFAULT_LEN + data.length);
+ byteBuffer.put(code);
+ byteBuffer.put(length);
+ byteBuffer.put(data);
+ } else {
+ byteBuffer = ByteBuffer.allocate(OPT_CODE_LEN);
+ byteBuffer.put(code);
+ }
+ return byteBuffer.array();
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ try {
+ return deserializer().deserialize(data, offset, length);
+ } catch (DeserializationException e) {
+ log.warn("Can't deserialize DhcpOption {}", e);
+ return null;
+ }
+ }
+
+ /**
+ * Deserializer function for DHCP option.
+ *
+ * @return deserializer function
+ */
+ public static Deserializer<DhcpOption> deserializer() {
+ return (data, offset, length) -> {
+ DhcpOption dhcpOption = new DhcpOption();
+ ByteBuffer byteBuffer = ByteBuffer.wrap(data, offset, length);
+ dhcpOption.code = byteBuffer.get();
+ if (byteBuffer.hasRemaining()) {
+ dhcpOption.length = byteBuffer.get();
+ dhcpOption.data = new byte[dhcpOption.length];
+ byteBuffer.get(dhcpOption.data);
+ } else {
+ dhcpOption.length = 0;
+ dhcpOption.data = null;
+ }
+ return dhcpOption;
+ };
+ }
+
+ /**
+ * @return the code
+ */
+ public byte getCode() {
+ return this.code;
+ }
+
+ /**
+ * @param code the code to set
+ * @return this
+ */
+ public DhcpOption setCode(final byte code) {
+ this.code = code;
+ return this;
+ }
+
+ /**
+ * @return the length
+ */
+ public byte getLength() {
+ return this.length;
+ }
+
+ /**
+ * @param length the length to set
+ * @return this
+ */
+ public DhcpOption setLength(final byte length) {
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * @return the data
+ */
+ public byte[] getData() {
+ return this.data;
+ }
+
+ /**
+ * @param data the data to set
+ * @return this
+ */
+ public DhcpOption setData(final byte[] data) {
+ this.data = data;
+ return this;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ return Objects.hash(code, length, data);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(final Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (!(obj instanceof DhcpOption)) {
+ return false;
+ }
+ final DhcpOption other = (DhcpOption) obj;
+ return Objects.equals(this.code, other.code) &&
+ Objects.equals(this.length, other.length) &&
+ Arrays.equals(this.data, other.data);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Object#toString()
+ */
+ @Override
+ public String toString() {
+ return "DhcpOption [code=" + this.code + ", length=" + this.length
+ + ", data=" + Arrays.toString(this.data) + "]";
+ }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java
new file mode 100644
index 0000000..498704d
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/DhcpRelayAgentOption.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2017-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.onlab.packet.dhcp;
+
+import com.google.common.collect.Maps;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.Deserializer;
+import org.onlab.packet.IPacket;
+import org.slf4j.Logger;
+
+import java.nio.ByteBuffer;
+import java.util.Map;
+import java.util.Objects;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Representation of DHCP relay agent option (option 82).
+ */
+public class DhcpRelayAgentOption extends DhcpOption {
+ private static final int SUB_OPT_DEFAULT_LEN = 2;
+ private final Logger log = getLogger(getClass());
+ private final Map<Byte, DhcpOption> subOptions = Maps.newHashMap();
+
+ // Sub-option codes for option 82
+ public enum RelayAgentInfoOptions {
+ CIRCUIT_ID((byte) 1),
+ REMOTE_ID((byte) 2),
+ DOCSIS((byte) 4),
+ LINK_SELECTION((byte) 5),
+ SUBSCRIBER_ID((byte) 6),
+ RADIUS((byte) 7),
+ AUTH((byte) 8),
+ VENDOR_SPECIFIC((byte) 9),
+ RELAY_AGENT_FLAGS((byte) 10),
+ SERVER_ID_OVERRIDE((byte) 11),
+ VIRTUAL_SUBNET_SELECTION((byte) 151),
+ VIRTUAL_SUBNET_SELECTION_CTRL((byte) 152);
+
+ private byte value;
+ public byte getValue() {
+ return value;
+ }
+ RelayAgentInfoOptions(byte value) {
+ this.value = value;
+ }
+ }
+
+ @Override
+ public byte[] serialize() {
+ int totalLen = 0;
+ totalLen += subOptions.size() * SUB_OPT_DEFAULT_LEN;
+ totalLen += subOptions.values().stream().mapToInt(DhcpOption::getLength).sum();
+ totalLen += DEFAULT_LEN;
+ ByteBuffer byteBuffer = ByteBuffer.allocate(totalLen);
+ byteBuffer.put(code);
+ byteBuffer.put(length);
+ subOptions.values().forEach(subOpt -> {
+ byteBuffer.put(subOpt.code);
+ byteBuffer.put(subOpt.length);
+ byteBuffer.put(subOpt.data);
+ });
+ return byteBuffer.array();
+ }
+
+ @Override
+ public IPacket deserialize(byte[] data, int offset, int length) {
+ try {
+ return deserializer().deserialize(data, offset, length);
+ } catch (DeserializationException e) {
+ log.warn("can't deserialize DHCP relay agent information option {}", e);
+ return null;
+ }
+ }
+
+ /**
+ * Deserializer function for DHCP relay agent option.
+ *
+ * @return deserializer function
+ */
+ public static Deserializer<DhcpOption> deserializer() {
+ return (data, offset, length) -> {
+ DhcpRelayAgentOption relayOption = new DhcpRelayAgentOption();
+ ByteBuffer byteBuffer = ByteBuffer.wrap(data, offset, length);
+ relayOption.code = byteBuffer.get();
+ relayOption.length = byteBuffer.get();
+
+ while (byteBuffer.remaining() >= DEFAULT_LEN) {
+ byte subOptCode = byteBuffer.get();
+ byte subOptLen = byteBuffer.get();
+ byte[] subOptData = new byte[subOptLen];
+ byteBuffer.get(subOptData);
+
+ DhcpOption subOption = new DhcpOption();
+ subOption.code = subOptCode;
+ subOption.length = subOptLen;
+ subOption.data = subOptData;
+ relayOption.subOptions.put(subOptCode, subOption);
+ }
+
+ return relayOption;
+ };
+ }
+
+ /**
+ * Gets sub-option from this option by given option code.
+ *
+ * @param code the option code
+ * @return sub-option of given code; null if there is no sub-option for given
+ * code
+ */
+ public DhcpOption getSubOption(byte code) {
+ return subOptions.get(code);
+ }
+
+ /**
+ * Adds a sub-option for this option.
+ *
+ * @param subOption the sub-option
+ */
+ public void addSubOption(DhcpOption subOption) {
+ this.length += SUB_OPT_DEFAULT_LEN + subOption.length;
+ this.subOptions.put(subOption.getCode(), subOption);
+ }
+
+ /**
+ * Removes a sub-option by given sub-option code.
+ *
+ * @param code the code for sub-option
+ * @return sub-option removed; null of sub-option not exists
+ */
+ public DhcpOption removeSubOption(byte code) {
+ DhcpOption subOption = subOptions.remove(code);
+ if (subOption != null) {
+ this.length -= SUB_OPT_DEFAULT_LEN + subOption.length;
+ }
+ return subOption;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (!(obj instanceof DhcpRelayAgentOption)) {
+ return false;
+ }
+ DhcpRelayAgentOption that = (DhcpRelayAgentOption) obj;
+ return Objects.equals(this.subOptions, that.subOptions);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(), subOptions);
+ }
+}
diff --git a/utils/misc/src/main/java/org/onlab/packet/dhcp/package-info.java b/utils/misc/src/main/java/org/onlab/packet/dhcp/package-info.java
new file mode 100644
index 0000000..1033b5d
--- /dev/null
+++ b/utils/misc/src/main/java/org/onlab/packet/dhcp/package-info.java
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017-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.
+ */
+/**
+ * Utilities for decoding and encoding DHCP options.
+ */
+package org.onlab.packet.dhcp;
\ No newline at end of file
diff --git a/utils/misc/src/test/java/org/onlab/packet/Dhcp6Test.java b/utils/misc/src/test/java/org/onlab/packet/Dhcp6Test.java
index 927266d..7b83c00 100644
--- a/utils/misc/src/test/java/org/onlab/packet/Dhcp6Test.java
+++ b/utils/misc/src/test/java/org/onlab/packet/Dhcp6Test.java
@@ -18,6 +18,7 @@
import com.google.common.collect.ImmutableList;
import org.junit.Test;
+import org.onlab.packet.dhcp.Dhcp6Option;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -80,7 +81,7 @@
assertEquals(dhcp6.getTransactionId(), TRANSACTION_ID);
assertEquals(dhcp6.getOptions().size(), 1);
- DHCP6Option clientIdOption = dhcp6.getOptions().get(0);
+ Dhcp6Option clientIdOption = dhcp6.getOptions().get(0);
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertArrayEquals(clientIdOption.getData(), OPT_CLIENT_ID_BYTE_ARR);
}
@@ -110,7 +111,7 @@
assertArrayEquals(dhcp6.getPeerAddress(), PEER_ADDRESS.toOctets());
assertEquals(dhcp6.getOptions().size(), 1);
- DHCP6Option clientIdOption = dhcp6.getOptions().get(0);
+ Dhcp6Option clientIdOption = dhcp6.getOptions().get(0);
assertEquals(clientIdOption.getCode(), DHCP6.OptionCode.CLIENTID.value());
assertArrayEquals(clientIdOption.getData(), OPT_CLIENT_ID_BYTE_ARR);
}
@@ -124,13 +125,13 @@
dhcp6.setMsgType(DHCP6.MsgType.REQUEST.value());
dhcp6.setTransactionId(TRANSACTION_ID);
- DHCP6Option opt1 = new DHCP6Option();
+ Dhcp6Option opt1 = new Dhcp6Option();
opt1.setCode(DHCP6.OptionCode.CLIENTID.value());
opt1.setLength(OPT_CLIENT_ID_SIZE);
opt1.setData(OPT_CLIENT_ID_BYTE_ARR);
- DHCP6Option opt2 = new DHCP6Option();
+ Dhcp6Option opt2 = new Dhcp6Option();
opt2.setCode(DHCP6.OptionCode.AUTH.value());
opt2.setLength(OPT_AUTH_SIZE);
opt2.setData(OPT_AUTH_BYTE_AR);
@@ -162,13 +163,13 @@
dhcp6.setLinkAddress(LINK_ADDRESS.toOctets());
dhcp6.setPeerAddress(PEER_ADDRESS.toOctets());
- DHCP6Option opt1 = new DHCP6Option();
+ Dhcp6Option opt1 = new Dhcp6Option();
opt1.setCode(DHCP6.OptionCode.CLIENTID.value());
opt1.setLength(OPT_CLIENT_ID_SIZE);
opt1.setData(OPT_CLIENT_ID_BYTE_ARR);
- DHCP6Option opt2 = new DHCP6Option();
+ Dhcp6Option opt2 = new Dhcp6Option();
opt2.setCode(DHCP6.OptionCode.AUTH.value());
opt2.setLength(OPT_AUTH_SIZE);
opt2.setData(OPT_AUTH_BYTE_AR);
diff --git a/utils/misc/src/test/java/org/onlab/packet/DhcpTest.java b/utils/misc/src/test/java/org/onlab/packet/DhcpTest.java
index b13f78b..d8f5f6b 100644
--- a/utils/misc/src/test/java/org/onlab/packet/DhcpTest.java
+++ b/utils/misc/src/test/java/org/onlab/packet/DhcpTest.java
@@ -20,10 +20,14 @@
import org.apache.commons.lang3.StringUtils;
import org.junit.Before;
import org.junit.Test;
+import org.onlab.packet.dhcp.DhcpOption;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -32,6 +36,33 @@
*/
public class DhcpTest {
+ // For serialize test
+ private static final int TRANSACTION_ID = 1000;
+ private static final MacAddress CLIENT1_HOST_MAC = MacAddress.valueOf("1a:1a:1a:1a:1a:1a");
+ private static final Ip4Address REQ_IP = Ip4Address.valueOf("10.2.0.2");
+ private static final byte[] EXPECTED_SERIALIZED = ByteBuffer.allocate(300)
+ .put((byte) 0x01) // op code
+ .put((byte) 0x01) // hardware type
+ .put((byte) 0x06) // hardware address len
+ .put((byte) 0x00) // hops
+ .putInt(0x3e8) // transaction id
+ .putShort((short) 0x0) // seconds
+ .putShort((short) 0x0) // flags
+ .putInt(0) // client ip
+ .putInt(0) // your ip
+ .putInt(0) // server ip
+ .putInt(0) // gateway ip
+ .put(CLIENT1_HOST_MAC.toBytes()) // client hardware address
+ .put(new byte[10]) // pad
+ .put(new byte[64]) // server name
+ .put(new byte[128]) // boot file name
+ .putInt(0x63825363) // magic cookie
+ .put(new byte[]{0x35, 0x1, 0x3}) // msg type
+ .put(new byte[]{0x32, 0x4, 0xa, 0x2, 0x0, 0x2}) // requested ip
+ .put((byte) 0xff) // end of options
+ .put(new byte[50]) // pad
+ .array();
+
private Deserializer<DHCP> deserializer = DHCP.deserializer();
private byte opCode = 1;
@@ -50,7 +81,7 @@
private String bootFileName = "test-file";
private String hostName = "test-host";
- private DHCPOption hostNameOption = new DHCPOption();
+ private DhcpOption hostNameOption = new DhcpOption();
private byte[] byteHeader;
@@ -97,7 +128,7 @@
bb.put(hostNameOption.getData());
// End of options marker
- bb.put((byte) (0xff & 255));
+ bb.put((DHCP.DHCPOptionCode.OptionCode_END.getValue()));
byteHeader = bb.array();
}
@@ -162,4 +193,49 @@
assertTrue(StringUtils.contains(str, "bootFileName=" + bootFileName));
// TODO: add option unit test
}
+
+
+
+ @Test
+ public void testSerialize() throws Exception {
+ 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) DHCP.MsgType.DHCPREQUEST.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 = REQ_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);
+
+ assertArrayEquals(EXPECTED_SERIALIZED, dhcpReply.serialize());
+ }
}