blob: 0185542e5df16fd113b6b20a309a82e4a0530e0c [file] [log] [blame]
/*
* Copyright 2016 Open Networking Laboratory
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onosproject.ospf.protocol.util;
import com.google.common.primitives.Bytes;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.onlab.packet.Ip4Address;
import org.onosproject.ospf.protocol.lsa.LsaHeader;
import org.onosproject.ospf.protocol.lsa.OpaqueLsaHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.bind.DatatypeConverter;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.StringTokenizer;
/**
* Representation of an OSPF constants and utility methods.
*/
public final class OspfUtil {
public static final int OSPF_VERSION_2 = 2;
public static final int OSPF_VERSION = OSPF_VERSION_2;
public static final int PACKET_MINIMUM_LENGTH = 24;
public static final int OSPF_HEADER_LENGTH = 24;
public static final int LSA_HEADER_LENGTH = 20;
public static final int DD_HEADER_LENGTH = OSPF_HEADER_LENGTH + 8;
public static final int LSREQUEST_LENGTH = 12;
public static final int OSPFPACKET_LENGTH_POS1 = 2;
public static final int OSPFPACKET_LENGTH_POS2 = 3;
public static final int OSPFPACKET_CHECKSUM_POS1 = 12;
public static final int OSPFPACKET_CHECKSUM_POS2 = 13;
public static final int LSAPACKET_CHECKSUM_POS1 = 16;
public static final int LSAPACKET_CHECKSUM_POS2 = 17;
public static final Ip4Address ALL_SPF_ROUTERS = Ip4Address.valueOf("224.0.0.5");
public static final Ip4Address ALL_DROUTERS = Ip4Address.valueOf("224.0.0.6");
public static final int ONLY_ALL_SPF_ROUTERS = 1;
public static final int JOIN_ALL_DROUTERS = 2;
public static final int INITIALIZE_SET = 1;
public static final int INITIALIZE_NOTSET = 0;
public static final int MORE_SET = 1;
public static final int MORE_NOTSET = 0;
public static final int IS_MASTER = 1;
public static final int NOT_MASTER = 0;
public static final int NOT_ASSIGNED = 0;
public static final int FOUR_BYTES = 4;
public static final int EIGHT_BYTES = 8;
public static final int TWELVE_BYTES = 12;
public static final int EXTERNAL_DESTINATION_LENGTH = 12;
private static final Logger log =
LoggerFactory.getLogger(OspfUtil.class);
/**
* Creates an instance.
*/
private OspfUtil() {
}
/**
* Checks given IPs are in same network or not.
*
* @param ip1 IP address
* @param ip2 IP address
* @param mask network mask
* @return true if both are in same network else false
* @throws Exception might throws exception while parsing ip address
*/
public static boolean sameNetwork(Ip4Address ip1, Ip4Address ip2, Ip4Address mask)
throws Exception {
byte[] a1 = ip1.toOctets();
byte[] a2 = ip2.toOctets();
byte[] m = mask.toOctets();
for (int i = 0; i < a1.length; i++) {
if ((a1[i] & m[i]) != (a2[i] & m[i])) {
return false;
}
}
return true;
}
/**
* Converts IP address to long.
*
* @param ipAddress IP address
* @return long value represents IP address
*/
public static long ipAddressToLong(String ipAddress) {
StringTokenizer st = new StringTokenizer(ipAddress, ".");
long ipAsNumber = Long.parseLong(st.nextToken()) * (long) Math.pow(256, 3);
ipAsNumber += Long.parseLong(st.nextToken()) * (long) Math.pow(256, 2);
ipAsNumber += Long.parseLong(st.nextToken()) * 256;
ipAsNumber += +Long.parseLong(st.nextToken());
return ipAsNumber;
}
/**
* Checks option field to see whether opaque enabled or not.
* 2nd Bit in options field of DdPacket represents Opaque.
* 7th bit is external capability.
* This method checks Opaque bit is set in the options or not.
*
* @param options options value
* @return true if opaque enabled else false.
*/
public static boolean isOpaqueEnabled(int options) {
Boolean[] bits = new Boolean[8];
for (int i = 7; i >= 0; i--) {
bits[i] = (options & (1 << i)) != 0;
}
List<Boolean> list = Arrays.asList(bits);
Collections.reverse(list);
//2nd bit is Opaque.
return list.get(1);
}
/**
* Converts a byte to integer variable.
*
* @param bytesToConvert bytes to convert
* @return integer representation of bytes
*/
public static int byteToInteger(byte[] bytesToConvert) {
final StringBuilder builder = new StringBuilder();
for (byte eachByte : bytesToConvert) {
builder.append(String.format("%02x", eachByte));
}
int num = Integer.parseInt(builder.toString(), 16);
return num;
}
/**
* Converts a byte to long variable.
*
* @param bytesToConvert bytes to convert
* @return long representation of bytes
*/
public static long byteToLong(byte[] bytesToConvert) {
final StringBuilder builder = new StringBuilder();
for (byte eachByte : bytesToConvert) {
builder.append(String.format("%02x", eachByte));
}
long num = Long.parseLong(builder.toString(), 16);
return num;
}
/**
* Creates a random number.
*
* @return random number
*/
public static int createRandomNumber() {
Random rnd = new Random();
int randomNumber = 10000000 + rnd.nextInt(90000000);
return randomNumber;
}
/**
* Reads the LSA header from channel buffer.
*
* @param channelBuffer channel buffer instance
* @return LSA header instance.
* @throws Exception might throws exception while parsing buffer
*/
public static LsaHeader readLsaHeader(ChannelBuffer channelBuffer) throws Exception {
//add all the LSA Headers - one header is of 20 bytes
LsaHeader lsaHeader = null;
if (channelBuffer.readableBytes() >= OspfUtil.LSA_HEADER_LENGTH) {
byte[] byteArray = new byte[OspfUtil.FOUR_BYTES];
channelBuffer.readBytes(byteArray, 0, OspfUtil.FOUR_BYTES);
ChannelBuffer tempBuffer = ChannelBuffers.copiedBuffer(byteArray);
int lsType = byteArray[3];
if (lsType == OspfParameters.AREA_LOCAL_OPAQUE_LSA || lsType == OspfParameters.LINK_LOCAL_OPAQUE_LSA
|| lsType == OspfParameters.AS_OPAQUE_LSA) {
OpaqueLsaHeader header = new OpaqueLsaHeader();
header.setAge(tempBuffer.readShort());
header.setOptions(tempBuffer.readByte());
header.setLsType(tempBuffer.readByte());
header.setOpaqueType(channelBuffer.readByte());
header.setOpaqueId(channelBuffer.readUnsignedMedium());
byte[] tempByteArray = new byte[OspfUtil.FOUR_BYTES];
channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
header.setAdvertisingRouter(Ip4Address.valueOf(tempByteArray));
header.setLsSequenceNo(channelBuffer.readInt());
header.setLsCheckSum(channelBuffer.readUnsignedShort());
header.setLsPacketLen(channelBuffer.readShort());
byte[] opaqueIdBytes = OspfUtil.convertToTwoBytes(header.opaqueId());
header.setLinkStateId(header.opaqueType() + "." + "0" + "." +
opaqueIdBytes[0] + "." + opaqueIdBytes[1]);
lsaHeader = header;
} else {
LsaHeader header = new LsaHeader();
header.setAge(tempBuffer.readShort());
header.setOptions(tempBuffer.readByte());
header.setLsType(tempBuffer.readByte());
byte[] tempByteArray = new byte[OspfUtil.FOUR_BYTES];
channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
header.setLinkStateId(InetAddress.getByAddress(tempByteArray).getHostName());
tempByteArray = new byte[OspfUtil.FOUR_BYTES];
channelBuffer.readBytes(tempByteArray, 0, OspfUtil.FOUR_BYTES);
header.setAdvertisingRouter(Ip4Address.valueOf(tempByteArray));
header.setLsSequenceNo(channelBuffer.readInt());
header.setLsCheckSum(channelBuffer.readUnsignedShort());
header.setLsPacketLen(channelBuffer.readShort());
lsaHeader = header;
}
}
return lsaHeader;
}
/**
* Converts an integer to two bytes.
*
* @param numberToConvert number to convert
* @return given number as bytes
*/
public static byte[] convertToTwoBytes(int numberToConvert) {
byte[] numInBytes = new byte[2];
String s1 = Integer.toHexString(numberToConvert);
if (s1.length() % 2 != 0) {
s1 = "0" + s1;
}
byte[] hexas = DatatypeConverter.parseHexBinary(s1);
if (hexas.length == 1) {
numInBytes[0] = 0;
numInBytes[1] = hexas[0];
} else {
numInBytes[0] = hexas[0];
numInBytes[1] = hexas[1];
}
return numInBytes;
}
/**
* Converts a number to three bytes.
*
* @param numberToConvert number to convert
* @return given number as bytes
*/
public static byte[] convertToThreeBytes(int numberToConvert) {
byte[] numInBytes = new byte[3];
String s1 = Integer.toHexString(numberToConvert);
if (s1.length() % 2 != 0) {
s1 = "0" + s1;
}
byte[] hexas = DatatypeConverter.parseHexBinary(s1);
if (hexas.length == 1) {
numInBytes[0] = 0;
numInBytes[1] = 0;
numInBytes[2] = hexas[0];
} else if (hexas.length == 2) {
numInBytes[0] = 0;
numInBytes[1] = hexas[0];
numInBytes[2] = hexas[1];
} else {
numInBytes[0] = hexas[0];
numInBytes[1] = hexas[1];
numInBytes[2] = hexas[2];
}
return numInBytes;
}
/**
* Converts a number to four bytes.
*
* @param numberToConvert number to convert
* @return given number as bytes
*/
public static byte[] convertToFourBytes(int numberToConvert) {
byte[] numInBytes = new byte[4];
String s1 = Integer.toHexString(numberToConvert);
if (s1.length() % 2 != 0) {
s1 = "0" + s1;
}
byte[] hexas = DatatypeConverter.parseHexBinary(s1);
if (hexas.length == 1) {
numInBytes[0] = 0;
numInBytes[1] = 0;
numInBytes[2] = 0;
numInBytes[3] = hexas[0];
} else if (hexas.length == 2) {
numInBytes[0] = 0;
numInBytes[1] = 0;
numInBytes[2] = hexas[0];
numInBytes[3] = hexas[1];
} else if (hexas.length == 3) {
numInBytes[0] = 0;
numInBytes[1] = hexas[0];
numInBytes[2] = hexas[1];
numInBytes[3] = hexas[2];
} else {
numInBytes[0] = hexas[0];
numInBytes[1] = hexas[1];
numInBytes[2] = hexas[2];
numInBytes[3] = hexas[3];
}
return numInBytes;
}
/**
* Converts a number to four bytes.
*
* @param numberToConvert number to convert
* @return given number as bytes
*/
public static byte[] convertToFourBytes(long numberToConvert) {
byte[] numInBytes = new byte[4];
String s1 = Long.toHexString(numberToConvert);
if (s1.length() % 2 != 0) {
s1 = "0" + s1;
}
if (s1.length() == 16) {
s1 = s1.substring(8, s1.length());
}
byte[] hexas = DatatypeConverter.parseHexBinary(s1);
if (hexas.length == 1) {
numInBytes[0] = 0;
numInBytes[1] = 0;
numInBytes[2] = 0;
numInBytes[3] = hexas[0];
} else if (hexas.length == 2) {
numInBytes[0] = 0;
numInBytes[1] = 0;
numInBytes[2] = hexas[0];
numInBytes[3] = hexas[1];
} else if (hexas.length == 3) {
numInBytes[0] = 0;
numInBytes[1] = hexas[0];
numInBytes[2] = hexas[1];
numInBytes[3] = hexas[2];
} else {
numInBytes[0] = hexas[0];
numInBytes[1] = hexas[1];
numInBytes[2] = hexas[2];
numInBytes[3] = hexas[3];
}
return numInBytes;
}
/**
* Adds the checksum and length in packet.
*
* @param ospfPacket ospf packet
* @param lengthBytePos1 length byte position
* @param lengthBytePos2 length byte position
* @param checksumBytePos1 checksum byte position
* @param checksumBytePos2 checksum byte position
* @return byte array with checksum and length
*/
public static byte[] addLengthAndCheckSum(byte[] ospfPacket, int lengthBytePos1, int lengthBytePos2,
int checksumBytePos1, int checksumBytePos2) {
//Set the length of the packet
//Get the total length of the packet
int length = ospfPacket.length;
//Convert the lenth to two bytes as the length field is 2 bytes
byte[] lenthInTwoBytes = OspfUtil.convertToTwoBytes(length);
//ospf header 3rd and 4th position represents length
ospfPacket[lengthBytePos1] = lenthInTwoBytes[0]; //assign 1st byte in lengthBytePos1
ospfPacket[lengthBytePos2] = lenthInTwoBytes[1]; //assign 2st byte in lengthBytePos2
//Get the checksum as two bytes.
byte[] checkSumInTwoBytes = new ChecksumCalculator().calculateOspfCheckSum(ospfPacket,
checksumBytePos1, checksumBytePos2);
ospfPacket[checksumBytePos1] = checkSumInTwoBytes[0]; //assign 1st byte in checksumBytePos1
ospfPacket[checksumBytePos2] = checkSumInTwoBytes[1]; //assign 2st byte in checksumBytePos2
return ospfPacket;
}
/**
* Adds metadata to ospf packet like whether to join multi cast group and destination IP.
*
* @param ospfPacket OSPF packet
* @param allDroutersValue whether to join multi cast or not
* @param destinationIp destination ip address
* @return byte array
*/
public static byte[] addMetadata(byte[] ospfPacket, int allDroutersValue, Ip4Address destinationIp) {
byte[] packet;
byte[] allDroutersByteVal = {(byte) allDroutersValue};
byte[] destIpAsBytes = destinationIp.toOctets();
byte[] metadata = Bytes.concat(allDroutersByteVal, destIpAsBytes);
packet = Bytes.concat(metadata, ospfPacket);
return packet;
}
}