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