2 * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.ipv6service;
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;
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;
58 private Ipv6ServiceUtils ipv6Utils;
59 private final ExecutorService packetProcessor = Executors.newCachedThreadPool();
61 public Ipv6PktHandler() {
62 this.ipv6Utils = Ipv6ServiceUtils.getInstance();
65 public void setPacketProcessingService(PacketProcessingService packetService) {
66 this.pktService = packetService;
69 public void setIfMgrInstance(IfMgr instance) {
70 this.ifMgr = instance;
74 public void onPacketReceived(PacketReceived packetReceived) {
78 if (packetReceived == null) {
79 LOG.debug("Received null packet. Returning without any processing");
83 byte[] data = packetReceived.getPayload();
84 if (data.length <= 0) {
85 LOG.debug("Received packet with invalid length {}", data.length);
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));
102 LOG.debug("IPv6 Pdu received on port {} with next-header {} ",
103 packetReceived.getIngress(), v6NxtHdr);
108 } catch (BufferException e) {
109 LOG.warn("Failed to decode packet: {}", e.getMessage());
114 public long getPacketProcessedCounter() {
115 return pktProccessedCounter;
118 private class PacketHandler implements Runnable {
120 PacketReceived packet;
122 PacketHandler(int icmpv6Type, PacketReceived packet) {
123 this.type = icmpv6Type;
124 this.packet = packet;
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();
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());
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));
154 pktProccessedCounter++;
155 LOG.warn("Port {} not found, skipping.", port);
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);
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());
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++;
190 private NeighborSolicitationPacket deserializeNSPacket(byte[] data) {
191 NeighborSolicitationPacketBuilder nsPdu = new NeighborSolicitationPacketBuilder();
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)));
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;
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());
234 return nsPdu.build();
237 private void updateNAResponse(NeighborSolicitationPacket pdu,
238 VirtualPort port, NeighborAdvertisePacketBuilder naPacket) {
240 if (!pdu.getSourceIpv6().equals(ipv6Utils.UNSPECIFIED_ADDR)) {
241 naPacket.setDestinationIpv6(pdu.getSourceIpv6());
242 flag = 0xE0; // Set Router, Solicited and Override Flag.
244 naPacket.setDestinationIpv6(ipv6Utils.ALL_NODES_MCAST_ADDR);
245 flag = 0xA0; // Set Router and Override Flag.
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());
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);
268 private byte[] icmp6NAPayloadtoByte(NeighborAdvertisePacket pdu) {
269 byte[] data = new byte[36];
270 Arrays.fill(data, (byte)0);
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());
278 byte[] address = null;
279 address = InetAddress.getByName(pdu.getTargetAddress().getValue()).getAddress();
281 } catch (UnknownHostException e) {
282 LOG.error("Serializing NA target address failed", e);
284 buf.put((byte)pdu.getOptionType().shortValue());
285 buf.put((byte)pdu.getTargetAddrLength().shortValue());
286 buf.put(ipv6Utils.bytesFromHexString(pdu.getTargetLlAddress().getValue().toString()));
290 private byte[] fillNeighborAdvertisementPacket(NeighborAdvertisePacket pdu) {
291 ByteBuffer buf = ByteBuffer.allocate(Ipv6Constants.ICMPV6_OFFSET + pdu.getIpv6Length());
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());
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());
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));
317 pktProccessedCounter++;
318 LOG.warn("Port {} not found, skipping.", port);
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);
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++;
344 private RouterSolicitationPacket deserializeRSPacket(byte[] data) {
345 RouterSolicitationPacketBuilder rsPdu = new RouterSolicitationPacketBuilder();
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)));
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;
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;
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;
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))));
395 } catch (BufferException | UnknownHostException e) {
396 LOG.warn("Exception obtained when deserializing Router Solicitation packet", e.toString());
398 return rsPdu.build();
401 private void updateRAResponse(RouterSolicitationPacket pdu,
402 RouterAdvertisementPacketBuilder raPacket,
403 MacAddress vmMac, VirtualPort routerPort) {
404 short icmpv6RaFlags = 0;
405 String gatewayMac = null;
407 List<String> autoConfigPrefixList = new ArrayList<>();
408 List<String> statefulConfigPrefixList = new ArrayList<>();
410 for (VirtualSubnet subnet : routerPort.getSubnets()) {
411 gatewayIp = subnet.getGatewayIp();
412 // Skip if its a v4 subnet.
413 if (gatewayIp.getIpv4Address() != null) {
417 if (!subnet.getIpv6RAMode().isEmpty()) {
418 if (Ipv6Constants.IPV6_AUTO_ADDRESS_SUBNETS.contains(subnet.getIpv6RAMode())) {
419 autoConfigPrefixList.add(String.valueOf(subnet.getSubnetCidr().getValue()));
422 if (subnet.getIpv6RAMode().equalsIgnoreCase(Ipv6Constants.IPV6_DHCPV6_STATEFUL)) {
423 statefulConfigPrefixList.add(String.valueOf(subnet.getSubnetCidr().getValue()));
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.
434 gatewayMac = routerPort.getMacAddress();
436 MacAddress sourceMac = MacAddress.getDefaultInstance(gatewayMac);
437 raPacket.setSourceMac(sourceMac);
438 raPacket.setDestinationMac(vmMac);
439 raPacket.setEthertype(pdu.getEthertype());
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());
452 raPacket.setIcmp6Type(Ipv6Constants.ICMP_V6_RA_CODE);
453 raPacket.setIcmp6Code((short)0);
454 raPacket.setIcmp6Chksum(0);
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);
462 raPacket.setOptionSourceAddr((short)1);
463 raPacket.setSourceAddrLength((short)1);
464 raPacket.setSourceLlAddress(MacAddress.getDefaultInstance(gatewayMac));
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);
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());
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());
493 raPacket.setPrefixList((List<PrefixList>) prefixList);
498 private byte[] fillRouterAdvertisementPacket(RouterAdvertisementPacket pdu) {
499 ByteBuffer buf = ByteBuffer.allocate(Ipv6Constants.ICMPV6_OFFSET + pdu.getIpv6Length());
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());
509 private byte[] icmp6RAPayloadtoByte(RouterAdvertisementPacket pdu) {
510 byte[] data = new byte[pdu.getIpv6Length()];
511 Arrays.fill(data, (byte)0);
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()));
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);
542 public void close() throws Exception {
543 packetProcessor.shutdown();