blob: 82fe90900f568d2e5bc48241cbf30a11cf4d1038 [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.ospfpacket.types;
import com.google.common.base.MoreObjects;
import com.google.common.primitives.Bytes;
import org.jboss.netty.buffer.ChannelBuffer;
import org.onosproject.ospf.exceptions.OspfErrorType;
import org.onosproject.ospf.exceptions.OspfParseException;
import org.onosproject.ospf.protocol.lsa.LsaHeader;
import org.onosproject.ospf.protocol.lsa.OpaqueLsaHeader;
import org.onosproject.ospf.protocol.ospfpacket.OspfPacketHeader;
import org.onosproject.ospf.protocol.util.OspfPacketType;
import org.onosproject.ospf.protocol.util.OspfParameters;
import org.onosproject.ospf.protocol.util.OspfUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Representation of an OSPF Database Description packet.
* Database Description packets are OSPF packet type 2.
* These packets are exchanged when an adjacency is being initialized.
* They describe the contents of the link-state database.
*/
public class DdPacket extends OspfPacketHeader {
/*
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Version # | 2 | Packet length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Router ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Area ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | AuType |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Authentication |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Authentication |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Interface MTU | Options |0|0|0|0|0|I|M|MS
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DD sequence number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+- -+
| |
+- An LSA Header -+
| |
+- -+
| |
+- -+
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| ... |
*/
private static final Logger log = LoggerFactory.getLogger(DdPacket.class);
private int imtu;
private int options;
private int ims; // initialize , more but / master slave bit
private int isMaster;
private int isInitialize;
private int isMore;
private long sequenceNo;
private boolean isOpaqueCapable;
private List<LsaHeader> lsaHeaderList = new ArrayList<>();
/**
* Creates an instance of DD packet.
*/
public DdPacket() {
}
/**
* Creates an instance of DD packet.
*
* @param ospfHeader OSPF header instance
*/
public DdPacket(OspfPacketHeader ospfHeader) {
populateHeader(ospfHeader);
}
/**
* Gets is opaque capable or not.
*
* @return true if opaque capable else false
*/
public boolean isOpaqueCapable() {
return isOpaqueCapable;
}
/**
* Sets is opaque capable or not.
*
* @param isOpaqueCapable true or false
*/
public void setIsOpaqueCapable(boolean isOpaqueCapable) {
this.isOpaqueCapable = isOpaqueCapable;
}
/**
* Gets IMS value.
*
* @return IMS bits as an int value
*/
public int ims() {
return ims;
}
/**
* Sets IMS value.
*
* @param ims IMS value
*/
public void setIms(int ims) {
this.ims = ims;
}
/**
* Gets master bit value.
*
* @return 1 if master else 0
*/
public int isMaster() {
return isMaster;
}
/**
* Sets master value.
*
* @param isMaster 1 represents master
*/
public void setIsMaster(int isMaster) {
this.isMaster = isMaster;
}
/**
* Gets Initialize bit value.
*
* @return 1 if initialize else 0
*/
public int isInitialize() {
return isInitialize;
}
/**
* Sets initialize value.
*
* @param isInitialize 1 is initialize else 0
*/
public void setIsInitialize(int isInitialize) {
this.isInitialize = isInitialize;
}
/**
* Gets is more bit set or not.
*
* @return 1 if more set else 0
*/
public int isMore() {
return isMore;
}
/**
* Sets more bit value to 0 or 1.
*
* @param isMore 1 if more set else 0
*/
public void setIsMore(int isMore) {
this.isMore = isMore;
}
/**
* Gets IMTU value.
*
* @return IMTU value
*/
public int imtu() {
return imtu;
}
/**
* Sets IMTU value.
*
* @param imtu value
*/
public void setImtu(int imtu) {
this.imtu = imtu;
}
/**
* Gets options value.
*
* @return options
*/
public int options() {
return options;
}
/**
* Sets options value.
*
* @param options options value
*/
public void setOptions(int options) {
this.options = options;
}
/**
* Gets sequence number.
*
* @return sequenceNo
*/
public long sequenceNo() {
return sequenceNo;
}
/**
* Sets Sequence number.
*
* @param sequenceNo sequence number
*/
public void setSequenceNo(long sequenceNo) {
this.sequenceNo = sequenceNo;
}
/**
* Gets LSA header list.
*
* @return LSA header
*/
public List<LsaHeader> getLsaHeaderList() {
return lsaHeaderList;
}
/**
* Adds LSA header to header list.
*
* @param lsaHeader lsa header instance
*/
public void addLsaHeader(LsaHeader lsaHeader) {
if (!lsaHeaderList.contains(lsaHeader)) {
lsaHeaderList.add(lsaHeader);
}
}
@Override
public OspfPacketType ospfMessageType() {
return OspfPacketType.DD;
}
@Override
public void readFrom(ChannelBuffer channelBuffer) throws OspfParseException {
try {
this.setImtu(channelBuffer.readShort());
int options = channelBuffer.readByte();
String obit = Integer.toHexString(options);
if (obit.length() == 1) {
obit = "0" + obit;
}
String toBinary = Integer.toBinaryString(Integer.parseInt(new Character(obit.charAt(0)).toString()));
if (toBinary.length() == 1) {
toBinary = "000" + toBinary;
} else if (toBinary.length() == 2) {
toBinary = "00" + toBinary;
} else if (toBinary.length() == 3) {
toBinary = "0" + toBinary;
}
if (Integer.parseInt(new Character(toBinary.charAt(1)).toString()) == 1) {
this.setIsOpaqueCapable(true);
}
this.setOptions(options);
this.setIms(channelBuffer.readByte());
//Convert the byte to ims bits
String strIms = Integer.toBinaryString(this.ims());
if (strIms.length() == 3) {
this.setIsInitialize(Integer.parseInt(Character.toString(strIms.charAt(0))));
this.setIsMore(Integer.parseInt(Character.toString(strIms.charAt(1))));
this.setIsMaster(Integer.parseInt(Character.toString(strIms.charAt(2))));
} else if (strIms.length() == 2) {
this.setIsInitialize(0);
this.setIsMore(Integer.parseInt(Character.toString(strIms.charAt(0))));
this.setIsMaster(Integer.parseInt(Character.toString(strIms.charAt(1))));
} else if (strIms.length() == 1) {
this.setIsInitialize(0);
this.setIsMore(0);
this.setIsMaster(Integer.parseInt(Character.toString(strIms.charAt(0))));
}
this.setSequenceNo(channelBuffer.readInt());
//add all the LSA Headers - header is of 20 bytes
while (channelBuffer.readableBytes() >= OspfUtil.LSA_HEADER_LENGTH) {
LsaHeader header = OspfUtil.readLsaHeader(channelBuffer.readBytes(OspfUtil.LSA_HEADER_LENGTH));
//add the LSAHeader to DDPacket
addLsaHeader(header);
}
} catch (Exception e) {
log.debug("Error::DdPacket:: {}", e.getMessage());
throw new OspfParseException(OspfErrorType.MESSAGE_HEADER_ERROR, OspfErrorType.BAD_MESSAGE_LENGTH);
}
}
@Override
public byte[] asBytes() {
byte[] ddMessage = null;
byte[] ddHeader = getDdHeaderAsByteArray();
byte[] ddBody = getDdBodyAsByteArray();
ddMessage = Bytes.concat(ddHeader, ddBody);
return ddMessage;
}
/**
* Gets DD Header as byte array.
*
* @return dd header as byte array.
*/
public byte[] getDdHeaderAsByteArray() {
List<Byte> headerLst = new ArrayList<>();
try {
headerLst.add((byte) this.ospfVersion());
headerLst.add((byte) this.ospfType());
headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.ospfPacLength())));
headerLst.addAll(Bytes.asList(this.routerId().toOctets()));
headerLst.addAll(Bytes.asList(this.areaId().toOctets()));
headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.checksum())));
headerLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.authType())));
//Authentication is 0 always. Total 8 bytes consist of zero
byte[] auth = new byte[OspfUtil.EIGHT_BYTES];
headerLst.addAll(Bytes.asList(auth));
} catch (Exception e) {
log.debug("Error");
}
return Bytes.toArray(headerLst);
}
/**
* Gets DD body as byte array.
*
* @return DD body
*/
public byte[] getDdBodyAsByteArray() {
List<Byte> bodyLst = new ArrayList<>();
try {
bodyLst.addAll(Bytes.asList(OspfUtil.convertToTwoBytes(this.imtu())));
bodyLst.add((byte) this.options());
StringBuilder sb = new StringBuilder();
sb.append(this.isInitialize());
sb.append(this.isMore());
sb.append(this.isMaster());
bodyLst.add((byte) Integer.parseInt(sb.toString(), 2));
bodyLst.addAll(Bytes.asList(OspfUtil.convertToFourBytes(this.sequenceNo()))); // passing long value
for (LsaHeader lsaHeader : lsaHeaderList) {
if (lsaHeader.lsType() == OspfParameters.LINK_LOCAL_OPAQUE_LSA ||
lsaHeader.lsType() == OspfParameters.AREA_LOCAL_OPAQUE_LSA ||
lsaHeader.lsType() == OspfParameters.AS_OPAQUE_LSA) {
OpaqueLsaHeader header = (OpaqueLsaHeader) lsaHeader;
bodyLst.addAll(Bytes.asList(header.getOpaqueLsaHeaderAsByteArray()));
} else {
bodyLst.addAll(Bytes.asList(lsaHeader.getLsaHeaderAsByteArray()));
}
}
} catch (Exception e) {
log.debug("Error::getLsrBodyAsByteArray {}", e.getMessage());
return Bytes.toArray(bodyLst);
}
return Bytes.toArray(bodyLst);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.omitNullValues()
.add("imtu", imtu)
.add("options", options)
.add("ims", ims)
.add("isMaster", isMaster)
.add("isInitialize", isInitialize)
.add("isMore", isMore)
.add("sequenceNo", sequenceNo)
.add("isOpaqueCapable", isOpaqueCapable)
.add("lsaHeaderList", lsaHeaderList)
.toString();
}
}