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();
40 public Ipv6ServiceUtils() {
41 icmpv6FlowMap = new ConcurrentHashMap<>();
44 public static Ipv6ServiceUtils getInstance() {
49 * Retrieves the object from the datastore.
50 * @param broker the data broker.
51 * @param datastoreType the data store type.
52 * @param path the wild card path.
53 * @return the required object.
55 public static <T extends DataObject> Optional<T> read(DataBroker broker, LogicalDatastoreType datastoreType,
56 InstanceIdentifier<T> path) {
57 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
58 Optional<T> result = Optional.absent();
60 result = tx.read(datastoreType, path).get();
61 } catch (InterruptedException | ExecutionException e) {
62 throw new RuntimeException(e);
70 * Retrieves the Interface from the datastore.
71 * @param broker the data broker
72 * @param interfaceName the interface name
73 * @return the interface.
75 public static org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
76 .Interface getInterface(DataBroker broker, String interfaceName) {
77 Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
78 .Interface> optInterface =
79 read(broker, LogicalDatastoreType.CONFIGURATION, getInterfaceIdentifier(interfaceName));
80 if (optInterface.isPresent()) {
81 return optInterface.get();
87 * Builds the interface identifier.
88 * @param interfaceName the interface name.
89 * @return the interface identifier.
91 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508
92 .interfaces.Interface> getInterfaceIdentifier(String interfaceName) {
93 return InstanceIdentifier.builder(Interfaces.class)
95 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces
96 .Interface.class, new InterfaceKey(interfaceName)).build();
99 public String bytesToHexString(byte[] bytes) {
103 StringBuffer buf = new StringBuffer();
104 for (int i = 0; i < bytes.length; i++) {
108 short u8byte = (short) (bytes[i] & 0xff);
109 String tmp = Integer.toHexString(u8byte);
110 if (tmp.length() == 1) {
115 return buf.toString();
118 public byte[] bytesFromHexString(String values) {
120 if (values != null) {
123 String[] octets = target.split(":");
125 byte[] ret = new byte[octets.length];
126 for (int i = 0; i < octets.length; i++) {
127 ret[i] = Integer.valueOf(octets[i], 16).byteValue();
132 public int calcIcmpv6Checksum(byte[] packet, Ipv6Header ip6Hdr) {
133 long checksum = getSummation(ip6Hdr.getSourceIpv6());
134 checksum += getSummation(ip6Hdr.getDestinationIpv6());
135 checksum = normalizeChecksum(checksum);
137 checksum += ip6Hdr.getIpv6Length();
138 checksum += ip6Hdr.getNextHeader();
140 int icmp6Offset = Ipv6Constants.ICMPV6_OFFSET;
141 long value = (((packet[icmp6Offset] & 0xff) << 8) | (packet[icmp6Offset + 1] & 0xff));
143 checksum = normalizeChecksum(checksum);
146 //move to icmp6 payload skipping the checksum field
148 int length = packet.length - icmp6Offset;
150 value = (((packet[icmp6Offset] & 0xff) << 8) | (packet[icmp6Offset + 1] & 0xff));
152 checksum = normalizeChecksum(checksum);
158 checksum += packet[icmp6Offset];
159 checksum = normalizeChecksum(checksum);
162 int finalChecksum = (int)(~checksum & 0xffff);
163 return finalChecksum;
166 public boolean validateChecksum(byte[] packet, Ipv6Header ip6Hdr, int recvChecksum) {
167 int checksum = calcIcmpv6Checksum(packet, ip6Hdr);
169 if (checksum == recvChecksum) {
175 private long getSummation(Ipv6Address addr) {
178 baddr = InetAddress.getByName(addr.getValue()).getAddress();
179 } catch (UnknownHostException e) {
180 LOG.error("getSummation: Failed to deserialize address {}", addr.getValue(), e);
186 while (len < baddr.length) {
187 value = (((baddr[len] & 0xff) << 8) | (baddr[len + 1] & 0xff));
189 sum = normalizeChecksum(sum);
195 private long normalizeChecksum(long value) {
196 if ((value & 0xffff0000) > 0) {
197 value = (value & 0xffff);
203 public byte[] convertEthernetHeaderToByte(EthernetHeader ethPdu) {
204 byte[] data = new byte[16];
205 Arrays.fill(data, (byte)0);
207 ByteBuffer buf = ByteBuffer.wrap(data);
208 buf.put(bytesFromHexString(ethPdu.getDestinationMac().getValue().toString()));
209 buf.put(bytesFromHexString(ethPdu.getSourceMac().getValue().toString()));
210 buf.putShort((short)ethPdu.getEthertype().intValue());
214 public byte[] convertIpv6HeaderToByte(Ipv6Header ip6Pdu) {
215 byte[] data = new byte[128];
216 Arrays.fill(data, (byte)0);
218 ByteBuffer buf = ByteBuffer.wrap(data);
219 long flowLabel = (((long)(ip6Pdu.getVersion().shortValue() & 0x0f) << 28)
220 | (ip6Pdu.getFlowLabel().longValue() & 0x0fffffff));
221 buf.putInt((int)flowLabel);
222 buf.putShort((short)ip6Pdu.getIpv6Length().intValue());
223 buf.put((byte)ip6Pdu.getNextHeader().shortValue());
224 buf.put((byte)ip6Pdu.getHopLimit().shortValue());
226 byte[] baddr = InetAddress.getByName(ip6Pdu.getSourceIpv6().getValue()).getAddress();
228 baddr = InetAddress.getByName(ip6Pdu.getDestinationIpv6().getValue()).getAddress();
230 } catch (UnknownHostException e) {
231 LOG.error("convertIpv6HeaderToByte: Failed to serialize src, dest address", e);
236 public Ipv6Address getIpv6LinkLocalAddressFromMac(MacAddress mac) {
237 byte[] octets = bytesFromHexString(mac.getValue());
239 /* As per the RFC2373, steps involved to generate a LLA include
240 1. Convert the 48 bit MAC address to 64 bit value by inserting 0xFFFE
241 between OUI and NIC Specific part.
242 2. Invert the Universal/Local flag in the OUI portion of the address.
243 3. Use the prefix "FE80::/10" along with the above 64 bit Interface
244 identifier to generate the IPv6 LLA. */
246 StringBuffer interfaceID = new StringBuffer();
247 short u8byte = (short) (octets[0] & 0xff);
249 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & u8byte), 2, "0"));
250 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[1]), 2, "0"));
251 interfaceID.append(":");
252 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[2]), 2, "0"));
253 interfaceID.append("ff:fe");
254 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[3]), 2, "0"));
255 interfaceID.append(":");
256 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[4]), 2, "0"));
257 interfaceID.append(StringUtils.leftPad(Integer.toHexString(0xFF & octets[5]), 2, "0"));
259 Ipv6Address ipv6LLA = new Ipv6Address("fe80:0:0:0:" + interfaceID.toString());