Netvirt troubleshooting improvements
[netvirt.git] / ipv6service / impl / src / main / java / org / opendaylight / netvirt / ipv6service / Ipv6PktHandler.java
1 /*
2  * Copyright (c) 2016 Red Hat, Inc. 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.ipv6service;
9
10 import com.google.common.util.concurrent.ThreadFactoryBuilder;
11 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
12 import java.net.InetAddress;
13 import java.net.UnknownHostException;
14 import java.nio.ByteBuffer;
15 import java.util.Arrays;
16 import java.util.concurrent.ExecutorService;
17 import java.util.concurrent.Executors;
18 import java.util.concurrent.ThreadFactory;
19 import java.util.concurrent.atomic.AtomicLong;
20 import javax.annotation.PreDestroy;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.opendaylight.genius.ipv6util.api.Icmpv6Type;
24 import org.opendaylight.genius.ipv6util.api.Ipv6Constants;
25 import org.opendaylight.genius.ipv6util.api.Ipv6Constants.Ipv6RouterAdvertisementType;
26 import org.opendaylight.genius.ipv6util.api.Ipv6Util;
27 import org.opendaylight.genius.ipv6util.api.decoders.Ipv6NaDecoder;
28 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
29 import org.opendaylight.genius.mdsalutil.NwConstants;
30 import org.opendaylight.genius.mdsalutil.packet.IPProtocols;
31 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
32 import org.opendaylight.netvirt.ipv6service.api.IIpv6PacketListener;
33 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
34 import org.opendaylight.openflowplugin.libraries.liblldp.BitBufferHelper;
35 import org.opendaylight.openflowplugin.libraries.liblldp.BufferException;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.Ipv6Header;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.NeighborAdvertisePacket;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.NeighborAdvertisePacketBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.NeighborSolicitationPacket;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.NeighborSolicitationPacketBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.RouterSolicitationPacket;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.packet.rev160620.RouterSolicitationPacketBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.PacketMetadata;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.ipv6.nd.util.rev170210.PacketMetadataBuilder;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
55 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
56 import org.opendaylight.yangtools.yang.common.Uint64;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59
60 @Singleton
61 public class Ipv6PktHandler implements AutoCloseable, PacketProcessingListener {
62     private static final Logger LOG = LoggerFactory.getLogger(Ipv6PktHandler.class);
63     private final AtomicLong pktProccessedCounter = new AtomicLong(0);
64     private final PacketProcessingService pktService;
65     private final IfMgr ifMgr;
66     private final IIpv6PacketListener ipv6PktListener;
67
68     private final ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
69             .setNameFormat("ipv6-pkt-%d").build();
70
71     private final ExecutorService packetProcessor = Executors.newCachedThreadPool(namedThreadFactory);
72
73     @Inject
74     public Ipv6PktHandler(PacketProcessingService pktService, IfMgr ifMgr, IIpv6PacketListener ipv6PktListener) {
75         this.pktService = pktService;
76         this.ifMgr = ifMgr;
77         this.ipv6PktListener = ipv6PktListener;
78     }
79
80     @Override
81     public void onPacketReceived(PacketReceived packetReceived) {
82         int     ethType;
83         int     v6NxtHdr;
84
85         if (packetReceived == null) {
86             LOG.debug("Received null packet. Returning without any processing");
87             return;
88         }
89
90         byte[] data = packetReceived.getPayload();
91         if (data.length <= 0) {
92             LOG.debug("Received packet with invalid length {}", data.length);
93             return;
94         }
95         try {
96             ethType = BitBufferHelper.getInt(BitBufferHelper.getBits(data, Ipv6Constants.ETHTYPE_START,
97                     Ipv6Constants.TWO_BYTES));
98             if (ethType == NwConstants.ETHTYPE_IPV6) {
99                 v6NxtHdr = BitBufferHelper.getByte(BitBufferHelper.getBits(data,
100                         Ipv6Constants.IP_V6_HDR_START + Ipv6Constants.IP_V6_NEXT_HDR, Ipv6Constants.ONE_BYTE));
101                 if (v6NxtHdr == IPProtocols.IPV6ICMP.intValue()) {
102                     int icmpv6Type = BitBufferHelper.getInt(BitBufferHelper.getBits(data,
103                             Ipv6Constants.ICMPV6_HDR_START, Ipv6Constants.ONE_BYTE));
104                     if (isOfInterest(icmpv6Type)) {
105                         packetProcessor.execute(new PacketHandler(icmpv6Type, packetReceived));
106                     }
107                 } else {
108                     LOG.debug("IPv6 Pdu received on port {} with next-header {} ",
109                             packetReceived.getIngress(), v6NxtHdr);
110                 }
111             } else {
112                 return;
113             }
114         } catch (BufferException e) {
115             LOG.warn("Failed to decode packet: {}", e.getMessage());
116             return;
117         }
118     }
119
120     private boolean isOfInterest(int icmpv6Type) {
121         return icmpv6Type == Icmpv6Type.ROUTER_SOLICITATION.getValue()
122                 || icmpv6Type == Icmpv6Type.NEIGHBOR_SOLICITATION.getValue()
123                 || icmpv6Type == Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue();
124     }
125
126     public long getPacketProcessedCounter() {
127         return pktProccessedCounter.get();
128     }
129
130     private class PacketHandler implements Runnable {
131         int type;
132         PacketReceived packet;
133
134         PacketHandler(int icmpv6Type, PacketReceived packet) {
135             this.type = icmpv6Type;
136             this.packet = packet;
137         }
138
139         @Override
140         public void run() {
141             if (type == Icmpv6Type.NEIGHBOR_SOLICITATION.getValue()) {
142                 LOG.info("Received Neighbor Solicitation request");
143                 processNeighborSolicitationRequest();
144             } else if (type == Icmpv6Type.ROUTER_SOLICITATION.getValue()) {
145                 LOG.info("Received Router Solicitation request");
146                 processRouterSolicitationRequest();
147             } else if (type == Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue()) {
148                 LOG.trace("Received Neighbor Advertisement packet");
149                 processNeighborAdvertisementPacket();
150             }
151         }
152
153         private void processNeighborSolicitationRequest() {
154             byte[] data = packet.getPayload();
155             NeighborSolicitationPacket nsPdu = deserializeNSPacket(data);
156             Ipv6Header ipv6Header = nsPdu;
157             if (Ipv6Util.validateChecksum(data, ipv6Header, nsPdu.getIcmp6Chksum().toJava()) == false) {
158                 pktProccessedCounter.incrementAndGet();
159                 LOG.warn("Received Neighbor Solicitation with invalid checksum on {}. Ignoring the packet.",
160                         packet.getIngress());
161                 return;
162             }
163
164             Uint64 metadata = packet.getMatch().getMetadata().getMetadata();
165             long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
166             String interfaceName = ifMgr.getInterfaceNameFromTag(portTag);
167             VirtualPort port = ifMgr.obtainV6Interface(new Uuid(interfaceName));
168             if (port == null) {
169                 pktProccessedCounter.incrementAndGet();
170                 LOG.warn("Port {} not found, skipping.", interfaceName);
171                 return;
172             }
173
174             VirtualPort routerPort = ifMgr.getRouterV6InterfaceForNetwork(port.getNetworkID());
175             if (routerPort == null) {
176                 pktProccessedCounter.incrementAndGet();
177                 LOG.warn("Port for network Id {} is not associated to a Router, skipping NS request.",
178                         port.getNetworkID());
179                 return;
180             }
181
182             if (!routerPort.getIpv6Addresses().contains(nsPdu.getTargetIpAddress())) {
183                 pktProccessedCounter.incrementAndGet();
184                 LOG.warn("No Router interface with address {} on the network {}, skipping NS request.",
185                         nsPdu.getTargetIpAddress(), port.getNetworkID());
186                 return;
187             }
188
189             //formulate the NA response
190             NeighborAdvertisePacketBuilder naPacket = new NeighborAdvertisePacketBuilder();
191             updateNAResponse(nsPdu, routerPort, naPacket);
192             // serialize the response packet
193             byte[] txPayload = fillNeighborAdvertisementPacket(naPacket.build());
194             InstanceIdentifier<Node> outNode = packet.getIngress().getValue().firstIdentifierOf(Node.class);
195             TransmitPacketInput input = new TransmitPacketInputBuilder().setPayload(txPayload)
196                     .setNode(new NodeRef(outNode))
197                     .setEgress(packet.getIngress()).build();
198             // Tx the packet out of the controller.
199             if (pktService != null) {
200                 LOG.debug("Transmitting the Neighbor Advt packet out on {}", packet.getIngress());
201                 JdkFutures.addErrorLogging(pktService.transmitPacket(input), LOG, "transmitPacket");
202                 pktProccessedCounter.incrementAndGet();
203             }
204         }
205
206         private NeighborSolicitationPacket deserializeNSPacket(byte[] data) {
207             NeighborSolicitationPacketBuilder nsPdu = new NeighborSolicitationPacketBuilder();
208             int bitOffset = 0;
209
210             try {
211                 nsPdu.setDestinationMac(new MacAddress(
212                         Ipv6Util.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
213                 bitOffset = bitOffset + 48;
214                 nsPdu.setSourceMac(new MacAddress(
215                         Ipv6Util.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
216                 bitOffset = bitOffset + 48;
217                 nsPdu.setEthertype(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
218
219                 bitOffset = Ipv6Constants.IP_V6_HDR_START;
220                 nsPdu.setVersion(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 4)));
221                 bitOffset = bitOffset + 4;
222                 nsPdu.setFlowLabel(BitBufferHelper.getLong(BitBufferHelper.getBits(data, bitOffset, 28)));
223                 bitOffset = bitOffset + 28;
224                 nsPdu.setIpv6Length(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
225                 bitOffset = bitOffset + 16;
226                 nsPdu.setNextHeader(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
227                 bitOffset = bitOffset + 8;
228                 nsPdu.setHopLimit(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
229                 bitOffset = bitOffset + 8;
230                 nsPdu.setSourceIpv6(Ipv6Address.getDefaultInstance(
231                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
232                 bitOffset = bitOffset + 128;
233                 nsPdu.setDestinationIpv6(Ipv6Address.getDefaultInstance(
234                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
235                 bitOffset = bitOffset + 128;
236
237                 nsPdu.setIcmp6Type(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
238                 bitOffset = bitOffset + 8;
239                 nsPdu.setIcmp6Code(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
240                 bitOffset = bitOffset + 8;
241                 nsPdu.setIcmp6Chksum(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
242                 bitOffset = bitOffset + 16;
243                 nsPdu.setReserved(Long.valueOf(0));
244                 bitOffset = bitOffset + 32;
245                 nsPdu.setTargetIpAddress(Ipv6Address.getDefaultInstance(
246                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
247             } catch (BufferException | UnknownHostException  e) {
248                 LOG.warn("Exception obtained when deserializing NS packet", e);
249             }
250             return nsPdu.build();
251         }
252
253         private void updateNAResponse(NeighborSolicitationPacket pdu,
254                                       VirtualPort port, NeighborAdvertisePacketBuilder naPacket) {
255             long flag = 0;
256             if (!Ipv6ServiceUtils.UNSPECIFIED_ADDR.equals(pdu.getSourceIpv6())) {
257                 naPacket.setDestinationIpv6(pdu.getSourceIpv6());
258                 flag = 0xE0; // Set Router, Solicited and Override Flag.
259             } else {
260                 naPacket.setDestinationIpv6(Ipv6ServiceUtils.ALL_NODES_MCAST_ADDR);
261                 flag = 0xA0; // Set Router and Override Flag.
262             }
263             naPacket.setDestinationMac(pdu.getSourceMac());
264             naPacket.setEthertype(pdu.getEthertype());
265             naPacket.setSourceIpv6(pdu.getTargetIpAddress());
266             naPacket.setSourceMac(new MacAddress(port.getMacAddress()));
267             naPacket.setHopLimit(Ipv6Constants.ICMP_V6_MAX_HOP_LIMIT);
268             naPacket.setIcmp6Type(Icmpv6Type.NEIGHBOR_ADVERTISEMENT.getValue());
269             naPacket.setIcmp6Code(pdu.getIcmp6Code());
270             flag = flag << 24;
271             naPacket.setFlags(flag);
272             naPacket.setFlowLabel(pdu.getFlowLabel());
273             naPacket.setIpv6Length(32);
274             naPacket.setNextHeader(pdu.getNextHeader());
275             naPacket.setOptionType(Ipv6Constants.ICMP_V6_OPTION_TARGET_LLA);
276             naPacket.setTargetAddrLength((short)1);
277             naPacket.setTargetAddress(pdu.getTargetIpAddress());
278             naPacket.setTargetLlAddress(new MacAddress(port.getMacAddress()));
279             naPacket.setVersion(pdu.getVersion());
280             naPacket.setIcmp6Chksum(0);
281             return;
282         }
283
284         private byte[] icmp6NAPayloadtoByte(NeighborAdvertisePacket pdu) {
285             byte[] data = new byte[36];
286             Arrays.fill(data, (byte)0);
287
288             ByteBuffer buf = ByteBuffer.wrap(data);
289             buf.put((byte)pdu.getIcmp6Type().shortValue());
290             buf.put((byte)pdu.getIcmp6Code().shortValue());
291             buf.putShort((short)pdu.getIcmp6Chksum().intValue());
292             buf.putInt((int)pdu.getFlags().longValue());
293             try {
294                 byte[] address = null;
295                 address = InetAddress.getByName(pdu.getTargetAddress().getValue()).getAddress();
296                 buf.put(address);
297             } catch (UnknownHostException e) {
298                 LOG.error("Serializing NA target address failed", e);
299             }
300             buf.put((byte)pdu.getOptionType().shortValue());
301             buf.put((byte)pdu.getTargetAddrLength().shortValue());
302             buf.put(Ipv6Util.bytesFromHexString(pdu.getTargetLlAddress().getValue()));
303             return data;
304         }
305
306         private byte[] fillNeighborAdvertisementPacket(NeighborAdvertisePacket pdu) {
307             ByteBuffer buf = ByteBuffer.allocate(Ipv6Constants.ICMPV6_OFFSET + pdu.getIpv6Length().toJava());
308
309             buf.put(Ipv6Util.convertEthernetHeaderToByte(pdu), 0, 14);
310             buf.put(Ipv6Util.convertIpv6HeaderToByte(pdu), 0, 40);
311             buf.put(icmp6NAPayloadtoByte(pdu), 0, pdu.getIpv6Length().toJava());
312             int checksum = Ipv6Util.calculateIcmpv6Checksum(buf.array(), pdu);
313             buf.putShort(Ipv6Constants.ICMPV6_OFFSET + 2, (short)checksum);
314             return buf.array();
315         }
316
317         private void processRouterSolicitationRequest() {
318             byte[] data = packet.getPayload();
319             RouterSolicitationPacket rsPdu = deserializeRSPacket(data);
320             Ipv6Header ipv6Header = rsPdu;
321             if (Ipv6Util.validateChecksum(data, ipv6Header, rsPdu.getIcmp6Chksum().toJava()) == false) {
322                 pktProccessedCounter.incrementAndGet();
323                 LOG.warn("Received RS packet with invalid checksum on {}. Ignoring the packet.",
324                         packet.getIngress());
325                 return;
326             }
327
328             Uint64 metadata = packet.getMatch().getMetadata().getMetadata();
329             long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
330             String interfaceName = ifMgr.getInterfaceNameFromTag(portTag);
331             Uuid portId = new Uuid(interfaceName);
332             VirtualPort port = ifMgr.obtainV6Interface(portId);
333             if (port == null) {
334                 pktProccessedCounter.incrementAndGet();
335                 LOG.info("Port {} not found, skipping.", interfaceName);
336                 return;
337             }
338
339             VirtualPort routerPort = ifMgr.getRouterV6InterfaceForNetwork(port.getNetworkID());
340             if (routerPort == null) {
341                 pktProccessedCounter.incrementAndGet();
342                 LOG.warn("Port for networkId {} is not associated to a Router, skipping.", port.getNetworkID());
343                 return;
344             }
345             Ipv6RouterAdvt ipv6RouterAdvert = new Ipv6RouterAdvt(pktService, ifMgr);
346             LOG.debug("Sending Solicited Router Advertisement for the port {} belongs to the network {}", port,
347                     port.getNetworkID());
348             ipv6RouterAdvert.transmitRtrAdvertisement(Ipv6RouterAdvertisementType.SOLICITED_ADVERTISEMENT,
349                     routerPort, 0, rsPdu, port.getDpId(), port.getIntfUUID());
350             pktProccessedCounter.incrementAndGet();
351         }
352
353         private RouterSolicitationPacket deserializeRSPacket(byte[] data) {
354             RouterSolicitationPacketBuilder rsPdu = new RouterSolicitationPacketBuilder();
355             int bitOffset = 0;
356
357             try {
358                 rsPdu.setDestinationMac(new MacAddress(
359                         Ipv6Util.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
360                 bitOffset = bitOffset + 48;
361                 rsPdu.setSourceMac(new MacAddress(
362                         Ipv6Util.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
363                 bitOffset = bitOffset + 48;
364                 rsPdu.setEthertype(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
365
366                 bitOffset = Ipv6Constants.IP_V6_HDR_START;
367                 rsPdu.setVersion(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 4)));
368                 bitOffset = bitOffset + 4;
369                 rsPdu.setFlowLabel(BitBufferHelper.getLong(BitBufferHelper.getBits(data, bitOffset, 28)));
370                 bitOffset = bitOffset + 28;
371
372                 rsPdu.setIpv6Length(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
373                 bitOffset = bitOffset + 16;
374                 rsPdu.setNextHeader(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
375                 bitOffset = bitOffset + 8;
376                 rsPdu.setHopLimit(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
377                 bitOffset = bitOffset + 8;
378                 rsPdu.setSourceIpv6(Ipv6Address.getDefaultInstance(
379                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
380                 bitOffset = bitOffset + 128;
381                 rsPdu.setDestinationIpv6(Ipv6Address.getDefaultInstance(
382                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
383                 bitOffset = bitOffset + 128;
384
385                 rsPdu.setIcmp6Type(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
386                 bitOffset = bitOffset + 8;
387                 rsPdu.setIcmp6Code(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
388                 bitOffset = bitOffset + 8;
389                 rsPdu.setIcmp6Chksum(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
390                 bitOffset = bitOffset + 16;
391                 rsPdu.setReserved(Long.valueOf(0));
392                 bitOffset = bitOffset + 32;
393
394                 if (rsPdu.getIpv6Length().toJava() > Ipv6Constants.ICMPV6_RA_LENGTH_WO_OPTIONS) {
395                     rsPdu.setOptionType(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
396                     bitOffset = bitOffset + 8;
397                     rsPdu.setSourceAddrLength(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
398                     bitOffset = bitOffset + 8;
399                     if (rsPdu.getOptionType().shortValue() == Ipv6Constants.ICMP_V6_OPTION_SOURCE_LLA) {
400                         rsPdu.setSourceLlAddress(new MacAddress(
401                                 Ipv6Util.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
402                     }
403                 }
404             } catch (BufferException | UnknownHostException e) {
405                 LOG.warn("Exception obtained when deserializing Router Solicitation packet", e);
406             }
407             return rsPdu.build();
408         }
409
410         private void processNeighborAdvertisementPacket() {
411             byte[] data = packet.getPayload();
412             NeighborAdvertisePacket naPdu;
413             try {
414                 naPdu = new Ipv6NaDecoder(data).decode();
415             } catch (UnknownHostException | BufferException e) {
416                 LOG.warn("Exception occured during deserializing NA packet", e);
417                 return;
418             }
419             Ipv6Header ipv6Header = naPdu;
420             if (Ipv6Util.validateChecksum(data, ipv6Header, naPdu.getIcmp6Chksum().toJava()) == false) {
421                 pktProccessedCounter.incrementAndGet();
422                 LOG.warn("Received Neighbor Advertisement with invalid checksum on {}. Ignoring the packet.",
423                         packet.getIngress());
424                 return;
425             }
426
427             short tableId = packet.getTableId().getValue().toJava();
428             Uint64 metadata = packet.getMatch().getMetadata().getMetadata();
429             long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
430             String interfaceName = ifMgr.getInterfaceNameFromTag(portTag);
431
432             NeighborAdvertisePacket naPacket = new NeighborAdvertisePacketBuilder(naPdu)
433                     .addAugmentation(PacketMetadata.class, new PacketMetadataBuilder().setOfTableId((long) tableId)
434                             .setMetadata(metadata).setInterface(interfaceName).build())
435                     .build();
436             fireNaNotification(naPacket);
437         }
438     }
439
440     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
441             justification = "https://github.com/spotbugs/spotbugs/issues/811")
442     private void fireNaNotification(NeighborAdvertisePacket naPacket) {
443         ipv6PktListener.onNaReceived(naPacket);
444     }
445
446     @Override
447     @PreDestroy
448     public void close() {
449         packetProcessor.shutdown();
450     }
451 }