blob: 1867959f55d5a30b87e972ceb2214ed114f85434 [file] [log] [blame]
/*
* Copyright 2016-present 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.bgpio.types.attr;
import com.google.common.base.MoreObjects;
import org.jboss.netty.buffer.ChannelBuffer;
import org.onlab.packet.IpAddress;
import org.onosproject.bgpio.exceptions.BgpParseException;
import org.onosproject.bgpio.types.BgpErrorType;
import org.onosproject.bgpio.types.BgpValueType;
import org.onosproject.bgpio.types.WideCommunityAttrHeader;
import org.onosproject.bgpio.types.WideCommunityExcludeTarget;
import org.onosproject.bgpio.types.WideCommunityInteger;
import org.onosproject.bgpio.types.WideCommunityIpV4Neighbour;
import org.onosproject.bgpio.types.WideCommunityParameter;
import org.onosproject.bgpio.types.WideCommunityTarget;
import org.onosproject.bgpio.util.Validation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
/**
* Provides implementation of wide community path attribute.
*/
public class WideCommunity implements BgpValueType {
private static final Logger log = LoggerFactory.getLogger(WideCommunity.class);
public static final byte TYPE = (byte) 129;
public static final short LENGTH = 4;
public static final byte TYPE_LENGTH_SIZE = 3;
public static final byte FLAGS = (byte) 0x90;
private WideCommunityAttrHeader wideCommunityHeader;
private int community;
private int localAsn;
private int contextAsn;
private WideCommunityTarget target;
private WideCommunityExcludeTarget excludeTarget;
private WideCommunityParameter parameter;
/**
* Creates an instance of wide community.
*
* @param wideCommunityHeader wide community header
* @param community wide community
* @param localAsn local ASN number
* @param contextAsn context ASN number
* @param target wide community include target
* @param excludeTarget wide community exclude target
* @param parameter wide community parameter
*/
public WideCommunity(WideCommunityAttrHeader wideCommunityHeader, int community, int localAsn, int contextAsn,
WideCommunityTarget target, WideCommunityExcludeTarget excludeTarget,
WideCommunityParameter parameter) {
this.wideCommunityHeader = wideCommunityHeader;
this.community = community;
this.localAsn = localAsn;
this.contextAsn = contextAsn;
this.target = target;
this.excludeTarget = excludeTarget;
this.parameter = parameter;
}
/**
* Returns object of this class with specified values.
*
* @param community wide community
* @param localAsn local ASN number
* @param contextAsn context ASN number
* @param target wide community include target
* @param excludeTarget wide community exclude target
* @param parameter wide community parameter
* @return object of WideCommunityAttr
*/
public static WideCommunity of(WideCommunityAttrHeader wideCommunityHeader, int community, int localAsn,
int contextAsn, WideCommunityTarget target,
WideCommunityExcludeTarget excludeTarget, WideCommunityParameter parameter) {
return new WideCommunity(wideCommunityHeader, community, localAsn, contextAsn, target, excludeTarget,
parameter);
}
/**
* Returns wide community value.
*
* @return wide community value
*/
public int community() {
return community;
}
/**
* Sets wide community value.
*
* @param community wide community value
*/
public void setCommunity(int community) {
this.community = community;
}
/**
* Returns wide community local autonomous number.
*
* @return local autonomous number
*/
public int localAsn() {
return localAsn;
}
/**
* Sets wide community local autonomous number.
*
* @param localAsn local autonomous number
*/
public void setLocalAsn(int localAsn) {
this.localAsn = localAsn;
}
/**
* Returns wide community context autonomous number.
*
* @return contest autonomous number
*/
public int contextAsn() {
return contextAsn;
}
/**
* Sets wide community context autonomous number.
*
* @param contextAsn context autonomous number
*/
public void setContextAsn(int contextAsn) {
this.contextAsn = contextAsn;
}
/**
* Returns wide community target.
*
* @return wide community target
*/
public WideCommunityTarget target() {
return target;
}
/**
* Sets wide community target.
*
* @param target wide community target
*/
public void setTarget(WideCommunityTarget target) {
this.target = target;
}
/**
* Returns wide community exclude target.
*
* @return wide community exclude target
*/
public WideCommunityExcludeTarget excludeTarget() {
return excludeTarget;
}
/**
* Sets wide community exclude target.
*
* @param excludeTarget wide community texclude arget
*/
public void setExcludeTarget(WideCommunityExcludeTarget excludeTarget) {
this.excludeTarget = excludeTarget;
}
/**
* Returns wide community parameter.
*
* @return wide community parameter
*/
public WideCommunityParameter parameter() {
return parameter;
}
/**
* Sets wide community parameter.
*
* @param parameter wide community parameter
*/
public void setParameter(WideCommunityParameter parameter) {
this.parameter = parameter;
}
@Override
public int hashCode() {
return Objects.hash(wideCommunityHeader, community, localAsn, contextAsn, target, excludeTarget, parameter);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof WideCommunity) {
WideCommunity other = (WideCommunity) obj;
return Objects.equals(wideCommunityHeader, other.wideCommunityHeader)
&& Objects.equals(community, other.community) && Objects.equals(localAsn, other.localAsn)
&& Objects.equals(contextAsn, other.contextAsn) && Objects.equals(target, other.target)
&& Objects.equals(excludeTarget, other.excludeTarget) && Objects.equals(parameter, other.parameter);
}
return false;
}
@Override
public int write(ChannelBuffer c) {
int iTargetLenIndex;
int length;
int iLenStartIndex = c.writerIndex();
c.writeByte(FLAGS); // TODO: update flag value
c.writeByte(TYPE);
int iLengthIndex = c.writerIndex();
c.writeShort(0);
wideCommunityHeader.write(c);
int iComLengthIndex = c.writerIndex();
c.writeShort(0);
c.writeInt(community);
c.writeInt(localAsn);
c.writeInt(contextAsn);
if (target() != null) {
c.writeByte(WideCommunityTarget.TYPE);
iTargetLenIndex = c.writerIndex();
c.writeShort(0); // length
target.write(c);
length = c.writerIndex() - iTargetLenIndex;
c.setShort(iTargetLenIndex, (short) (length - 2));
}
if (excludeTarget() != null) {
c.writeByte(WideCommunityExcludeTarget.TYPE);
iTargetLenIndex = c.writerIndex();
c.writeShort(0); // length
excludeTarget.write(c);
length = c.writerIndex() - iTargetLenIndex;
c.setShort(iTargetLenIndex, (short) (length - 2));
}
if (parameter() != null) {
c.writeByte(WideCommunityParameter.TYPE);
iTargetLenIndex = c.writerIndex();
c.writeShort(0); // length
parameter.write(c);
length = c.writerIndex() - iTargetLenIndex;
c.setShort(iTargetLenIndex, (short) (length - 2));
}
length = c.writerIndex() - iComLengthIndex;
c.setShort(iComLengthIndex, (short) (length - 2));
length = c.writerIndex() - iLengthIndex;
c.setShort(iLengthIndex, (short) (length - 2));
return c.writerIndex() - iLenStartIndex;
}
/**
* Reads the wide community attribute.
*
* @param c ChannelBuffer
* @return object of WideCommunityAttr
* @throws BgpParseException while parsing BgpPrefixAttrRouteTag
*/
public static WideCommunity read(ChannelBuffer c) throws BgpParseException {
WideCommunityAttrHeader wideCommunityHeader;
int community;
int localAsn;
int contextAsn;
WideCommunityTarget target = null;
WideCommunityExcludeTarget excludeTarget = null;
WideCommunityParameter parameter = null;
short length = c.readShort();
if (c.readableBytes() < length) {
Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR, length);
}
wideCommunityHeader = WideCommunityAttrHeader.read(c);
if ((c.readableBytes() < 12) || (c.readableBytes() < wideCommunityHeader.length())) {
Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR, length);
}
community = c.readInt();
localAsn = c.readInt();
contextAsn = c.readInt();
while (c.readableBytes() > 0) {
if (c.readableBytes() < TYPE_LENGTH_SIZE) {
Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR,
c.readableBytes());
}
byte type = c.readByte();
length = c.readShort();
if (c.readableBytes() < length) {
Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR,
c.readableBytes());
}
if (type == WideCommunityTarget.TYPE) {
target = WideCommunityTarget.read(c);
} else if (type == WideCommunityExcludeTarget.TYPE) {
excludeTarget = WideCommunityExcludeTarget.read(c);
} else if (type == WideCommunityParameter.TYPE) {
parameter = WideCommunityParameter.read(c);
}
}
return new WideCommunity(wideCommunityHeader, community, localAsn, contextAsn,
target, excludeTarget, parameter);
}
/**
* Encode wide community target(s).
*
* @param c channel buffer
* @param targetTlv wide community include/exclude target
*/
public static void encodeWideCommunityTlv(ChannelBuffer c,
List<BgpValueType> targetTlv) {
/*
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| IPV4Neig(8) | Length: 8 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| local 10101010 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| remote 10101010 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* */
List<BgpValueType> target = targetTlv;
if (target == null) {
log.debug("target is null");
return;
}
Iterator<BgpValueType> listIterator = targetTlv.iterator();
while (listIterator.hasNext()) {
BgpValueType attr = listIterator.next();
if (attr instanceof WideCommunityIpV4Neighbour) {
WideCommunityIpV4Neighbour ipv4Neig = (WideCommunityIpV4Neighbour) attr;
ipv4Neig.write(c);
} else if (attr instanceof WideCommunityInteger) {
WideCommunityInteger integer = (WideCommunityInteger) attr;
integer.write(c);
}
}
return;
}
/**
* Decode wide community target(s).
*
* @param c channel buffer
* @return target list
* @throws BgpParseException on decode error
*/
public static List<BgpValueType> decodeWideCommunityTlv(ChannelBuffer c) throws BgpParseException {
List<BgpValueType> targetTlv = new ArrayList<>();
while (c.readableBytes() > 0) {
if (c.readableBytes() < TYPE_LENGTH_SIZE) {
Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR,
c.readableBytes());
}
byte atomType = c.readByte();
short atomLength = c.readShort();
if (c.readableBytes() < atomLength) {
Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR,
atomLength);
}
if (atomType == WideCommunityIpV4Neighbour.TYPE) {
ChannelBuffer tempBuf = c.readBytes(atomLength);
WideCommunityIpV4Neighbour wideCommAtom = new WideCommunityIpV4Neighbour();
while (tempBuf.readableBytes() > 0) {
wideCommAtom.add(IpAddress.valueOf(tempBuf.readInt()),
IpAddress.valueOf(tempBuf.readInt()));
}
targetTlv.add(wideCommAtom);
} else if (atomType == WideCommunityInteger.TYPE) {
ChannelBuffer tempBuf = c.readBytes(atomLength);
List<Integer> integer = new ArrayList<>();
while (tempBuf.readableBytes() > 0) {
integer.add(tempBuf.readInt());
}
targetTlv.add(new WideCommunityInteger(integer));
} else {
Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.MALFORMED_ATTRIBUTE_LIST,
atomLength);
}
}
return targetTlv;
}
@Override
public short getType() {
return TYPE;
}
@Override
public int compareTo(Object o) {
// TODO:
return 0;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.omitNullValues()
.add("FLAGS", FLAGS)
.add("wideCommunityHeader", wideCommunityHeader)
.add("community", community)
.add("localAsn", localAsn)
.add("contextAsn", contextAsn)
.add("target", target)
.add("excludeTarget", excludeTarget)
.add("parameter", parameter).toString();
}
}