/* * 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.protocol.flowspec; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Objects; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; import org.onosproject.bgpio.types.BgpFsDestinationPortNum; import org.onosproject.bgpio.types.BgpFsDestinationPrefix; import org.onosproject.bgpio.types.BgpFsDscpValue; import org.onosproject.bgpio.types.BgpFsFragment; import org.onosproject.bgpio.types.BgpFsIcmpCode; import org.onosproject.bgpio.types.BgpFsIcmpType; import org.onosproject.bgpio.types.BgpFsIpProtocol; import org.onosproject.bgpio.types.BgpFsPacketLength; import org.onosproject.bgpio.types.BgpFsPortNum; import org.onosproject.bgpio.types.BgpFsSourcePortNum; import org.onosproject.bgpio.types.BgpFsSourcePrefix; import org.onosproject.bgpio.types.BgpFsTcpFlags; import org.onosproject.bgpio.types.BgpValueType; import org.onosproject.bgpio.types.RouteDistinguisher; import org.onosproject.bgpio.util.Constants; import com.google.common.base.MoreObjects; /** * This Class stores flow specification components and action. */ public class BgpFlowSpecNlri { private List<BgpValueType> flowSpecComponents; private List<BgpValueType> fsActionTlv; private RouteDistinguisher routeDistinguisher; public static final short FLOW_SPEC_LEN = 240; /** * Flow specification details object constructor with the parameter. * * @param flowSpecComponents flow specification components */ public BgpFlowSpecNlri(List<BgpValueType> flowSpecComponents) { this.flowSpecComponents = flowSpecComponents; } /** * Flow specification details object constructor. * */ public BgpFlowSpecNlri() { } /** * Returns flow specification action tlv. * * @return flow specification action tlv */ public List<BgpValueType> fsActionTlv() { return this.fsActionTlv; } /** * Set flow specification action tlv. * * @param fsActionTlv flow specification action tlv */ public void setFsActionTlv(List<BgpValueType> fsActionTlv) { this.fsActionTlv = fsActionTlv; } /** * Returns route distinguisher for the flow specification components. * * @return route distinguisher for the flow specification components */ public RouteDistinguisher routeDistinguisher() { return this.routeDistinguisher; } /** * Set route distinguisher for flow specification component. * * @param routeDistinguisher route distinguisher */ public void setRouteDistinguiher(RouteDistinguisher routeDistinguisher) { this.routeDistinguisher = routeDistinguisher; } /** * Returns flow specification components. * * @return flow specification components */ public List<BgpValueType> flowSpecComponents() { return this.flowSpecComponents; } /** * Sets flow specification components. * * @param flowSpecComponents flow specification components */ public void setFlowSpecComponents(List<BgpValueType> flowSpecComponents) { this.flowSpecComponents = flowSpecComponents; } @Override public int hashCode() { return Objects.hash(flowSpecComponents); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof BgpFlowSpecNlri) { int countObjSubTlv = 0; int countOtherSubTlv = 0; boolean isCommonSubTlv = true; BgpFlowSpecNlri other = (BgpFlowSpecNlri) obj; Iterator<BgpValueType> objListIterator = other.flowSpecComponents.iterator(); countOtherSubTlv = other.flowSpecComponents.size(); countObjSubTlv = flowSpecComponents.size(); if (countObjSubTlv != countOtherSubTlv) { return false; } else { while (objListIterator.hasNext() && isCommonSubTlv) { BgpValueType subTlv = objListIterator.next(); if (flowSpecComponents.contains(subTlv) && other.flowSpecComponents.contains(subTlv)) { isCommonSubTlv = Objects.equals(flowSpecComponents.get(flowSpecComponents.indexOf(subTlv)), other.flowSpecComponents.get(other.flowSpecComponents.indexOf(subTlv))); } else { isCommonSubTlv = false; } } return isCommonSubTlv; } } return false; } /** * Write flow type to channel buffer. * * @param tlv flow type * @param cb channel buffer */ public static void writeFlowType(BgpValueType tlv, ChannelBuffer cb) { switch (tlv.getType()) { case Constants.BGP_FLOWSPEC_DST_PREFIX: BgpFsDestinationPrefix fsDstPrefix = (BgpFsDestinationPrefix) tlv; fsDstPrefix.write(cb); break; case Constants.BGP_FLOWSPEC_SRC_PREFIX: BgpFsSourcePrefix fsSrcPrefix = (BgpFsSourcePrefix) tlv; fsSrcPrefix.write(cb); break; case Constants.BGP_FLOWSPEC_IP_PROTO: BgpFsIpProtocol fsIpProtocol = (BgpFsIpProtocol) tlv; fsIpProtocol.write(cb); break; case Constants.BGP_FLOWSPEC_PORT: BgpFsPortNum fsPortNum = (BgpFsPortNum) tlv; fsPortNum.write(cb); break; case Constants.BGP_FLOWSPEC_DST_PORT: BgpFsDestinationPortNum fsDstPortNum = (BgpFsDestinationPortNum) tlv; fsDstPortNum.write(cb); break; case Constants.BGP_FLOWSPEC_SRC_PORT: BgpFsSourcePortNum fsSrcPortNum = (BgpFsSourcePortNum) tlv; fsSrcPortNum.write(cb); break; case Constants.BGP_FLOWSPEC_ICMP_TP: BgpFsIcmpType fsIcmpType = (BgpFsIcmpType) tlv; fsIcmpType.write(cb); break; case Constants.BGP_FLOWSPEC_ICMP_CD: BgpFsIcmpCode fsIcmpCode = (BgpFsIcmpCode) tlv; fsIcmpCode.write(cb); break; case Constants.BGP_FLOWSPEC_TCP_FLAGS: BgpFsTcpFlags fsTcpFlags = (BgpFsTcpFlags) tlv; fsTcpFlags.write(cb); break; case Constants.BGP_FLOWSPEC_PCK_LEN: BgpFsPacketLength fsPacketLen = (BgpFsPacketLength) tlv; fsPacketLen.write(cb); break; case Constants.BGP_FLOWSPEC_DSCP: BgpFsDscpValue fsDscpVal = (BgpFsDscpValue) tlv; fsDscpVal.write(cb); break; case Constants.BGP_FLOWSPEC_FRAGMENT: BgpFsFragment fsFragment = (BgpFsFragment) tlv; fsFragment.write(cb); break; default: break; } return; } /** * Update buffer with identical flow types. * * @param cb channel buffer * @param bgpFlowSpecNlri flow specification */ public static void updateBufferIdenticalFlowTypes(ChannelBuffer cb, BgpFlowSpecNlri bgpFlowSpecNlri) { List<BgpValueType> flowSpec = bgpFlowSpecNlri.flowSpecComponents(); ListIterator<BgpValueType> listIterator = flowSpec.listIterator(); while (listIterator.hasNext()) { ChannelBuffer flowSpecTmpBuff = ChannelBuffers.dynamicBuffer(); int tmpBuffStartIndx = flowSpecTmpBuff.writerIndex(); BgpValueType tlv = listIterator.next(); writeFlowType(tlv, flowSpecTmpBuff); /* RFC 5575: section 4, If the NLRI length value is smaller than 240 (0xf0 hex), the length field can be encoded as a single octet. Otherwise, it is encoded as an extended-length 2-octet values */ int len = flowSpecTmpBuff.writerIndex() - tmpBuffStartIndx; if (len >= FLOW_SPEC_LEN) { cb.writeShort(len); } else { cb.writeByte(len); } //Copy from bynamic buffer to channel buffer cb.writeBytes(flowSpecTmpBuff); } return; } /** * Update buffer with non-identical flow types. * * @param cb channel buffer * @param bgpFlowSpecNlri flow specification */ public static void updateBufferNonIdenticalFlowTypes(ChannelBuffer cb, BgpFlowSpecNlri bgpFlowSpecNlri) { ChannelBuffer flowSpecTmpBuff = ChannelBuffers.dynamicBuffer(); List<BgpValueType> flowSpec = bgpFlowSpecNlri.flowSpecComponents(); ListIterator<BgpValueType> listIterator = flowSpec.listIterator(); int tmpBuffStartIndx = flowSpecTmpBuff.writerIndex(); flowSpec = bgpFlowSpecNlri.flowSpecComponents(); listIterator = flowSpec.listIterator(); while (listIterator.hasNext()) { BgpValueType tlv = listIterator.next(); writeFlowType(tlv, flowSpecTmpBuff); } /* RFC 5575: section 4, If the NLRI length value is smaller than 240 (0xf0 hex), the length field can be encoded as a single octet. Otherwise, it is encoded as an extended-length 2-octet values */ int len = flowSpecTmpBuff.writerIndex() - tmpBuffStartIndx; if (len >= FLOW_SPEC_LEN) { cb.writeShort(len); } else { cb.writeByte(len); } //Copy from bynamic buffer to channel buffer cb.writeBytes(flowSpecTmpBuff); } @Override public String toString() { return MoreObjects.toStringHelper(getClass()) .add("flowSpecComponents", flowSpecComponents) .toString(); } }