Added DHCP Option-82(circuit-id) to Dhcp relay app, addressed patch-1 comments

Change-Id: If99fd1f0794b3aff9ae88948d98632e6c9ff1090
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 5731b31..79bfaa8 100644
--- a/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
+++ b/apps/dhcprelay/src/main/java/org/onosproject/dhcprelay/DhcpRelay.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.dhcprelay;
 
+import java.nio.ByteBuffer;
+import java.util.List;
 import java.util.Set;
 
 import org.apache.felix.scr.annotations.Activate;
@@ -23,10 +25,14 @@
 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.Ethernet;
 import org.onlab.packet.IPv4;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.UDP;
+import org.onlab.packet.VlanId;
+import org.onlab.util.HexString;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.ConnectPoint;
@@ -52,6 +58,8 @@
 
 import com.google.common.collect.ImmutableSet;
 import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_CircuitID;
+import static org.onlab.packet.DHCP.DHCPOptionCode.OptionCode_MessageType;
 /**
  * DHCP Relay Agent Application Component.
  */
@@ -185,40 +193,38 @@
                     UDP udpPacket = (UDP) ipv4Packet.getPayload();
                     DHCP dhcpPayload = (DHCP) udpPacket.getPayload();
                     if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
-                        udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
-                        //This packet is dhcp client request.
-                        forwardPacket(context, dhcpPayload);
-                    } else {
-                        //This packet is a dhcp reply from DHCP server.
-                        sendReply(context, dhcpPayload);
+                        udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT ||
+                        udpPacket.getSourcePort() == UDP.DHCP_SERVER_PORT &&
+                        udpPacket.getDestinationPort() == UDP.DHCP_CLIENT_PORT) {
+                        //This packet is dhcp.
+                        processDhcpPacket(context, dhcpPayload);
                     }
                 }
             }
         }
 
         //forward the packet to ConnectPoint where the DHCP server is attached.
-        private void forwardPacket(PacketContext context, DHCP dhcpPayload) {
-            if (dhcpPayload == null) {
-                log.debug("DHCP packet without payload, do nothing");
-                return;
-            }
+        private void forwardPacket(Ethernet packet) {
 
             //send Packetout to dhcp server connectpoint.
             if (dhcpServerConnectPoint != null) {
                 TrafficTreatment t = DefaultTrafficTreatment.builder()
                         .setOutput(dhcpServerConnectPoint.port()).build();
                 OutboundPacket o = new DefaultOutboundPacket(
-                        dhcpServerConnectPoint.deviceId(), t, context.inPacket().unparsed());
+                        dhcpServerConnectPoint.deviceId(), t, ByteBuffer.wrap(packet.serialize()));
                 packetService.emit(o);
             }
         }
 
-        /*//process the dhcp packet before sending to server
+        //process the dhcp packet before sending to server
         private void processDhcpPacket(PacketContext context, DHCP dhcpPayload) {
+
             if (dhcpPayload == null) {
                 return;
             }
+
             Ethernet packet = context.inPacket().parsed();
+            String circuitIdFrmClient = context.inPacket().receivedFrom().elementId().toString();
             DHCPPacketType incomingPacketType = null;
             for (DHCPOption option : dhcpPayload.getOptions()) {
                 if (option.getCode() == OptionCode_MessageType.getValue()) {
@@ -228,21 +234,78 @@
             }
             switch (incomingPacketType) {
             case DHCPDISCOVER:
+                //add the circuit id as switch dpid and forward the packet to dhcp server.
+                Ethernet ethernetPacketDiscover = processDhcpPacketFrmClient(packet, circuitIdFrmClient,
+                        (byte) DHCPPacketType.DHCPDISCOVER.getValue());
+                forwardPacket(ethernetPacketDiscover);
+                break;
+            case DHCPOFFER:
+                //reply to dhcp client.
+                sendReply(packet);
+                break;
+            case DHCPREQUEST:
+                //add the circuit id as switch dpid and forward the packet to dhcp server.
+                Ethernet ethernetPacketRequest = processDhcpPacketFrmClient(packet, circuitIdFrmClient,
+                        (byte) DHCPPacketType.DHCPREQUEST.getValue());
+                forwardPacket(ethernetPacketRequest);
+                break;
+            case DHCPACK:
+                //reply to dhcp client.
+                sendReply(packet);
                 break;
             default:
                 break;
             }
-        }*/
+        }
+
+        //build the DHCP discover/request packet with circuitid(DpId) suboption.
+        private Ethernet processDhcpPacketFrmClient(Ethernet ethernetPacket, String circuitId,
+                byte incomingPacketType) {
+
+            // get dhcp header.
+            Ethernet etherReply = (Ethernet) ethernetPacket.clone();
+            IPv4 ipv4Packet = (IPv4) etherReply.getPayload();
+            UDP udpPacket = (UDP) ipv4Packet.getPayload();
+            DHCP dhcpPacket = (DHCP) udpPacket.getPayload();
+
+            // DHCP Options.
+            List<DHCPOption> optionList = dhcpPacket.getOptions();
+
+            // Dhcp SubOption as CircuitID
+            DHCPOption option = new DHCPOption();
+            option.setCode(OptionCode_CircuitID.getValue());
+            option.setLength((byte) 10);
+
+            // start object for suboption circuit id.
+            String[] actualDpId = circuitId.split(":", 2);
+            DHCPOption subOption = new DHCPOption();
+            subOption.setCode((byte) 1);
+            byte[] subOptionData = HexString.fromHexString(actualDpId[1], null);
+            subOption.setData(subOptionData);
+            subOption.setLength((byte) 8);
+            // end object for suboption circuit id.
+
+            // converting suboption to byte array
+            byte[] data = new byte[10];
+            ByteBuffer bb = ByteBuffer.wrap(data);
+            DHCP.dhcpOptionToByteArray(subOption, bb);
+
+            option.setData(data);
+            optionList.add(optionList.size() - 1, option);
+
+            dhcpPacket.setOptions(optionList);
+            udpPacket.setPayload(dhcpPacket);
+            ipv4Packet.setPayload(udpPacket);
+            etherReply.setPayload(ipv4Packet);
+            return etherReply;
+        }
 
         //send the response to the requestor host.
-        private void sendReply(PacketContext context, DHCP dhcpPayload) {
-            if (dhcpPayload == null) {
-                log.debug("DHCP packet without payload, do nothing");
-                return;
-            }
+        private void sendReply(Ethernet ethPacket) {
+
             //get the host info
-            Ethernet packet = context.inPacket().parsed();
-            Host host = hostService.getHost(HostId.hostId(packet.getDestinationMAC()));
+            Host host = hostService.getHost(HostId.hostId(ethPacket.getDestinationMAC(),
+                    VlanId.vlanId(ethPacket.getVlanID())));
             ConnectPoint dhcpRequestor = new ConnectPoint(host.location().elementId(),
                                                     host.location().port());
 
@@ -251,7 +314,7 @@
                 TrafficTreatment t = DefaultTrafficTreatment.builder()
                         .setOutput(dhcpRequestor.port()).build();
                 OutboundPacket o = new DefaultOutboundPacket(
-                        dhcpRequestor.deviceId(), t, context.inPacket().unparsed());
+                        dhcpRequestor.deviceId(), t, ByteBuffer.wrap(ethPacket.serialize()));
                 packetService.emit(o);
             }
         }
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 034b67a..012443e 100644
--- a/utils/misc/src/main/java/org/onlab/packet/DHCP.java
+++ b/utils/misc/src/main/java/org/onlab/packet/DHCP.java
@@ -62,7 +62,7 @@
         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_END((byte) 255);
+        OptionCode_CircuitID((byte) 82), OptionCode_END((byte) 255);
 
         protected byte value;
 
@@ -426,17 +426,22 @@
         bb.put((byte) 0x53);
         bb.put((byte) 0x63);
         for (final DHCPOption option : this.options) {
-            final int code = option.getCode() & 0xff;
-            bb.put((byte) code);
-            if (code != 0 && code != 255) {
-                bb.put(option.getLength());
-                bb.put(option.getData());
-            }
+            dhcpOptionToByteArray(option, bb);
         }
         // 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) {