Merge "Add pkt handling to DHCPService"
[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.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.util.Arrays;
15 import java.util.Iterator;
16 import java.util.List;
17
18 import org.apache.commons.net.util.SubnetUtils;
19 import org.apache.commons.net.util.SubnetUtils.SubnetInfo;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22 import org.opendaylight.controller.liblldp.EtherTypes;
23 import org.opendaylight.controller.liblldp.HexEncode;
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.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.vpnservice.dhcpservice.api.DHCP;
29 import org.opendaylight.vpnservice.dhcpservice.api.DHCPConstants;
30 import org.opendaylight.vpnservice.dhcpservice.api.DHCPMConstants;
31 import org.opendaylight.vpnservice.dhcpservice.api.DHCPUtils;
32 import org.opendaylight.vpnservice.mdsalutil.MDSALDataStoreUtils;
33 import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
34 import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
35 import org.opendaylight.vpnservice.mdsalutil.packet.IPv4;
36 import org.opendaylight.vpnservice.mdsalutil.packet.UDP;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnet.attributes.HostRoutes;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.subnets.rev150712.subnets.attributes.subnets.Subnet;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
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.SendToController;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
54 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
55
56 import com.google.common.base.Optional;
57
58 public class DhcpPktHandler implements AutoCloseable, PacketProcessingListener {
59     
60     private static final Logger LOG = LoggerFactory.getLogger(DhcpPktHandler.class);
61     private final DataBroker dataBroker;
62     private final DhcpManager dhcpMgr;
63
64     private boolean computeUdpChecksum = true;
65     private PacketProcessingService pktService;
66
67     public DhcpPktHandler(final DataBroker broker, final DhcpManager dhcpManager) {
68         this.dataBroker = broker;
69         dhcpMgr = dhcpManager;
70     }
71
72     //TODO: Handle this in a separate thread
73     @Override
74     public void onPacketReceived(PacketReceived packet) {
75         LOG.trace("Pkt received: {}", packet);
76         Class<? extends PacketInReason> pktInReason = packet.getPacketInReason();
77         short tableId = packet.getTableId().getValue();
78         if (isPktInReasonSendtoCtrl(pktInReason) && ((DHCPMConstants.DHCP_TABLE == tableId))) {
79             byte[] inPayload = packet.getPayload();
80             Ethernet ethPkt = new Ethernet();
81             try {
82                 ethPkt.deserialize(inPayload, 0, inPayload.length * NetUtils.NumBitsInAByte);
83             } catch (Exception e) {
84                 LOG.warn("Failed to decode DHCP Packet", e);
85                 return;
86             }
87             try {
88                 DHCP pktIn = getDhcpPktIn(ethPkt);
89                 LOG.trace("DHCPPkt received: {}", pktIn);
90                 if (pktIn != null) {
91                     NodeConnectorRef inNcRef = packet.getIngress();
92                     FlowCapableNodeConnector fcNc = this.getFlowCapableNodeConnector(inNcRef);
93                     DHCP replyPkt = handleDhcpPacket(pktIn, fcNc);
94                     byte[] pktOut = getDhcpPacketOut(replyPkt, ethPkt, fcNc);
95                     sendPacketOut(pktOut, inNcRef);
96                 }
97             } catch (Exception e) {
98                 LOG.warn("Failed to get DHCP Reply", e);
99             }
100         }
101     }
102
103     private void sendPacketOut(byte[] pktOut, NodeConnectorRef ingress) {
104         // We go out the same port we came in on
105         InstanceIdentifier<Node> egressNodePath = getNodePath(ingress.getValue());
106         TransmitPacketInput input = new TransmitPacketInputBuilder()
107             .setPayload(pktOut).setNode(new NodeRef(egressNodePath))
108             .setEgress(ingress).build();
109         LOG.trace("Transmitting packet: {}",input);
110         this.pktService.transmitPacket(input);
111     }
112
113     private InstanceIdentifier<Node> getNodePath(InstanceIdentifier<?> nodeInstanceId) {
114         return nodeInstanceId.firstIdentifierOf(Node.class);
115     }
116
117     private DHCP handleDhcpPacket(DHCP dhcpPkt, FlowCapableNodeConnector fcNc) {
118         LOG.debug("DHCP pkt rcvd {}", dhcpPkt);
119         byte msgType = dhcpPkt.getMsgType();
120         if (msgType == DHCPConstants.MSG_DECLINE) {
121             LOG.debug("DHCPDECLINE received");
122             return null;
123         } else if (msgType == DHCPConstants.MSG_RELEASE) {
124             LOG.debug("DHCPRELEASE received");
125             return null;
126         }
127
128         Port nPort = getNeutronPort(fcNc);
129         Subnet nSubnet = getNeutronSubnet(nPort);
130         DhcpInfo dhcpInfo = getDhcpInfo(nPort, nSubnet);
131         LOG.trace("NeutronPort: {} \n NeutronSubnet: {}, dhcpInfo{}",nPort, nSubnet, dhcpInfo);
132         DHCP reply = null;
133         if (dhcpInfo != null) {
134             if (msgType == DHCPConstants.MSG_DISCOVER) {
135                 reply = getReplyToDiscover(dhcpPkt, dhcpInfo);
136             } else if (msgType == DHCPConstants.MSG_REQUEST) {
137                 reply = getReplyToRequest(dhcpPkt, dhcpInfo);
138             }
139         }
140
141         return reply;
142     }
143
144     private DhcpInfo getDhcpInfo(Port nPort, Subnet nSubnet) {
145         DhcpInfo dhcpInfo = null;
146         if( (nPort != null) && (nSubnet != null) ) {
147             String clientIp = nPort.getFixedIps().get(0).getIpAddress().getIpv4Address().getValue();
148             String serverIp = nSubnet.getGatewayIp().getIpv4Address().getValue();
149             List<IpAddress> dnsServers = nSubnet.getDnsNameservers();
150             dhcpInfo = new DhcpInfo();
151             dhcpInfo.setClientIp(clientIp).setServerIp(serverIp)
152                 .setCidr(nSubnet.getCidr()).setHostRoutes(nSubnet.getHostRoutes())
153                 .setDnsServersIpAddrs(dnsServers).setGatewayIp(serverIp);
154         } else {
155             //FIXME: Delete this test code
156             LOG.error("TestOnly Code");
157             dhcpInfo = new DhcpInfo();
158             dhcpInfo.setClientIp("1.1.1.3").setServerIp("1.1.1.1")
159                 .setCidr("1.1.1.0/24").addDnsServer("1.1.1.1");
160             LOG.warn("Failed to get Subnet info for DHCP reply");
161         }
162         return dhcpInfo;
163     }
164
165     private Subnet getNeutronSubnet(Port nPort) {
166         return dhcpMgr.getNeutronSubnet(nPort);
167     }
168
169     private Port getNeutronPort(FlowCapableNodeConnector fcNc) {
170             return dhcpMgr.getNeutronPort(fcNc.getName());
171     }
172
173     private FlowCapableNodeConnector getFlowCapableNodeConnector(NodeConnectorRef inNcRef) {
174         InstanceIdentifier<NodeConnector> ncId = inNcRef.getValue().firstIdentifierOf(NodeConnector.class);
175         Optional<NodeConnector> nodeConnector = 
176                         MDSALDataStoreUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, ncId);
177         if(nodeConnector.isPresent()) {
178             NodeConnector nc = nodeConnector.get();
179             LOG.trace("Incoming pkt's NodeConnector: {}", nc);
180             FlowCapableNodeConnector fcnc = nc.getAugmentation(FlowCapableNodeConnector.class);
181             return fcnc;
182         }
183         return null;
184     }
185
186     private DHCP getDhcpPktIn(Ethernet ethPkt) {
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                     byte[] rawDhcpPayload = udpPkt.getRawPayload();
194                     DHCP reply = new DHCP();
195                     try {
196                         reply.deserialize(rawDhcpPayload, 0, rawDhcpPayload.length);
197                     } catch (PacketException e) {
198                         LOG.warn("Failed to deserialize DHCP pkt", e);
199                         return null;
200                     }
201                     return reply;
202                 }
203             }
204         }
205         return null;
206     }
207
208     DHCP getReplyToDiscover(DHCP dhcpPkt, DhcpInfo dhcpInfo) {
209         DHCP reply = new DHCP();
210         reply.setOp(DHCPConstants.BOOTREPLY);
211         reply.setHtype(dhcpPkt.getHtype());
212         reply.setHlen(dhcpPkt.getHlen());
213         reply.setHops((byte) 0);
214         reply.setXid(dhcpPkt.getXid());
215         reply.setSecs((short) 0);
216
217         reply.setYiaddr(dhcpInfo.getClientIp());
218         reply.setSiaddr(dhcpInfo.getServerIp());
219
220         reply.setFlags(dhcpPkt.getFlags());
221         reply.setGiaddr(dhcpPkt.getGiaddr());
222         reply.setChaddr(dhcpPkt.getChaddr());
223
224         reply.setMsgType(DHCPConstants.MSG_OFFER);
225         if(dhcpPkt.containsOption(DHCPConstants.OPT_PARAMETER_REQUEST_LIST)) {
226             setParameterListOptions(dhcpPkt, reply, dhcpInfo);
227         }
228         setCommonOptions(reply, dhcpInfo);
229         return reply;
230     }
231
232     DHCP getReplyToRequest(DHCP dhcpPkt, DhcpInfo dhcpInfo) {
233         boolean sendAck = false;
234         byte[] requestedIp = null;
235         DHCP reply = new DHCP();
236         reply.setOp(DHCPConstants.BOOTREPLY);
237         reply.setHtype(dhcpPkt.getHtype());
238         reply.setHlen(dhcpPkt.getHlen());
239         reply.setHops((byte) 0);
240         reply.setXid(dhcpPkt.getXid());
241         reply.setSecs((short) 0);
242
243         reply.setFlags(dhcpPkt.getFlags());
244         reply.setGiaddr(dhcpPkt.getGiaddr());
245         reply.setChaddr(dhcpPkt.getChaddr());
246         byte[] allocatedIp = DHCPUtils.strAddrToByteArray(dhcpInfo.getClientIp());
247         if(Arrays.equals(allocatedIp, dhcpPkt.getCiaddr())) {
248             //This means a renew request
249             sendAck = true;
250         } else {
251             requestedIp = dhcpPkt.getOptionBytes(DHCPConstants.OPT_REQUESTED_ADDRESS);
252             sendAck = Arrays.equals(allocatedIp, requestedIp);
253         }
254
255         if (sendAck) {
256             reply.setCiaddr(dhcpPkt.getCiaddr());
257             reply.setYiaddr(dhcpInfo.getClientIp());
258             reply.setSiaddr(dhcpInfo.getServerIp());
259             reply.setMsgType(DHCPConstants.MSG_ACK);
260             if(dhcpPkt.containsOption(DHCPConstants.OPT_PARAMETER_REQUEST_LIST)) {
261                 setParameterListOptions(dhcpPkt, reply, dhcpInfo);
262             }
263             setCommonOptions(reply, dhcpInfo);
264         }
265         else {
266             reply.setMsgType(DHCPConstants.MSG_NAK);
267         }
268         return reply;
269     }
270
271     protected byte[] getDhcpPacketOut(DHCP reply, Ethernet etherPkt, FlowCapableNodeConnector fcNc) {
272         if (reply == null) {
273             /*
274              * DECLINE or RELEASE don't result in reply packet
275              */
276             return null;
277         }
278         LOG.debug("Sending DHCP Pkt {}", reply);
279         // create UDP pkt
280         UDP udpPkt = new UDP();
281         byte[] rawPkt;
282         try {
283             rawPkt = reply.serialize();
284         } catch (PacketException e2) {
285             // TODO Auto-generated catch block
286             e2.printStackTrace();
287             return null;
288         }
289         udpPkt.setRawPayload(rawPkt);
290         udpPkt.setDestinationPort(DHCPMConstants.dhcpClientPort);
291         udpPkt.setSourcePort(DHCPMConstants.dhcpServerPort);
292         udpPkt.setLength((short) (rawPkt.length + 8));
293         //Create IP Pkt
294         IPv4 ip4Reply = new IPv4();
295         try {
296             rawPkt = udpPkt.serialize();
297         } catch (PacketException e) {
298             // TODO Auto-generated catch block
299             e.printStackTrace();
300             return null;
301         }
302         short checkSum = 0;
303         if(this.computeUdpChecksum) {
304          checkSum = computeChecksum(rawPkt, reply.getSiaddr(),
305                 NetUtils.intToByteArray4(DHCPMConstants.BCAST_IP));
306         }
307         udpPkt.setChecksum(checkSum);
308         ip4Reply.setPayload(udpPkt);
309         ip4Reply.setProtocol(IPProtocols.UDP.byteValue());
310         ip4Reply.setSourceAddress(reply.getSiaddrAsInetAddr());
311         ip4Reply.setDestinationAddress(DHCPMConstants.BCAST_IP);
312         ip4Reply.setTotalLength((short) (rawPkt.length+20));
313         ip4Reply.setTtl((byte) 32);
314         // create Ethernet Frame
315         Ethernet ether = new Ethernet();
316         //TODO: 
317         ether.setSourceMACAddress(getServerMacAddress(fcNc));
318         ether.setDestinationMACAddress(etherPkt.getSourceMACAddress());
319         ether.setEtherType(EtherTypes.IPv4.shortValue());
320         ether.setPayload(ip4Reply);
321         try {
322             rawPkt = ether.serialize();
323         } catch (PacketException e) {
324             LOG.warn("Failed to serialize ethernet reply",e);
325             return null;
326         }
327         return rawPkt;
328     }
329
330     private byte[] getServerMacAddress(FlowCapableNodeConnector fcNc) {
331         // Should we return ControllerMac instead?
332         MacAddress macAddress = fcNc.getHardwareAddress();
333         return DHCPUtils.strMacAddrtoByteArray(macAddress.getValue());
334     }
335
336     public short computeChecksum(byte[] inData, byte[] srcAddr, byte[] destAddr) {
337         short checkSum = (short) 0;
338         int sum = 0, carry = 0;
339         int wordData, i;
340
341         for (i = 0; i < inData.length - 1; i = i + 2) {
342             // Skip, if the current bytes are checkSum bytes
343             wordData = ((inData[i] << 8) & 0xFF00) + (inData[i + 1] & 0xFF);
344             sum = sum + wordData;
345         }
346
347         if (i < inData.length) {
348             wordData = ((inData[i] << 8) & 0xFF00) + (0 & 0xFF);
349             sum = sum + wordData;
350         }
351
352         for (i = 0; i < 4; i = i + 2) {
353             wordData = ((srcAddr[i] << 8) & 0xFF00) + (srcAddr[i + 1] & 0xFF);
354             sum = sum + wordData;
355         }
356
357         for (i = 0; i < 4; i = i + 2) {
358             wordData = ((destAddr[i] << 8) & 0xFF00) + (destAddr[i + 1] & 0xFF);
359             sum = sum + wordData;
360         }
361         sum = sum + 17 + inData.length;
362
363         while((sum >> 16) != 0) {
364             carry = (sum >> 16);
365             sum = (sum & 0xFFFF)+ carry;
366         }
367         checkSum = (short) ~((short) sum & 0xFFFF);
368         if(checkSum == 0) {
369             checkSum = (short)0xffff;
370         }
371         return checkSum;
372     }
373
374     private void setCommonOptions(DHCP pkt, DhcpInfo dhcpInfo) {
375         pkt.setOptionInt(DHCPConstants.OPT_LEASE_TIME, dhcpMgr.getDhcpLeaseTime());
376         if (dhcpMgr.getDhcpDefDomain() != null) {
377             pkt.setOptionString(DHCPConstants.OPT_DOMAIN_NAME, dhcpMgr.getDhcpDefDomain());
378         }
379         if(dhcpMgr.getDhcpLeaseTime() > 0) {
380             pkt.setOptionInt(DHCPConstants.OPT_REBINDING_TIME, dhcpMgr.getDhcpRebindingTime());
381             pkt.setOptionInt(DHCPConstants.OPT_RENEWAL_TIME, dhcpMgr.getDhcpRenewalTime());
382         }
383         SubnetUtils util = null;
384         SubnetInfo info = null;
385         util = new SubnetUtils(dhcpInfo.getCidr());
386         info = util.getInfo();
387         String gwIp = dhcpInfo.getGatewayIp();
388         List<String> dnServers = dhcpInfo.getDnsServers();
389         try {
390             /*
391              * setParameterListOptions may have initialized some of these
392              * options to maintain order. If we can't fill them, unset to avoid
393              * sending wrong information in reply.
394              */
395             if (gwIp != null) {
396                 pkt.setOptionInetAddr(DHCPConstants.OPT_SERVER_IDENTIFIER, gwIp);
397                 pkt.setOptionInetAddr(DHCPConstants.OPT_ROUTERS, gwIp);
398             } else {
399                 pkt.unsetOption(DHCPConstants.OPT_SERVER_IDENTIFIER);
400                 pkt.unsetOption(DHCPConstants.OPT_ROUTERS);
401             }
402             if (info != null) {
403                 pkt.setOptionInetAddr(DHCPConstants.OPT_SUBNET_MASK, info.getNetmask());
404                 pkt.setOptionInetAddr(DHCPConstants.OPT_BROADCAST_ADDRESS, info.getBroadcastAddress());
405             } else {
406                 pkt.unsetOption(DHCPConstants.OPT_SUBNET_MASK);
407                 pkt.unsetOption(DHCPConstants.OPT_BROADCAST_ADDRESS);
408             }
409             if ((dnServers != null) && (dnServers.size() > 0)) {
410                 pkt.setOptionStrAddrs(DHCPConstants.OPT_DOMAIN_NAME_SERVERS, dnServers);
411             } else {
412                 pkt.unsetOption(DHCPConstants.OPT_DOMAIN_NAME_SERVERS);
413             }
414         } catch (UnknownHostException e) {
415             // TODO Auto-generated catch block
416             e.printStackTrace();
417         }
418     }
419
420     private void setParameterListOptions(DHCP req, DHCP reply, DhcpInfo dhcpInfo) {
421         byte[] paramList = req.getOptionBytes(DHCPConstants.OPT_PARAMETER_REQUEST_LIST);
422         for(int i = 0; i < paramList.length; i++) {
423             switch (paramList[i]) {
424             case DHCPConstants.OPT_SUBNET_MASK:
425             case DHCPConstants.OPT_ROUTERS:
426             case DHCPConstants.OPT_SERVER_IDENTIFIER:
427             case DHCPConstants.OPT_DOMAIN_NAME_SERVERS:
428             case DHCPConstants.OPT_BROADCAST_ADDRESS:
429             case DHCPConstants.OPT_LEASE_TIME:
430             case DHCPConstants.OPT_RENEWAL_TIME:
431             case DHCPConstants.OPT_REBINDING_TIME:
432                 /* These values will be filled in setCommonOptions
433                  * Setting these just to preserve order as
434                  * specified in PARAMETER_REQUEST_LIST.
435                  */
436                 reply.setOptionInt(paramList[i], 0);
437                 break;
438             case DHCPConstants.OPT_DOMAIN_NAME:
439                 reply.setOptionString(paramList[i], " ");
440                 break;
441             case DHCPConstants.OPT_CLASSLESS_ROUTE:
442                 setOptionClasslessRoute(reply, dhcpInfo);
443                 break;
444             default:
445                 LOG.debug("DHCP Option code {} not supported yet", paramList[i]);
446                 break;
447             }
448         }
449     }
450     private void setOptionClasslessRoute(DHCP reply, DhcpInfo dhcpInfo) {
451         List<HostRoutes> hostRoutes = dhcpInfo.getHostRoutes();
452         if(hostRoutes == null) {
453             //we can't set this option, so return
454             return;
455         }
456         ByteArrayOutputStream result = new ByteArrayOutputStream();
457         Iterator<HostRoutes> iter = hostRoutes.iterator();
458         while(iter.hasNext()) {
459             HostRoutes hostRoute = iter.next();
460             String router = hostRoute.getNexthop().toString();
461             String dest = hostRoute.getDestination().toString();
462             try {
463                 result.write(convertToClasslessRouteOption(dest, router));
464             } catch (IOException | NullPointerException e) {
465                 LOG.debug("Exception {}",e.getMessage());
466             }
467         }
468         if (result.size() > 0) {
469             reply.setOptionBytes(DHCPConstants.OPT_CLASSLESS_ROUTE , result.toByteArray());
470         }
471     }
472
473     protected byte[] convertToClasslessRouteOption(String dest, String router) {
474         ByteArrayOutputStream bArr = new ByteArrayOutputStream();
475         if((dest == null ||
476                 router == null)) {
477             return null;
478         }
479
480         //get prefix
481         Short prefix = null;
482         String[] parts = dest.split("/");
483         if (parts.length < 2) {
484             prefix = new Short((short)0);
485         } else {
486             prefix = Short.valueOf(parts[1]);
487         }
488
489         bArr.write(prefix.byteValue());
490         SubnetUtils util = new SubnetUtils(dest);
491         SubnetInfo info = util.getInfo();
492         String strNetAddr = info.getNetworkAddress();
493         try {
494             byte[] netAddr = InetAddress.getByName(strNetAddr).getAddress();
495           //Strip any trailing 0s from netAddr
496             for(int i = 0; i < netAddr.length;i++) {
497                 if(netAddr[i] != 0) {
498                     bArr.write(netAddr,i,1);
499                 }
500             }
501             bArr.write(InetAddress.getByName(router).getAddress());
502         } catch (IOException e) {
503             return null;
504         }
505         return bArr.toByteArray();
506     }
507
508     private boolean isPktInReasonSendtoCtrl(Class<? extends PacketInReason> pktInReason) {
509         return (pktInReason == SendToController.class);
510     }
511
512     @Override
513     public void close() throws Exception {
514         // TODO Auto-generated method stub
515     }
516
517     public void setPacketProcessingService(PacketProcessingService packetService) {
518         this.pktService = packetService;
519     }
520
521 }