/* * Copyright 2015-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.protocol.linkstate; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Objects; import org.jboss.netty.buffer.ChannelBuffer; import org.onosproject.bgpio.exceptions.BgpParseException; import org.onosproject.bgpio.types.BgpErrorType; import org.onosproject.bgpio.types.BgpValueType; import org.onosproject.bgpio.types.IPv4AddressTlv; import org.onosproject.bgpio.types.IPv6AddressTlv; import org.onosproject.bgpio.types.LinkLocalRemoteIdentifiersTlv; import org.onosproject.bgpio.types.attr.BgpAttrNodeMultiTopologyId; import org.onosproject.bgpio.util.Constants; import org.onosproject.bgpio.util.UnSupportedAttribute; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.MoreObjects; import com.google.common.base.Preconditions; /** * Implementation of local node descriptors, remote node descriptors and link descriptors. */ public class BgpLinkLSIdentifier implements Comparable<Object> { private static final Logger log = LoggerFactory.getLogger(BgpLinkLSIdentifier.class); public static final short IPV4_INTERFACE_ADDRESS_TYPE = 259; public static final short IPV4_NEIGHBOR_ADDRESS_TYPE = 260; public static final short IPV6_INTERFACE_ADDRESS_TYPE = 261; public static final short IPV6_NEIGHBOR_ADDRESS_TYPE = 262; private NodeDescriptors localNodeDescriptors; private NodeDescriptors remoteNodeDescriptors; private List<BgpValueType> linkDescriptor; /** * Initialize fields. */ public BgpLinkLSIdentifier() { this.localNodeDescriptors = null; this.remoteNodeDescriptors = null; this.linkDescriptor = null; } /** * Constructors to initialize parameters. * * @param localNodeDescriptors local node descriptors * @param remoteNodeDescriptors remote node descriptors * @param linkDescriptor link descriptors */ public BgpLinkLSIdentifier(NodeDescriptors localNodeDescriptors, NodeDescriptors remoteNodeDescriptors, LinkedList<BgpValueType> linkDescriptor) { this.localNodeDescriptors = Preconditions.checkNotNull(localNodeDescriptors); this.remoteNodeDescriptors = Preconditions.checkNotNull(remoteNodeDescriptors); this.linkDescriptor = Preconditions.checkNotNull(linkDescriptor); } /** * Reads channel buffer and parses link identifier. * * @param cb ChannelBuffer * @param protocolId in linkstate nlri * @return object of BGPLinkLSIdentifier * @throws BgpParseException while parsing link identifier */ public static BgpLinkLSIdentifier parseLinkIdendifier(ChannelBuffer cb, byte protocolId) throws BgpParseException { log.debug("Parse local node descriptor"); NodeDescriptors localNodeDescriptors = new NodeDescriptors(); localNodeDescriptors = parseNodeDescriptors(cb, NodeDescriptors.LOCAL_NODE_DES_TYPE, protocolId); log.debug("Parse remote node descriptor"); NodeDescriptors remoteNodeDescriptors = new NodeDescriptors(); remoteNodeDescriptors = parseNodeDescriptors(cb, NodeDescriptors.REMOTE_NODE_DES_TYPE, protocolId); log.debug("Parse link descriptor"); LinkedList<BgpValueType> linkDescriptor = new LinkedList<>(); linkDescriptor = parseLinkDescriptors(cb); return new BgpLinkLSIdentifier(localNodeDescriptors, remoteNodeDescriptors, linkDescriptor); } /** * Parses Local/Remote node descriptors. * * @param cb ChannelBuffer * @param desType descriptor type * @param protocolId protocol identifier * @return object of NodeDescriptors * @throws BgpParseException while parsing Local/Remote node descriptors */ public static NodeDescriptors parseNodeDescriptors(ChannelBuffer cb, short desType, byte protocolId) throws BgpParseException { log.debug("Parse node descriptors"); ChannelBuffer tempBuf = cb.copy(); short type = cb.readShort(); short length = cb.readShort(); if (cb.readableBytes() < length) { throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.OPTIONAL_ATTRIBUTE_ERROR, tempBuf.readBytes(cb.readableBytes() + Constants.TYPE_AND_LEN_AS_SHORT)); } NodeDescriptors nodeIdentifier = new NodeDescriptors(); ChannelBuffer tempCb = cb.readBytes(length); if (type == desType) { nodeIdentifier = NodeDescriptors.read(tempCb, length, desType, protocolId); } else { throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.MALFORMED_ATTRIBUTE_LIST, null); } return nodeIdentifier; } /** * Parses link descriptors. * * @param cb ChannelBuffer * @return list of link descriptors * @throws BgpParseException while parsing link descriptors */ public static LinkedList<BgpValueType> parseLinkDescriptors(ChannelBuffer cb) throws BgpParseException { LinkedList<BgpValueType> linkDescriptor = new LinkedList<>(); BgpValueType tlv = null; int count = 0; while (cb.readableBytes() > 0) { ChannelBuffer tempBuf = cb.copy(); short type = cb.readShort(); short length = cb.readShort(); if (cb.readableBytes() < length) { throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.OPTIONAL_ATTRIBUTE_ERROR, tempBuf.readBytes(cb.readableBytes() + Constants.TYPE_AND_LEN_AS_SHORT)); } ChannelBuffer tempCb = cb.readBytes(length); switch (type) { case LinkLocalRemoteIdentifiersTlv.TYPE: tlv = LinkLocalRemoteIdentifiersTlv.read(tempCb); break; case IPV4_INTERFACE_ADDRESS_TYPE: tlv = IPv4AddressTlv.read(tempCb, IPV4_INTERFACE_ADDRESS_TYPE); break; case IPV4_NEIGHBOR_ADDRESS_TYPE: tlv = IPv4AddressTlv.read(tempCb, IPV4_NEIGHBOR_ADDRESS_TYPE); break; case IPV6_INTERFACE_ADDRESS_TYPE: tlv = IPv6AddressTlv.read(tempCb, IPV6_INTERFACE_ADDRESS_TYPE); break; case IPV6_NEIGHBOR_ADDRESS_TYPE: tlv = IPv6AddressTlv.read(tempCb, IPV6_NEIGHBOR_ADDRESS_TYPE); break; case BgpAttrNodeMultiTopologyId.ATTRNODE_MULTITOPOLOGY: tlv = BgpAttrNodeMultiTopologyId.read(tempCb); count++; log.debug("MultiTopologyId TLV cannot repeat more than once"); if (count > 1) { //length + 4 implies data contains type, length and value throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.OPTIONAL_ATTRIBUTE_ERROR, tempBuf.readBytes(length + Constants.TYPE_AND_LEN_AS_SHORT)); } break; default: UnSupportedAttribute.skipBytes(tempCb, length); } linkDescriptor.add(tlv); } return linkDescriptor; } /** * Returns local node descriptors. * * @return local node descriptors */ public NodeDescriptors localNodeDescriptors() { return this.localNodeDescriptors; } /** * Returns remote node descriptors. * * @return remote node descriptors */ public NodeDescriptors remoteNodeDescriptors() { return this.remoteNodeDescriptors; } /** * Returns link descriptors. * * @return link descriptors */ public List<BgpValueType> linkDescriptors() { return this.linkDescriptor; } @Override public int hashCode() { return Objects.hash(linkDescriptor, localNodeDescriptors, remoteNodeDescriptors); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof BgpLinkLSIdentifier) { int countObjSubTlv = 0; int countOtherSubTlv = 0; boolean isCommonSubTlv = true; BgpLinkLSIdentifier other = (BgpLinkLSIdentifier) obj; Iterator<BgpValueType> objListIterator = other.linkDescriptor.iterator(); countOtherSubTlv = other.linkDescriptor.size(); countObjSubTlv = linkDescriptor.size(); if (countObjSubTlv != countOtherSubTlv) { return false; } else { while (objListIterator.hasNext() && isCommonSubTlv) { BgpValueType subTlv = objListIterator.next(); if (linkDescriptor.contains(subTlv) && other.linkDescriptor.contains(subTlv)) { isCommonSubTlv = Objects.equals(linkDescriptor.get(linkDescriptor.indexOf(subTlv)), other.linkDescriptor.get(other.linkDescriptor.indexOf(subTlv))); } else { isCommonSubTlv = false; } } return isCommonSubTlv && Objects.equals(this.localNodeDescriptors, other.localNodeDescriptors) && Objects.equals(this.remoteNodeDescriptors, other.remoteNodeDescriptors); } } return false; } @Override public String toString() { return MoreObjects.toStringHelper(getClass()) .add("localNodeDescriptors", localNodeDescriptors) .add("remoteNodeDescriptors", remoteNodeDescriptors) .add("linkDescriptor", linkDescriptor) .toString(); } @Override public int compareTo(Object o) { if (this.equals(o)) { return 0; } boolean tlvFound = false; int result = this.localNodeDescriptors.compareTo(((BgpLinkLSIdentifier) o).localNodeDescriptors); if (result != 0) { return result; } else if (this.remoteNodeDescriptors.compareTo(((BgpLinkLSIdentifier) o).remoteNodeDescriptors) != 0) { return this.remoteNodeDescriptors.compareTo(((BgpLinkLSIdentifier) o).remoteNodeDescriptors); } else { int countOtherSubTlv = ((BgpLinkLSIdentifier) o).linkDescriptor.size(); int countObjSubTlv = linkDescriptor.size(); if (countOtherSubTlv != countObjSubTlv) { if (countOtherSubTlv > countObjSubTlv) { return 1; } else { return -1; } } ListIterator<BgpValueType> listIterator = linkDescriptor.listIterator(); while (listIterator.hasNext()) { BgpValueType tlv1 = listIterator.next(); for (BgpValueType tlv : ((BgpLinkLSIdentifier) o).linkDescriptor) { if (tlv.getType() == tlv1.getType()) { result = linkDescriptor.get(linkDescriptor.indexOf(tlv1)).compareTo( ((BgpLinkLSIdentifier) o).linkDescriptor.get(((BgpLinkLSIdentifier) o).linkDescriptor .indexOf(tlv))); if (result != 0) { return result; } tlvFound = true; break; } } if (!tlvFound) { return 1; } } } return 0; } }