Merge "Fix Sonar (soon Checkstyle) constant name"
[netvirt.git] / vpnservice / 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 java.math.BigInteger;
11 import java.net.InetAddress;
12 import java.net.UnknownHostException;
13 import java.nio.ByteBuffer;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.List;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.Executors;
19 import org.opendaylight.controller.liblldp.BitBufferHelper;
20 import org.opendaylight.controller.liblldp.BufferException;
21 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
22 import org.opendaylight.netvirt.ipv6service.utils.Ipv6Constants;
23 import org.opendaylight.netvirt.ipv6service.utils.Ipv6ServiceUtils;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IetfInetUtil;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Prefix;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.EthernetHeader;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.Ipv6Header;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.NeighborAdvertisePacket;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.NeighborAdvertisePacketBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.NeighborSolicitationPacket;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.NeighborSolicitationPacketBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterAdvertisementPacket;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterAdvertisementPacketBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterSolicitationPacket;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.RouterSolicitationPacketBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.router.advertisement.packet.PrefixList;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.router.advertisement.packet.PrefixListBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInput;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 public class Ipv6PktHandler implements AutoCloseable, PacketProcessingListener {
54     private static final Logger LOG = LoggerFactory.getLogger(Ipv6PktHandler.class);
55     private long pktProccessedCounter = 0;
56     private PacketProcessingService pktService;
57     private IfMgr ifMgr;
58     private Ipv6ServiceUtils ipv6Utils;
59     private final ExecutorService packetProcessor = Executors.newCachedThreadPool();
60
61     public Ipv6PktHandler() {
62         this.ipv6Utils = Ipv6ServiceUtils.getInstance();
63     }
64
65     public void setPacketProcessingService(PacketProcessingService packetService) {
66         this.pktService = packetService;
67     }
68
69     public void setIfMgrInstance(IfMgr instance) {
70         this.ifMgr = instance;
71     }
72
73     @Override
74     public void onPacketReceived(PacketReceived packetReceived) {
75         int     ethType;
76         int     v6NxtHdr;
77
78         if (packetReceived == null) {
79             LOG.debug("Received null packet. Returning without any processing");
80             return;
81         }
82
83         byte[] data = packetReceived.getPayload();
84         if (data.length <= 0) {
85             LOG.debug("Received packet with invalid length {}", data.length);
86             return;
87         }
88         try {
89             ethType = BitBufferHelper.getInt(BitBufferHelper.getBits(data, Ipv6Constants.ETHTYPE_START,
90                     Ipv6Constants.TWO_BYTES));
91             if (ethType == Ipv6Constants.IP_V6_ETHTYPE) {
92                 v6NxtHdr = BitBufferHelper.getByte(BitBufferHelper.getBits(data,
93                         (Ipv6Constants.IP_V6_HDR_START + Ipv6Constants.IP_V6_NEXT_HDR), Ipv6Constants.ONE_BYTE));
94                 if (v6NxtHdr == Ipv6Constants.ICMP_V6_TYPE) {
95                     int icmpv6Type = BitBufferHelper.getInt(BitBufferHelper.getBits(data,
96                             Ipv6Constants.ICMPV6_HDR_START, Ipv6Constants.ONE_BYTE));
97                     if ((icmpv6Type == Ipv6Constants.ICMP_V6_RS_CODE)
98                             || (icmpv6Type == Ipv6Constants.ICMP_V6_NS_CODE)) {
99                         packetProcessor.submit(new PacketHandler(icmpv6Type, packetReceived));
100                     }
101                 } else {
102                     LOG.debug("IPv6 Pdu received on port {} with next-header {} ",
103                             packetReceived.getIngress(), v6NxtHdr);
104                 }
105             } else {
106                 return;
107             }
108         } catch (BufferException e) {
109             LOG.warn("Failed to decode packet: {}", e.getMessage());
110             return;
111         }
112     }
113
114     public long getPacketProcessedCounter() {
115         return pktProccessedCounter;
116     }
117
118     private class PacketHandler implements Runnable {
119         int type;
120         PacketReceived packet;
121
122         PacketHandler(int icmpv6Type, PacketReceived packet) {
123             this.type = icmpv6Type;
124             this.packet = packet;
125         }
126
127         @Override
128         public void run() {
129             if (type == Ipv6Constants.ICMP_V6_NS_CODE) {
130                 LOG.info("Received Neighbor Solicitation request");
131                 processNeighborSolicitationRequest();
132             } else if (type == Ipv6Constants.ICMP_V6_RS_CODE) {
133                 LOG.info("Received Router Solicitation request");
134                 processRouterSolicitationRequest();
135             }
136         }
137
138         private void processNeighborSolicitationRequest() {
139             byte[] data = packet.getPayload();
140             NeighborSolicitationPacket nsPdu = deserializeNSPacket(data);
141             Ipv6Header ipv6Header = (Ipv6Header) nsPdu;
142             if (ipv6Utils.validateChecksum(data, ipv6Header, nsPdu.getIcmp6Chksum()) == false) {
143                 pktProccessedCounter++;
144                 LOG.warn("Received Neighbor Solicitation with invalid checksum on {}. Ignoring the packet.",
145                         packet.getIngress());
146                 return;
147             }
148
149             BigInteger metadata = packet.getMatch().getMetadata().getMetadata();
150             long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
151             String interfaceName = ifMgr.getInterfaceNameFromTag(portTag);
152             VirtualPort port = ifMgr.obtainV6Interface(new Uuid(interfaceName));
153             if (port == null) {
154                 pktProccessedCounter++;
155                 LOG.warn("Port {} not found, skipping.", port);
156                 return;
157             }
158
159             VirtualPort routerPort = ifMgr.getRouterV6InterfaceForNetwork(port.getNetworkID());
160             if (routerPort == null) {
161                 pktProccessedCounter++;
162                 LOG.warn("Port {} is not associated to a Router, skipping NS request.", routerPort);
163                 return;
164             }
165
166             if (!routerPort.getIpv6Addresses().contains(nsPdu.getTargetIpAddress())) {
167                 pktProccessedCounter++;
168                 LOG.warn("No Router interface with address {} on the network {}, skipping NS request.",
169                         nsPdu.getTargetIpAddress(), port.getNetworkID());
170                 return;
171             }
172
173             //formulate the NA response
174             NeighborAdvertisePacketBuilder naPacket = new NeighborAdvertisePacketBuilder();
175             updateNAResponse(nsPdu, routerPort, naPacket);
176             // serialize the response packet
177             byte[] txPayload = fillNeighborAdvertisementPacket(naPacket.build());
178             InstanceIdentifier<Node> outNode = packet.getIngress().getValue().firstIdentifierOf(Node.class);
179             TransmitPacketInput input = new TransmitPacketInputBuilder().setPayload(txPayload)
180                     .setNode(new NodeRef(outNode))
181                     .setEgress(packet.getIngress()).build();
182             // Tx the packet out of the controller.
183             if (pktService != null) {
184                 LOG.debug("Transmitting the Neighbor Advt packet out on {}", packet.getIngress());
185                 pktService.transmitPacket(input);
186                 pktProccessedCounter++;
187             }
188         }
189
190         private NeighborSolicitationPacket deserializeNSPacket(byte[] data) {
191             NeighborSolicitationPacketBuilder nsPdu = new NeighborSolicitationPacketBuilder();
192             int bitOffset = 0;
193
194             try {
195                 nsPdu.setDestinationMac(new MacAddress(
196                         ipv6Utils.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
197                 bitOffset = bitOffset + 48;
198                 nsPdu.setSourceMac(new MacAddress(
199                         ipv6Utils.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
200                 bitOffset = bitOffset + 48;
201                 nsPdu.setEthertype(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
202
203                 bitOffset = Ipv6Constants.IP_V6_HDR_START;
204                 nsPdu.setVersion(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 4)));
205                 bitOffset = bitOffset + 4;
206                 nsPdu.setFlowLabel(BitBufferHelper.getLong(BitBufferHelper.getBits(data, bitOffset, 28)));
207                 bitOffset = bitOffset + 28;
208                 nsPdu.setIpv6Length(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
209                 bitOffset = bitOffset + 16;
210                 nsPdu.setNextHeader(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
211                 bitOffset = bitOffset + 8;
212                 nsPdu.setHopLimit(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
213                 bitOffset = bitOffset + 8;
214                 nsPdu.setSourceIpv6(Ipv6Address.getDefaultInstance(
215                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
216                 bitOffset = bitOffset + 128;
217                 nsPdu.setDestinationIpv6(Ipv6Address.getDefaultInstance(
218                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
219                 bitOffset = bitOffset + 128;
220
221                 nsPdu.setIcmp6Type(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
222                 bitOffset = bitOffset + 8;
223                 nsPdu.setIcmp6Code(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
224                 bitOffset = bitOffset + 8;
225                 nsPdu.setIcmp6Chksum(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
226                 bitOffset = bitOffset + 16;
227                 nsPdu.setReserved(Long.valueOf(0));
228                 bitOffset = bitOffset + 32;
229                 nsPdu.setTargetIpAddress(Ipv6Address.getDefaultInstance(
230                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
231             } catch (BufferException | UnknownHostException  e) {
232                 LOG.warn("Exception obtained when deserializing NS packet", e.toString());
233             }
234             return nsPdu.build();
235         }
236
237         private void updateNAResponse(NeighborSolicitationPacket pdu,
238                                       VirtualPort port, NeighborAdvertisePacketBuilder naPacket) {
239             long flag = 0;
240             if (!pdu.getSourceIpv6().equals(ipv6Utils.UNSPECIFIED_ADDR)) {
241                 naPacket.setDestinationIpv6(pdu.getSourceIpv6());
242                 flag = 0xE0; // Set Router, Solicited and Override Flag.
243             } else {
244                 naPacket.setDestinationIpv6(ipv6Utils.ALL_NODES_MCAST_ADDR);
245                 flag = 0xA0; // Set Router and Override Flag.
246             }
247             naPacket.setDestinationMac(pdu.getSourceMac());
248             naPacket.setEthertype(pdu.getEthertype());
249             naPacket.setSourceIpv6(pdu.getTargetIpAddress());
250             naPacket.setSourceMac(new MacAddress(port.getMacAddress()));
251             naPacket.setHopLimit(Ipv6Constants.ICMP_V6_MAX_HOP_LIMIT);
252             naPacket.setIcmp6Type(Ipv6Constants.ICMP_V6_NA_CODE);
253             naPacket.setIcmp6Code(pdu.getIcmp6Code());
254             flag = flag << 24;
255             naPacket.setFlags(flag);
256             naPacket.setFlowLabel(pdu.getFlowLabel());
257             naPacket.setIpv6Length(32);
258             naPacket.setNextHeader(pdu.getNextHeader());
259             naPacket.setOptionType((short)2);
260             naPacket.setTargetAddrLength((short)1);
261             naPacket.setTargetAddress(pdu.getTargetIpAddress());
262             naPacket.setTargetLlAddress(new MacAddress(port.getMacAddress()));
263             naPacket.setVersion(pdu.getVersion());
264             naPacket.setIcmp6Chksum(0);
265             return;
266         }
267
268         private byte[] icmp6NAPayloadtoByte(NeighborAdvertisePacket pdu) {
269             byte[] data = new byte[36];
270             Arrays.fill(data, (byte)0);
271
272             ByteBuffer buf = ByteBuffer.wrap(data);
273             buf.put((byte)pdu.getIcmp6Type().shortValue());
274             buf.put((byte)pdu.getIcmp6Code().shortValue());
275             buf.putShort((short)pdu.getIcmp6Chksum().intValue());
276             buf.putInt((int)pdu.getFlags().longValue());
277             try {
278                 byte[] address = null;
279                 address = InetAddress.getByName(pdu.getTargetAddress().getValue()).getAddress();
280                 buf.put(address);
281             } catch (UnknownHostException e) {
282                 LOG.error("Serializing NA target address failed", e);
283             }
284             buf.put((byte)pdu.getOptionType().shortValue());
285             buf.put((byte)pdu.getTargetAddrLength().shortValue());
286             buf.put(ipv6Utils.bytesFromHexString(pdu.getTargetLlAddress().getValue().toString()));
287             return data;
288         }
289
290         private byte[] fillNeighborAdvertisementPacket(NeighborAdvertisePacket pdu) {
291             ByteBuffer buf = ByteBuffer.allocate(Ipv6Constants.ICMPV6_OFFSET + pdu.getIpv6Length());
292
293             buf.put(ipv6Utils.convertEthernetHeaderToByte((EthernetHeader)pdu), 0, 14);
294             buf.put(ipv6Utils.convertIpv6HeaderToByte((Ipv6Header)pdu), 0, 40);
295             buf.put(icmp6NAPayloadtoByte(pdu), 0, pdu.getIpv6Length());
296             int checksum = ipv6Utils.calcIcmpv6Checksum(buf.array(), (Ipv6Header) pdu);
297             buf.putShort((Ipv6Constants.ICMPV6_OFFSET + 2), (short)checksum);
298             return (buf.array());
299         }
300
301         private void processRouterSolicitationRequest() {
302             byte[] data = packet.getPayload();
303             RouterSolicitationPacket rsPdu = deserializeRSPacket(data);
304             Ipv6Header ipv6Header = (Ipv6Header) rsPdu;
305             if (ipv6Utils.validateChecksum(data, ipv6Header, rsPdu.getIcmp6Chksum()) == false) {
306                 pktProccessedCounter++;
307                 LOG.warn("Received RS packet with invalid checksum on {}. Ignoring the packet.",
308                         packet.getIngress());
309                 return;
310             }
311
312             BigInteger metadata = packet.getMatch().getMetadata().getMetadata();
313             long portTag = MetaDataUtil.getLportFromMetadata(metadata).intValue();
314             String interfaceName = ifMgr.getInterfaceNameFromTag(portTag);
315             VirtualPort port = ifMgr.obtainV6Interface(new Uuid(interfaceName));
316             if (port == null) {
317                 pktProccessedCounter++;
318                 LOG.warn("Port {} not found, skipping.", port);
319                 return;
320             }
321
322             VirtualPort routerPort = ifMgr.getRouterV6InterfaceForNetwork(port.getNetworkID());
323             if (routerPort == null) {
324                 pktProccessedCounter++;
325                 LOG.warn("Port {} is not associated to a Router, skipping.", routerPort);
326                 return;
327             }
328
329             RouterAdvertisementPacketBuilder raPacket = new RouterAdvertisementPacketBuilder();
330             updateRAResponse(rsPdu, raPacket, rsPdu.getSourceMac(), routerPort);
331             // Serialize the response packet
332             byte[] txPayload = fillRouterAdvertisementPacket(raPacket.build());
333             InstanceIdentifier<Node> outNode = packet.getIngress().getValue().firstIdentifierOf(Node.class);
334             TransmitPacketInput input = new TransmitPacketInputBuilder().setPayload(txPayload)
335                     .setNode(new NodeRef(outNode))
336                     .setEgress(packet.getIngress()).build();
337             if (pktService != null) {
338                 LOG.debug("Transmitting the Router Advt packet out {}", packet.getIngress());
339                 pktService.transmitPacket(input);
340                 pktProccessedCounter++;
341             }
342         }
343
344         private RouterSolicitationPacket deserializeRSPacket(byte[] data) {
345             RouterSolicitationPacketBuilder rsPdu = new RouterSolicitationPacketBuilder();
346             int bitOffset = 0;
347
348             try {
349                 rsPdu.setDestinationMac(new MacAddress(
350                         ipv6Utils.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
351                 bitOffset = bitOffset + 48;
352                 rsPdu.setSourceMac(new MacAddress(
353                         ipv6Utils.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
354                 bitOffset = bitOffset + 48;
355                 rsPdu.setEthertype(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
356
357                 bitOffset = Ipv6Constants.IP_V6_HDR_START;
358                 rsPdu.setVersion(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 4)));
359                 bitOffset = bitOffset + 4;
360                 rsPdu.setFlowLabel(BitBufferHelper.getLong(BitBufferHelper.getBits(data, bitOffset, 28)));
361                 bitOffset = bitOffset + 28;
362
363                 rsPdu.setIpv6Length(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
364                 bitOffset = bitOffset + 16;
365                 rsPdu.setNextHeader(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
366                 bitOffset = bitOffset + 8;
367                 rsPdu.setHopLimit(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
368                 bitOffset = bitOffset + 8;
369                 rsPdu.setSourceIpv6(Ipv6Address.getDefaultInstance(
370                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
371                 bitOffset = bitOffset + 128;
372                 rsPdu.setDestinationIpv6(Ipv6Address.getDefaultInstance(
373                         InetAddress.getByAddress(BitBufferHelper.getBits(data, bitOffset, 128)).getHostAddress()));
374                 bitOffset = bitOffset + 128;
375
376                 rsPdu.setIcmp6Type(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
377                 bitOffset = bitOffset + 8;
378                 rsPdu.setIcmp6Code(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
379                 bitOffset = bitOffset + 8;
380                 rsPdu.setIcmp6Chksum(BitBufferHelper.getInt(BitBufferHelper.getBits(data, bitOffset, 16)));
381                 bitOffset = bitOffset + 16;
382                 rsPdu.setReserved(Long.valueOf(0));
383                 bitOffset = bitOffset + 32;
384
385                 if (rsPdu.getIpv6Length() > Ipv6Constants.ICMPV6_RA_LENGTH_WO_OPTIONS) {
386                     rsPdu.setOptionType(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
387                     bitOffset = bitOffset + 8;
388                     rsPdu.setSourceAddrLength(BitBufferHelper.getShort(BitBufferHelper.getBits(data, bitOffset, 8)));
389                     bitOffset = bitOffset + 8;
390                     if (rsPdu.getOptionType() == 1) {
391                         rsPdu.setSourceLlAddress(new MacAddress(
392                                 ipv6Utils.bytesToHexString(BitBufferHelper.getBits(data, bitOffset, 48))));
393                     }
394                 }
395             } catch (BufferException | UnknownHostException e) {
396                 LOG.warn("Exception obtained when deserializing Router Solicitation packet", e.toString());
397             }
398             return rsPdu.build();
399         }
400
401         private void updateRAResponse(RouterSolicitationPacket pdu,
402                                       RouterAdvertisementPacketBuilder raPacket,
403                                       MacAddress vmMac, VirtualPort routerPort) {
404             short icmpv6RaFlags = 0;
405             String gatewayMac = null;
406             IpAddress gatewayIp;
407             List<String> autoConfigPrefixList = new ArrayList<>();
408             List<String> statefulConfigPrefixList = new ArrayList<>();
409
410             for (VirtualSubnet subnet : routerPort.getSubnets()) {
411                 gatewayIp = subnet.getGatewayIp();
412                 // Skip if its a v4 subnet.
413                 if (gatewayIp.getIpv4Address() != null) {
414                     continue;
415                 }
416
417                 if (!subnet.getIpv6RAMode().isEmpty()) {
418                     if (Ipv6Constants.IPV6_AUTO_ADDRESS_SUBNETS.contains(subnet.getIpv6RAMode())) {
419                         autoConfigPrefixList.add(String.valueOf(subnet.getSubnetCidr().getValue()));
420                     }
421
422                     if (subnet.getIpv6RAMode().equalsIgnoreCase(Ipv6Constants.IPV6_DHCPV6_STATEFUL)) {
423                         statefulConfigPrefixList.add(String.valueOf(subnet.getSubnetCidr().getValue()));
424                     }
425                 }
426
427                 if (subnet.getIpv6RAMode().equalsIgnoreCase(Ipv6Constants.IPV6_DHCPV6_STATELESS)) {
428                     icmpv6RaFlags = (short) (icmpv6RaFlags | (1 << 6)); // Other Configuration.
429                 } else if (subnet.getIpv6RAMode().equalsIgnoreCase(Ipv6Constants.IPV6_DHCPV6_STATEFUL)) {
430                     icmpv6RaFlags = (short) (icmpv6RaFlags | (1 << 7)); // Managed Address Conf.
431                 }
432             }
433
434             gatewayMac = routerPort.getMacAddress();
435
436             MacAddress sourceMac = MacAddress.getDefaultInstance(gatewayMac);
437             raPacket.setSourceMac(sourceMac);
438             raPacket.setDestinationMac(vmMac);
439             raPacket.setEthertype(pdu.getEthertype());
440
441             raPacket.setVersion(pdu.getVersion());
442             raPacket.setFlowLabel(pdu.getFlowLabel());
443             int prefixListLength = autoConfigPrefixList.size() + statefulConfigPrefixList.size();
444             raPacket.setIpv6Length(Ipv6Constants.ICMPV6_RA_LENGTH_WO_OPTIONS
445                     + Ipv6Constants.ICMPV6_OPTION_SOURCE_LLA_LENGTH
446                     + prefixListLength * Ipv6Constants.ICMPV6_OPTION_PREFIX_LENGTH);
447             raPacket.setNextHeader(pdu.getNextHeader());
448             raPacket.setHopLimit(Ipv6Constants.ICMP_V6_MAX_HOP_LIMIT);
449             raPacket.setSourceIpv6(ipv6Utils.getIpv6LinkLocalAddressFromMac(sourceMac));
450             raPacket.setDestinationIpv6(pdu.getSourceIpv6());
451
452             raPacket.setIcmp6Type(Ipv6Constants.ICMP_V6_RA_CODE);
453             raPacket.setIcmp6Code((short)0);
454             raPacket.setIcmp6Chksum(0);
455
456             raPacket.setCurHopLimit((short) Ipv6Constants.IPV6_DEFAULT_HOP_LIMIT);
457             raPacket.setFlags((short) icmpv6RaFlags);
458             raPacket.setRouterLifetime(Ipv6Constants.IPV6_ROUTER_LIFETIME);
459             raPacket.setReachableTime((long) 0);
460             raPacket.setRetransTime((long) 0);
461
462             raPacket.setOptionSourceAddr((short)1);
463             raPacket.setSourceAddrLength((short)1);
464             raPacket.setSourceLlAddress(MacAddress.getDefaultInstance(gatewayMac));
465
466             List<PrefixList> prefixList = new ArrayList<>();
467             PrefixListBuilder prefix = new PrefixListBuilder();
468             prefix.setOptionType((short)3);
469             prefix.setOptionLength((short)4);
470             // Note: EUI-64 auto-configuration requires 64 bits.
471             prefix.setPrefixLength((short)64);
472             prefix.setValidLifetime((long) Ipv6Constants.IPV6_RA_VALID_LIFETIME);
473             prefix.setPreferredLifetime((long) Ipv6Constants.IPV6_RA_PREFERRED_LIFETIME);
474             prefix.setReserved((long) 0);
475
476             short autoConfPrefixFlags = 0;
477             autoConfPrefixFlags = (short) (autoConfPrefixFlags | (1 << 7)); // On-link flag
478             autoConfPrefixFlags = (short) (autoConfPrefixFlags | (1 << 6)); // Autonomous address-configuration flag.
479             for (String v6Prefix : autoConfigPrefixList) {
480                 prefix.setFlags((short)autoConfPrefixFlags);
481                 prefix.setPrefix(new Ipv6Prefix(v6Prefix));
482                 prefixList.add(prefix.build());
483             }
484
485             short statefulPrefixFlags = 0;
486             statefulPrefixFlags = (short) (statefulPrefixFlags | (1 << 7)); // On-link flag
487             for (String v6Prefix : statefulConfigPrefixList) {
488                 prefix.setFlags((short)statefulPrefixFlags);
489                 prefix.setPrefix(new Ipv6Prefix(v6Prefix));
490                 prefixList.add(prefix.build());
491             }
492
493             raPacket.setPrefixList((List<PrefixList>) prefixList);
494
495             return;
496         }
497
498         private byte[] fillRouterAdvertisementPacket(RouterAdvertisementPacket pdu) {
499             ByteBuffer buf = ByteBuffer.allocate(Ipv6Constants.ICMPV6_OFFSET + pdu.getIpv6Length());
500
501             buf.put(ipv6Utils.convertEthernetHeaderToByte((EthernetHeader)pdu), 0, 14);
502             buf.put(ipv6Utils.convertIpv6HeaderToByte((Ipv6Header)pdu), 0, 40);
503             buf.put(icmp6RAPayloadtoByte(pdu), 0, pdu.getIpv6Length());
504             int checksum = ipv6Utils.calcIcmpv6Checksum(buf.array(), (Ipv6Header) pdu);
505             buf.putShort((Ipv6Constants.ICMPV6_OFFSET + 2), (short)checksum);
506             return (buf.array());
507         }
508
509         private byte[] icmp6RAPayloadtoByte(RouterAdvertisementPacket pdu) {
510             byte[] data = new byte[pdu.getIpv6Length()];
511             Arrays.fill(data, (byte)0);
512
513             ByteBuffer buf = ByteBuffer.wrap(data);
514             buf.put((byte)pdu.getIcmp6Type().shortValue());
515             buf.put((byte)pdu.getIcmp6Code().shortValue());
516             buf.putShort((short)pdu.getIcmp6Chksum().intValue());
517             buf.put((byte)pdu.getCurHopLimit().shortValue());
518             buf.put((byte)pdu.getFlags().shortValue());
519             buf.putShort((short)pdu.getRouterLifetime().intValue());
520             buf.putInt((int)pdu.getReachableTime().longValue());
521             buf.putInt((int)pdu.getRetransTime().longValue());
522             buf.put((byte)pdu.getOptionSourceAddr().shortValue());
523             buf.put((byte)pdu.getSourceAddrLength().shortValue());
524             buf.put(ipv6Utils.bytesFromHexString(pdu.getSourceLlAddress().getValue().toString()));
525
526             for (PrefixList prefix : pdu.getPrefixList()) {
527                 buf.put((byte)prefix.getOptionType().shortValue());
528                 buf.put((byte)prefix.getOptionLength().shortValue());
529                 buf.put((byte)prefix.getPrefixLength().shortValue());
530                 buf.put((byte)prefix.getFlags().shortValue());
531                 buf.putInt((int)prefix.getValidLifetime().longValue());
532                 buf.putInt((int)prefix.getPreferredLifetime().longValue());
533                 buf.putInt((int)prefix.getReserved().longValue());
534                 buf.put(IetfInetUtil.INSTANCE.ipv6PrefixToBytes(new Ipv6Prefix(prefix.getPrefix())),0,16);
535             }
536             return data;
537         }
538
539     }
540
541     @Override
542     public void close() throws Exception {
543         packetProcessor.shutdown();
544     }
545 }