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