Bug 5199 : Corrected the log messages
[vpnservice.git] / dhcpservice / dhcpservice-impl / src / main / java / org / opendaylight / vpnservice / dhcpservice / DhcpPktHandler.java
1 /*
2  * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.vpnservice.dhcpservice;
9
10 import java.io.ByteArrayOutputStream;
11 import java.io.IOException;
12 import java.math.BigInteger;
13 import java.net.InetAddress;
14 import java.net.UnknownHostException;
15 import java.util.Arrays;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Future;
21
22 import org.apache.commons.lang3.tuple.ImmutablePair;
23 import org.apache.commons.net.util.SubnetUtils;
24 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
25 import org.opendaylight.controller.liblldp.EtherTypes;
26 import org.opendaylight.controller.liblldp.NetUtils;
27 import org.opendaylight.controller.liblldp.PacketException;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.vpnservice.dhcpservice.api.DHCP;
31 import org.opendaylight.vpnservice.dhcpservice.api.DHCPConstants;
32 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
33 import org.opendaylight.vpnservice.dhcpservice.api.DHCPUtils;
34 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
35 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
36 import org.opendaylight.vpnservice.mdsalutil.NwConstants;
37 import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
38 import org.opendaylight.vpnservice.mdsalutil.packet.IEEE8021Q;
39 import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
40 import org.opendaylight.vpnservice.mdsalutil.packet.IPv4;
41 import org.opendaylight.vpnservice.mdsalutil.packet.UDP;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.HostRoutes;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceInputBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetEgressActionsForInterfaceOutput;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexInput;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexInputBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetInterfaceFromIfIndexOutput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
61 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
62 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
63 import org.opendaylight.yangtools.yang.common.RpcResult;
64 import org.slf4j.Logger;
65 import org.slf4j.LoggerFactory;
66
67 import com.google.common.base.Optional;
68
69 public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
70
71     private static final Logger LOG = LoggerFactory.getLogger(DhcpPktHandler.class);
72     private final DataBroker dataBroker;
73     private final DhcpManager dhcpMgr;
74     private OdlInterfaceRpcService interfaceManagerRpc;
75     private static HashMap<String, ImmutablePair<BigInteger, String>> localCache = new HashMap<String, ImmutablePair<BigInteger, String>>();
76     private boolean computeUdpChecksum = true;
77     private PacketProcessingService pktService;
78
79     public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager) {
80         this.dataBroker = broker;
81         dhcpMgr = dhcpManager;
82     }
83
84     //TODO: Handle this in a separate thread
85     @Override
86     public void onPacketReceived(PacketReceived packet) {
87         LOG.trace("Pkt received: {}", packet);
88         Class<? extends PacketInReason> pktInReason = packet.getPacketInReason();
89         if (isPktInReasonSendtoCtrl(pktInReason)) {
90             byte[] inPayload = packet.getPayload();
91             Ethernet ethPkt = new Ethernet();
92             try {
93                 ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
94             } catch (Exception e) {
95                 LOG.warn("Failed to decode DHCP Packet", e);
96                 return;
97             }
98             try {
99                 DHCP pktIn;
100                 pktIn = getDhcpPktIn(ethPkt);
101                 if (pktIn != null) {
102                     LOG.trace("DHCPPkt received: {}", pktIn);
103                     BigInteger metadata = packet.getMatch().getMetadata().getMetadata();
104                     long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
105                     String interfaceName = getInterfaceNameFromTag(portTag);
106                     ImmutablePair<BigInteger, String> pair = getDpnIdPhysicalAddressFromInterfaceName(interfaceName);
107                     DHCP replyPkt = handleDhcpPacket(pktIn, interfaceName);
108                     byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, pair.getRight());
109                     sendPacketOut(pktOut, pair.getLeft(), interfaceName);
110                 }
111             } catch (Exception e) {
112                 LOG.warn("Failed to get DHCP Reply");
113                 LOG.trace("Reason for failure {}", e);
114             }
115         }
116     }
117
118     private void sendPacketOut(byte[] pktOut, BigInteger dpnId, String interfaceName) {
119         LOG.trace("Sending packet out DpId {}, portId {}, vlanId {}, interfaceName {}", dpnId, interfaceName);
120         List<Action> action = getEgressAction(interfaceName);
121         TransmitPacketInput output = MDSALUtil.getPacketOut(action, pktOut, dpnId);
122         LOG.trace("Transmitting packet: {}",output);
123         this.pktService.transmitPacket(output);
124     }
125
126     private DHCP handleDhcpPacket(DHCP dhcpPkt, String interfaceName) {
127         LOG.debug("DHCP pkt rcvd {}", dhcpPkt);
128         byte msgType = dhcpPkt.getMsgType();
129         if (msgType == DHCPConstants.MSG_DECLINE) {
130             LOG.debug("DHCPDECLINE received");
131             return null;
132         } else if (msgType == DHCPConstants.MSG_RELEASE) {
133             LOG.debug("DHCPRELEASE received");
134             return null;
135         }
136
137         Port nPort = getNeutronPort(interfaceName);
138         Subnet nSubnet = getNeutronSubnet(nPort);
139         DhcpInfo dhcpInfo = getDhcpInfo(nPort, nSubnet);
140         LOG.trace("NeutronPort: {} \n NeutronSubnet: {}, dhcpInfo{}",nPort, nSubnet, dhcpInfo);
141         DHCP reply = null;
142         if (dhcpInfo != null) {
143             if (msgType == DHCPConstants.MSG_DISCOVER) {
144                 reply = getReplyToDiscover(dhcpPkt, dhcpInfo);
145             } else if (msgType == DHCPConstants.MSG_REQUEST) {
146                 reply = getReplyToRequest(dhcpPkt, dhcpInfo);
147             }
148         }
149
150         return reply;
151     }
152
153     private DhcpInfo getDhcpInfo(Port nPort, Subnet nSubnet) {
154         DhcpInfo dhcpInfo = null;
155         if( (nPort != null) && (nSubnet != null) ) {
156             String clientIp = nPort.getFixedIps().get(0).getIpAddress().getIpv4Address().getValue();
157             String serverIp = nSubnet.getGatewayIp().getIpv4Address().getValue();
158             List<IpAddress> dnsServers = nSubnet.getDnsNameservers();
159             dhcpInfo = new DhcpInfo();
160             dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
161                 .setCidr(nSubnet.getCidr()).setHostRoutes(nSubnet.getHostRoutes())
162                 .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
163         } else {
164             //FIXME: Delete this test code
165             LOG.error("TestOnly Code");
166             dhcpInfo = new DhcpInfo();
167             dhcpInfo.setClientIp("1.1.1.3").setServerIp("1.1.1.1")
168                 .setCidr("1.1.1.0/24").addDnsServer("1.1.1.1");
169             LOG.warn("Failed to get Subnet info for DHCP reply");
170         }
171         return dhcpInfo;
172     }
173
174     private Subnet getNeutronSubnet(Port nPort) {
175         return dhcpMgr.getNeutronSubnet(nPort);
176     }
177
178     private Port getNeutronPort(String interfaceName) {
179             return dhcpMgr.getNeutronPort(interfaceName);
180     }
181
182     private DHCP getDhcpPktIn(Ethernet actualEthernetPacket) {
183         Ethernet ethPkt = actualEthernetPacket;
184         LOG.trace("Inside getDhcpPktIn ethPkt {}", ethPkt);
185         if (ethPkt.getEtherType() == (short)NwConstants.ETHTYPE_802_1Q) {
186             ethPkt = (Ethernet)ethPkt.getPayload();
187         }
188         if (ethPkt.getPayload() instanceof IPv4) {
189             IPv4 ipPkt = (IPv4) ethPkt.getPayload();
190             if (ipPkt.getPayload() instanceof UDP) {
191                 UDP udpPkt = (UDP) ipPkt.getPayload();
192                 if ((udpPkt.getSourcePort() == DHCPMConstants.dhcpClientPort)
193                         && (udpPkt.getDestinationPort() == DHCPMConstants.dhcpServerPort)) {
194                     LOG.trace("Matched dhcpClientPort and dhcpServerPort");
195                     byte[] rawDhcpPayload = udpPkt.getRawPayload();
196                     DHCP reply = new DHCP();
197                     try {
198                         reply.deserialize(rawDhcpPayload, 0, rawDhcpPayload.length);
199                     } catch (PacketException e) {
200                         LOG.warn("Failed to deserialize DHCP pkt");
201                         LOG.trace("Reason for failure {}", e);
202                         return null;
203                     }
204                     return reply;
205                 }
206             }
207         }
208         return null;
209     }
210
211     DHCP getReplyToDiscover(DHCP dhcpPkt, DhcpInfo dhcpInfo) {
212         DHCP reply = new DHCP();
213         reply.setOp(DHCPConstants.BOOTREPLY);
214         reply.setHtype(dhcpPkt.getHtype());
215         reply.setHlen(dhcpPkt.getHlen());
216         reply.setHops((byte) 0);
217         reply.setXid(dhcpPkt.getXid());
218         reply.setSecs((short) 0);
219
220         reply.setYiaddr(dhcpInfo.getClientIp());
221         reply.setSiaddr(dhcpInfo.getServerIp());
222
223         reply.setFlags(dhcpPkt.getFlags());
224         reply.setGiaddr(dhcpPkt.getGiaddr());
225         reply.setChaddr(dhcpPkt.getChaddr());
226
227         reply.setMsgType(DHCPConstants.MSG_OFFER);
228         if(dhcpPkt.containsOption(DHCPConstants.OPT_PARAMETER_REQUEST_LIST)) {
229             setParameterListOptions(dhcpPkt, reply, dhcpInfo);
230         }
231         setCommonOptions(reply, dhcpInfo);
232         return reply;
233     }
234
235     DHCP getReplyToRequest(DHCP dhcpPkt, DhcpInfo dhcpInfo) {
236         boolean sendAck = false;
237         byte[] requestedIp = null;
238         DHCP reply = new DHCP();
239         reply.setOp(DHCPConstants.BOOTREPLY);
240         reply.setHtype(dhcpPkt.getHtype());
241         reply.setHlen(dhcpPkt.getHlen());
242         reply.setHops((byte) 0);
243         reply.setXid(dhcpPkt.getXid());
244         reply.setSecs((short) 0);
245
246         reply.setFlags(dhcpPkt.getFlags());
247         reply.setGiaddr(dhcpPkt.getGiaddr());
248         reply.setChaddr(dhcpPkt.getChaddr());
249         byte[] allocatedIp = DHCPUtils.strAddrToByteArray(dhcpInfo.getClientIp());
250         if(Arrays.equals(allocatedIp, dhcpPkt.getCiaddr())) {
251             //This means a renew request
252             sendAck = true;
253         } else {
254             requestedIp = dhcpPkt.getOptionBytes(DHCPConstants.OPT_REQUESTED_ADDRESS);
255             sendAck = Arrays.equals(allocatedIp, requestedIp);
256         }
257
258         if (sendAck) {
259             reply.setCiaddr(dhcpPkt.getCiaddr());
260             reply.setYiaddr(dhcpInfo.getClientIp());
261             reply.setSiaddr(dhcpInfo.getServerIp());
262             reply.setMsgType(DHCPConstants.MSG_ACK);
263             if(dhcpPkt.containsOption(DHCPConstants.OPT_PARAMETER_REQUEST_LIST)) {
264                 setParameterListOptions(dhcpPkt, reply, dhcpInfo);
265             }
266             setCommonOptions(reply, dhcpInfo);
267         }
268         else {
269             reply.setMsgType(DHCPConstants.MSG_NAK);
270         }
271         return reply;
272     }
273
274     protected byte[] getDhcpPacketOut(DHCP reply, Ethernet etherPkt, String phyAddrees) {
275         if (reply == null) {
276             /*
277              * DECLINE or RELEASE don't result in reply packet
278              */
279             return null;
280         }
281         LOG.debug("Sending DHCP Pkt {}", reply);
282         // create UDP pkt
283         UDP udpPkt = new UDP();
284         byte[] rawPkt;
285         try {
286             rawPkt = reply.serialize();
287         } catch (PacketException e2) {
288             // TODO Auto-generated catch block
289             e2.printStackTrace();
290             return null;
291         }
292         udpPkt.setRawPayload(rawPkt);
293         udpPkt.setDestinationPort(DHCPMConstants.dhcpClientPort);
294         udpPkt.setSourcePort(DHCPMConstants.dhcpServerPort);
295         udpPkt.setLength((short) (rawPkt.length + 8));
296         //Create IP Pkt
297         IPv4 ip4Reply = new IPv4();
298         try {
299             rawPkt = udpPkt.serialize();
300         } catch (PacketException e) {
301             // TODO Auto-generated catch block
302             e.printStackTrace();
303             return null;
304         }
305         short checkSum = 0;
306         if(this.computeUdpChecksum) {
307          checkSum = computeChecksum(rawPkt, reply.getSiaddr(),
308                 NetUtils.intToByteArray4(DHCPMConstants.BCAST_IP));
309         }
310         udpPkt.setChecksum(checkSum);
311         ip4Reply.setPayload(udpPkt);
312         ip4Reply.setProtocol(IPProtocols.UDP.byteValue());
313         ip4Reply.setSourceAddress(reply.getSiaddrAsInetAddr());
314         ip4Reply.setDestinationAddress(DHCPMConstants.BCAST_IP);
315         ip4Reply.setTotalLength((short) (rawPkt.length+20));
316         ip4Reply.setTtl((byte) 32);
317         // create Ethernet Frame
318         Ethernet ether = new Ethernet();
319         if (etherPkt.getEtherType() == (short)NwConstants.ETHTYPE_802_1Q) {
320             IEEE8021Q vlanPacket = (IEEE8021Q) etherPkt.getPayload();
321             IEEE8021Q vlanTagged = new IEEE8021Q();
322             vlanTagged.setCFI(vlanPacket.getCfi());
323             vlanTagged.setPriority(vlanPacket.getPriority());
324             vlanTagged.setVlanId(vlanPacket.getVlanId());
325             vlanTagged.setPayload(ip4Reply);
326             vlanTagged.setEtherType(EtherTypes.IPv4.shortValue());
327             ether.setPayload(vlanTagged);
328             ether.setEtherType((short) NwConstants.ETHTYPE_802_1Q);
329         } else {
330             ether.setEtherType(EtherTypes.IPv4.shortValue());
331             ether.setPayload(ip4Reply);
332         }
333         //TODO: 
334         ether.setSourceMACAddress(getServerMacAddress(phyAddrees));
335         ether.setDestinationMACAddress(etherPkt.getSourceMACAddress());
336
337         try {
338             rawPkt = ether.serialize();
339         } catch (PacketException e) {
340             LOG.warn("Failed to serialize ethernet reply",e);
341             return null;
342         }
343         return rawPkt;
344     }
345
346     private byte[] getServerMacAddress(String phyAddress) {
347         // Should we return ControllerMac instead?
348         return DHCPUtils.strMacAddrtoByteArray(phyAddress);
349     }
350
351     public short computeChecksum(byte[] inData, byte[] srcAddr, byte[] destAddr) {
352         short checkSum = (short) 0;
353         int sum = 0, carry = 0;
354         int wordData, i;
355
356         for (i = 0; i < inData.length - 1; i = i + 2) {
357             // Skip, if the current bytes are checkSum bytes
358             wordData = ((inData[i] << 8) & 0xFF00) + (inData[i + 1] & 0xFF);
359             sum = sum + wordData;
360         }
361
362         if (i < inData.length) {
363             wordData = ((inData[i] << 8) & 0xFF00) + (0 & 0xFF);
364             sum = sum + wordData;
365         }
366
367         for (i = 0; i < 4; i = i + 2) {
368             wordData = ((srcAddr[i] << 8) & 0xFF00) + (srcAddr[i + 1] & 0xFF);
369             sum = sum + wordData;
370         }
371
372         for (i = 0; i < 4; i = i + 2) {
373             wordData = ((destAddr[i] << 8) & 0xFF00) + (destAddr[i + 1] & 0xFF);
374             sum = sum + wordData;
375         }
376         sum = sum + 17 + inData.length;
377
378         while((sum >> 16) != 0) {
379             carry = (sum >> 16);
380             sum = (sum & 0xFFFF)+ carry;
381         }
382         checkSum = (short) ~((short) sum & 0xFFFF);
383         if(checkSum == 0) {
384             checkSum = (short)0xffff;
385         }
386         return checkSum;
387     }
388
389     private void setCommonOptions(DHCP pkt, DhcpInfo dhcpInfo) {
390         pkt.setOptionInt(DHCPConstants.OPT_LEASE_TIME, dhcpMgr.getDhcpLeaseTime());
391         if (dhcpMgr.getDhcpDefDomain() != null) {
392             pkt.setOptionString(DHCPConstants.OPT_DOMAIN_NAME, dhcpMgr.getDhcpDefDomain());
393         }
394         if(dhcpMgr.getDhcpLeaseTime() > 0) {
395             pkt.setOptionInt(DHCPConstants.OPT_REBINDING_TIME, dhcpMgr.getDhcpRebindingTime());
396             pkt.setOptionInt(DHCPConstants.OPT_RENEWAL_TIME, dhcpMgr.getDhcpRenewalTime());
397         }
398         SubnetUtils util = null;
399         SubnetInfo info = null;
400         util = new SubnetUtils(dhcpInfo.getCidr());
401         info = util.getInfo();
402         String gwIp = dhcpInfo.getGatewayIp();
403         List<String> dnServers = dhcpInfo.getDnsServers();
404         try {
405             /*
406              * setParameterListOptions may have initialized some of these
407              * options to maintain order. If we can't fill them, unset to avoid
408              * sending wrong information in reply.
409              */
410             if (gwIp != null) {
411                 pkt.setOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER, gwIp);
412                 pkt.setOptionInetAddr(DHCPConstants.OPT_ROUTERS, gwIp);
413             } else {
414                 pkt.unsetOption(DHCPConstants.OPT_SERVER_IDENTIFIER);
415                 pkt.unsetOption(DHCPConstants.OPT_ROUTERS);
416             }
417             if (info != null) {
418                 pkt.setOptionInetAddr(DHCPConstants.OPT_SUBNET_MASK, info.getNetmask());
419                 pkt.setOptionInetAddr(DHCPConstants.OPT_BROADCAST_ADDRESS, info.getBroadcastAddress());
420             } else {
421                 pkt.unsetOption(DHCPConstants.OPT_SUBNET_MASK);
422                 pkt.unsetOption(DHCPConstants.OPT_BROADCAST_ADDRESS);
423             }
424             if ((dnServers != null) && (dnServers.size() > 0)) {
425                 pkt.setOptionStrAddrs(DHCPConstants.OPT_DOMAIN_NAME_SERVERS, dnServers);
426             } else {
427                 pkt.unsetOption(DHCPConstants.OPT_DOMAIN_NAME_SERVERS);
428             }
429         } catch (UnknownHostException e) {
430             // TODO Auto-generated catch block
431             e.printStackTrace();
432         }
433     }
434
435     private void setParameterListOptions(DHCP req, DHCP reply, DhcpInfo dhcpInfo) {
436         byte[] paramList = req.getOptionBytes(DHCPConstants.OPT_PARAMETER_REQUEST_LIST);
437         for(int i = 0; i < paramList.length; i++) {
438             switch (paramList[i]) {
439             case DHCPConstants.OPT_SUBNET_MASK:
440             case DHCPConstants.OPT_ROUTERS:
441             case DHCPConstants.OPT_SERVER_IDENTIFIER:
442             case DHCPConstants.OPT_DOMAIN_NAME_SERVERS:
443             case DHCPConstants.OPT_BROADCAST_ADDRESS:
444             case DHCPConstants.OPT_LEASE_TIME:
445             case DHCPConstants.OPT_RENEWAL_TIME:
446             case DHCPConstants.OPT_REBINDING_TIME:
447                 /* These values will be filled in setCommonOptions
448                  * Setting these just to preserve order as
449                  * specified in PARAMETER_REQUEST_LIST.
450                  */
451                 reply.setOptionInt(paramList[i], 0);
452                 break;
453             case DHCPConstants.OPT_DOMAIN_NAME:
454                 reply.setOptionString(paramList[i], " ");
455                 break;
456             case DHCPConstants.OPT_CLASSLESS_ROUTE:
457                 setOptionClasslessRoute(reply, dhcpInfo);
458                 break;
459             default:
460                 LOG.debug("DHCP Option code {} not supported yet", paramList[i]);
461                 break;
462             }
463         }
464     }
465     private void setOptionClasslessRoute(DHCP reply, DhcpInfo dhcpInfo) {
466         List<HostRoutes> hostRoutes = dhcpInfo.getHostRoutes();
467         if(hostRoutes == null) {
468             //we can't set this option, so return
469             return;
470         }
471         ByteArrayOutputStream result = new ByteArrayOutputStream();
472         Iterator<HostRoutes> iter = hostRoutes.iterator();
473         while(iter.hasNext()) {
474             HostRoutes hostRoute = iter.next();
475             if(hostRoute.getNexthop().getIpv4Address() == null ||
476                 hostRoute.getDestination().getIpv4Prefix() == null ) {
477                 // we only deal with IPv4 addresses
478                 return;
479             }
480             String router = hostRoute.getNexthop().getIpv4Address().getValue();
481             String dest = hostRoute.getDestination().getIpv4Prefix().getValue();
482             try {
483                 result.write(convertToClasslessRouteOption(dest, router));
484             } catch (IOException | NullPointerException e) {
485                 LOG.debug("Exception {}",e.getMessage());
486             }
487         }
488         if (result.size() > 0) {
489             reply.setOptionBytes(DHCPConstants.OPT_CLASSLESS_ROUTE , result.toByteArray());
490         }
491     }
492
493     protected byte[] convertToClasslessRouteOption(String dest, String router) {
494         ByteArrayOutputStream bArr = new ByteArrayOutputStream();
495         if((dest == null ||
496                 router == null)) {
497             return null;
498         }
499
500         //get prefix
501         Short prefix = null;
502         String[] parts = dest.split("/");
503         if (parts.length < 2) {
504             prefix = new Short((short)0);
505         } else {
506             prefix = Short.valueOf(parts[1]);
507         }
508
509         bArr.write(prefix.byteValue());
510         SubnetUtils util = new SubnetUtils(dest);
511         SubnetInfo info = util.getInfo();
512         String strNetAddr = info.getNetworkAddress();
513         try {
514             byte[] netAddr = InetAddress.getByName(strNetAddr).getAddress();
515           //Strip any trailing 0s from netAddr
516             for(int i = 0; i < netAddr.length;i++) {
517                 if(netAddr[i] != 0) {
518                     bArr.write(netAddr,i,1);
519                 }
520             }
521             bArr.write(InetAddress.getByName(router).getAddress());
522         } catch (IOException e) {
523             return null;
524         }
525         return bArr.toByteArray();
526     }
527
528     private boolean isPktInReasonSendtoCtrl(Class<? extends PacketInReason> pktInReason) {
529         return (pktInReason == SendToController.class);
530     }
531
532     @Override
533     public void close() throws Exception {
534         // TODO Auto-generated method stub
535     }
536
537     public void setPacketProcessingService(PacketProcessingService packetService) {
538         this.pktService = packetService;
539     }
540
541     public void setInterfaceManagerRpc(OdlInterfaceRpcService interfaceManagerRpc) {
542         LOG.trace("Registered interfaceManager successfully");;
543         this.interfaceManagerRpc = interfaceManagerRpc;
544     }
545
546     private String getInterfaceNameFromTag(long portTag) {
547         String interfaceName = null;
548         GetInterfaceFromIfIndexInput input = new GetInterfaceFromIfIndexInputBuilder().setIfIndex(new Integer((int)portTag)).build();
549         Future<RpcResult<GetInterfaceFromIfIndexOutput>> futureOutput = interfaceManagerRpc.getInterfaceFromIfIndex(input);
550         try {
551             GetInterfaceFromIfIndexOutput output = futureOutput.get().getResult();
552             interfaceName = output.getInterfaceName();
553         } catch (InterruptedException | ExecutionException e) {
554             LOG.error("Error while retrieving the interfaceName from tag using getInterfaceFromIfIndex RPC");
555         }
556         LOG.trace("Returning interfaceName {} for tag {} form getInterfaceNameFromTag", interfaceName, portTag);
557         return interfaceName;
558     }
559
560     private org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(String interfaceName) {
561         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId =
562                 buildStateInterfaceId(interfaceName);
563         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional =
564                 MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, ifStateId, dataBroker);
565         if (!ifStateOptional.isPresent()) {
566             return null;
567         }
568
569         return ifStateOptional.get();
570     }
571
572     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
573         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
574                 InstanceIdentifier.builder(InterfacesState.class)
575                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
576                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName));
577         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id = idBuilder.build();
578         return id;
579     }
580
581     private List<Action> getEgressAction(String interfaceName) {
582         List<Action> actions = null;
583         try {
584             Future<RpcResult<GetEgressActionsForInterfaceOutput>> result =
585                     interfaceManagerRpc.getEgressActionsForInterface(
586                             new GetEgressActionsForInterfaceInputBuilder().setIntfName(interfaceName).build());
587             RpcResult<GetEgressActionsForInterfaceOutput> rpcResult = result.get();
588             if(!rpcResult.isSuccessful()) {
589                 LOG.warn("RPC Call to Get egress actions for interface {} returned with Errors {}", interfaceName, rpcResult.getErrors());
590             } else {
591                 actions = rpcResult.getResult().getAction();
592             }
593         } catch (InterruptedException | ExecutionException e) {
594             LOG.warn("Exception when egress actions for interface {}", interfaceName, e);
595         }
596         return actions;
597     }
598
599     private ImmutablePair<BigInteger, String> getDpnIdPhysicalAddressFromInterfaceName(String interfaceName) {
600         ImmutablePair<BigInteger, String> pair = localCache.get(interfaceName);
601         if (pair!=null && pair.getLeft() != null && pair.getRight() != null) {
602             return pair;
603         }
604         NodeConnectorId nodeConnectorId = null;
605         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface interfaceState = getInterfaceStateFromOperDS(interfaceName);
606         if(interfaceState != null) {
607             List<String> ofportIds = interfaceState.getLowerLayerIf();
608             nodeConnectorId = new NodeConnectorId(ofportIds.get(0));
609         }
610         BigInteger dpId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
611         String phyAddress = interfaceState==null ? "":interfaceState.getPhysAddress().getValue();
612         pair = new ImmutablePair<BigInteger, String>(dpId, phyAddress);
613         localCache.put(interfaceName, pair);
614         return null;
615     }
616 }