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
9 package org.opendaylight.netvirt.ipv6service.utils;
11 import com.google.common.base.Optional;
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.ConcurrentHashMap;
17 import java.util.concurrent.ConcurrentMap;
18 import java.util.concurrent.ExecutionException;
19 import org.apache.commons.lang3.StringUtils;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv6Address;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.EthernetHeader;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.ipv6service.nd.packet.rev160620.Ipv6Header;
30 import org.opendaylight.yangtools.yang.binding.DataObject;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
35 public class Ipv6ServiceUtils {
36 private static final Logger LOG = LoggerFactory.getLogger(Ipv6ServiceUtils.class);
37 private ConcurrentMap<String, InstanceIdentifier<Flow>> icmpv6FlowMap;
38 public static final Ipv6ServiceUtils instance = new Ipv6ServiceUtils();
39 public static Ipv6Address ALL_NODES_MCAST_ADDR;
40 public static Ipv6Address UNSPECIFIED_ADDR;
42 public Ipv6ServiceUtils() {
43 icmpv6FlowMap = new ConcurrentHashMap<>();
45 UNSPECIFIED_ADDR = Ipv6Address.getDefaultInstance(
46 InetAddress.getByName("0:0:0:0:0:0:0:0").getHostAddress());
47 ALL_NODES_MCAST_ADDR = Ipv6Address.getDefaultInstance(InetAddress.getByName("FF02::1").getHostAddress());
48 } catch (UnknownHostException e) {
49 LOG.error("Ipv6ServiceUtils: Failed to instantiate the ipv6 address", e);
53 public static Ipv6ServiceUtils getInstance() {
58 * Retrieves the object from the datastore.
59 * @param broker the data broker.
60 * @param datastoreType the data store type.
61 * @param path the wild card path.
62 * @return the required object.
64 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
65 InstanceIdentifier<T> path) {
66 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
67 Optional<T> result = Optional.absent();
69 result = tx.read(datastoreType, path).get();
70 } catch (InterruptedException | ExecutionException e) {
71 throw new RuntimeException(e);
79 * Retrieves the Interface from the datastore.
80 * @param broker the data broker
81 * @param interfaceName the interface name
82 * @return the interface.
84 public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
85 .Interface getInterface(DataBroker broker, String interfaceName) {
86 Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
87 .Interface> optInterface =
88 read(broker, LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName));
89 if (optInterface.isPresent()) {
90 return optInterface.get();
96 * Builds the interface identifier.
97 * @param interfaceName the interface name.
98 * @return the interface identifier.
100 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
101 .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
102 return InstanceIdentifier.builder(Interfaces.class)
104 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
105 .Interface.class, new InterfaceKey(interfaceName)).build();
108 public String bytesToHexString(byte[] bytes) {
112 StringBuffer buf = new StringBuffer();
113 for (int i = 0; i < bytes.length; i++) {
117 short u8byte = (short) (bytes[i] & 0xff);
118 String tmp = Integer.toHexString(u8byte);
119 if (tmp.length() == 1) {
124 return buf.toString();
127 public byte[] bytesFromHexString(String values) {
129 if (values != null) {
132 String[] octets = target.split(":");
134 byte[] ret = new byte[octets.length];
135 for (int i = 0; i < octets.length; i++) {
136 ret[i] = Integer.valueOf(octets[i], 16).byteValue();
141 public int calcIcmpv6Checksum(byte[] packet, Ipv6Header ip6Hdr) {
142 long checksum = getSummation(ip6Hdr.getSourceIpv6());
143 checksum += getSummation(ip6Hdr.getDestinationIpv6());
144 checksum = normalizeChecksum(checksum);
146 checksum += ip6Hdr.getIpv6Length();
147 checksum += ip6Hdr.getNextHeader();
149 int icmp6Offset = Ipv6Constants.ICMPV6_OFFSET;
150 long value = (((packet[icmp6Offset] & 0xff) << 8) | (packet[icmp6Offset + 1] & 0xff));
152 checksum = normalizeChecksum(checksum);
155 //move to icmp6 payload skipping the checksum field
157 int length = packet.length - icmp6Offset;
159 value = (((packet[icmp6Offset] & 0xff) << 8) | (packet[icmp6Offset + 1] & 0xff));
161 checksum = normalizeChecksum(checksum);
167 checksum += packet[icmp6Offset];
168 checksum = normalizeChecksum(checksum);
171 int finalChecksum = (int)(~checksum & 0xffff);
172 return finalChecksum;
175 public boolean validateChecksum(byte[] packet, Ipv6Header ip6Hdr, int recvChecksum) {
176 int checksum = calcIcmpv6Checksum(packet, ip6Hdr);
178 if (checksum == recvChecksum) {
184 private long getSummation(Ipv6Address addr) {
187 baddr = InetAddress.getByName(addr.getValue()).getAddress();
188 } catch (UnknownHostException e) {
189 LOG.error("getSummation: Failed to deserialize address {}", addr.getValue(), e);
195 while (len < baddr.length) {
196 value = (((baddr[len] & 0xff) << 8) | (baddr[len + 1] & 0xff));
198 sum = normalizeChecksum(sum);
204 private long normalizeChecksum(long value) {
205 if ((value & 0xffff0000) > 0) {
206 value = (value & 0xffff);
212 public byte[] convertEthernetHeaderToByte(EthernetHeader ethPdu) {
213 byte[] data = new byte[16];
214 Arrays.fill(data, (byte)0);
216 ByteBuffer buf = ByteBuffer.wrap(data);
217 buf.put(bytesFromHexString(ethPdu.getDestinationMac().getValue().toString()));
218 buf.put(bytesFromHexString(ethPdu.getSourceMac().getValue().toString()));
219 buf.putShort((short)ethPdu.getEthertype().intValue());
223 public byte[] convertIpv6HeaderToByte(Ipv6Header ip6Pdu) {
224 byte[] data = new byte[128];
225 Arrays.fill(data, (byte)0);
227 ByteBuffer buf = ByteBuffer.wrap(data);
228 long flowLabel = (((long)(ip6Pdu.getVersion().shortValue() & 0x0f) << 28)
229 | (ip6Pdu.getFlowLabel().longValue() & 0x0fffffff));
230 buf.putInt((int)flowLabel);
231 buf.putShort((short)ip6Pdu.getIpv6Length().intValue());
232 buf.put((byte)ip6Pdu.getNextHeader().shortValue());
233 buf.put((byte)ip6Pdu.getHopLimit().shortValue());
235 byte[] baddr = InetAddress.getByName(ip6Pdu.getSourceIpv6().getValue()).getAddress();
237 baddr = InetAddress.getByName(ip6Pdu.getDestinationIpv6().getValue()).getAddress();
239 } catch (UnknownHostException e) {
240 LOG.error("convertIpv6HeaderToByte: Failed to serialize src, dest address", e);
245 public Ipv6Address getIpv6LinkLocalAddressFromMac(MacAddress mac) {
246 byte[] octets = bytesFromHexString(mac.getValue());
248 /* As per the RFC2373, steps involved to generate a LLA include
249 1. Convert the 48 bit MAC address to 64 bit value by inserting 0xFFFE
250 between OUI and NIC Specific part.
251 2. Invert the Universal/Local flag in the OUI portion of the address.
252 3. Use the prefix "FE80::/10" along with the above 64 bit Interface
253 identifier to generate the IPv6 LLA. */
255 StringBuffer interfaceID = new StringBuffer();
256 short u8byte = (short) (octets[0] & 0xff);
258 interfaceID.append(Integer.toHexString(0xFF & u8byte));
259 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[1]), 2, "0"));
260 interfaceID.append(":");
261 interfaceID.append(Integer.toHexString(0xFF & octets[2]));
262 interfaceID.append("ff:fe");
263 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[3]), 2, "0"));
264 interfaceID.append(":");
265 interfaceID.append(Integer.toHexString(0xFF & octets[4]));
266 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[5]), 2, "0"));
268 Ipv6Address ipv6LLA = new Ipv6Address("fe80:0:0:0:" + interfaceID.toString());