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