| /* |
| * 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(); |
| } |
| } |