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