/* * 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.types; import java.net.InetAddress; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import org.jboss.netty.buffer.ChannelBuffer; import org.onlab.packet.Ip4Address; import org.onosproject.bgpio.exceptions.BgpParseException; import org.onosproject.bgpio.protocol.BgpLSNlri; import org.onosproject.bgpio.protocol.flowspec.BgpFlowSpecNlri; import org.onosproject.bgpio.protocol.linkstate.BgpPrefixIPv4LSNlriVer4; import org.onosproject.bgpio.protocol.linkstate.BgpNodeLSNlriVer4; import org.onosproject.bgpio.protocol.linkstate.BgpLinkLsNlriVer4; import org.onosproject.bgpio.util.Constants; import org.onosproject.bgpio.util.Validation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.MoreObjects; /* * Provides Implementation of MpReach Nlri BGP Path Attribute. */ public class MpReachNlri implements BgpValueType { private static final Logger log = LoggerFactory.getLogger(MpReachNlri.class); public static final byte MPREACHNLRI_TYPE = 14; public static final byte LINK_NLRITYPE = 2; public static final byte FLAGS = (byte) 0x90; private boolean isMpReachNlri = false; private final List<BgpLSNlri> mpReachNlri; private final int length; private final short afi; private final byte safi; private final Ip4Address ipNextHop; private BgpFlowSpecNlri bgpFlowSpecNlri; /** * Constructor to initialize parameters. * * @param mpReachNlri MpReach Nlri attribute * @param afi address family identifier * @param safi subsequent address family identifier * @param ipNextHop nexthop IpAddress * @param length of MpReachNlri */ public MpReachNlri(List<BgpLSNlri> mpReachNlri, short afi, byte safi, Ip4Address ipNextHop, int length) { this.mpReachNlri = mpReachNlri; this.isMpReachNlri = true; this.ipNextHop = ipNextHop; this.afi = afi; this.safi = safi; this.length = length; } public MpReachNlri(BgpFlowSpecNlri bgpFlowSpecNlri, short afi, byte safi) { this.mpReachNlri = null; this.isMpReachNlri = true; this.length = 0; this.ipNextHop = null; this.bgpFlowSpecNlri = bgpFlowSpecNlri; this.afi = afi; this.safi = safi; } /** * Returns whether MpReachNlri is present. * * @return whether MpReachNlri is present */ public boolean isMpReachNlriSet() { return this.isMpReachNlri; } /** * Returns list of MpReach Nlri. * * @return list of MpReach Nlri */ public List<BgpLSNlri> mpReachNlri() { return this.mpReachNlri; } /** * Returns length of MpReachNlri. * * @return length of MpReachNlri */ public int mpReachNlriLen() { return this.length; } /** * Returns BGP flow specification info. * * @return BGP flow specification info */ public BgpFlowSpecNlri bgpFlowSpecNlri() { return this.bgpFlowSpecNlri; } /** * Reads from ChannelBuffer and parses MpReachNlri. * * @param cb channelBuffer * @return object of MpReachNlri * @throws BgpParseException while parsing MpReachNlri */ public static MpReachNlri read(ChannelBuffer cb) throws BgpParseException { ChannelBuffer tempBuf = cb.copy(); Validation parseFlags = Validation.parseAttributeHeader(cb); int len = parseFlags.isShort() ? parseFlags.getLength() + Constants.TYPE_AND_LEN_AS_SHORT : parseFlags.getLength() + Constants.TYPE_AND_LEN_AS_BYTE; ChannelBuffer data = tempBuf.readBytes(len); if (cb.readableBytes() < parseFlags.getLength()) { Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR, parseFlags.getLength()); } if (!parseFlags.getFirstBit() && parseFlags.getSecondBit() && parseFlags.getThirdBit()) { throw new BgpParseException(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_FLAGS_ERROR, data); } BgpLSNlri bgpLSNlri = null; List<BgpLSNlri> mpReachNlri = new LinkedList<>(); ChannelBuffer tempCb = cb.readBytes(parseFlags.getLength()); short afi = 0; byte safi = 0; Ip4Address ipNextHop = null; while (tempCb.readableBytes() > 0) { afi = tempCb.readShort(); safi = tempCb.readByte(); //Supporting for AFI 16388 / SAFI 71 and VPN AFI 16388 / SAFI 128 if ((afi == Constants.AFI_VALUE) && (safi == Constants.SAFI_VALUE) || (afi == Constants.AFI_VALUE) && (safi == Constants.VPN_SAFI_VALUE)) { byte nextHopLen = tempCb.readByte(); InetAddress ipAddress = Validation.toInetAddress(nextHopLen, tempCb); if (ipAddress.isMulticastAddress()) { throw new BgpParseException("Multicast not supported"); } ipNextHop = Ip4Address.valueOf(ipAddress); byte reserved = tempCb.readByte(); while (tempCb.readableBytes() > 0) { short nlriType = tempCb.readShort(); short totNlriLen = tempCb.readShort(); if (tempCb.readableBytes() < totNlriLen) { Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR, totNlriLen); } tempBuf = tempCb.readBytes(totNlriLen); switch (nlriType) { case BgpNodeLSNlriVer4.NODE_NLRITYPE: bgpLSNlri = BgpNodeLSNlriVer4.read(tempBuf, afi, safi); break; case BgpLinkLsNlriVer4.LINK_NLRITYPE: bgpLSNlri = BgpLinkLsNlriVer4.read(tempBuf, afi, safi); break; case BgpPrefixIPv4LSNlriVer4.PREFIX_IPV4_NLRITYPE: bgpLSNlri = BgpPrefixIPv4LSNlriVer4.read(tempBuf, afi, safi); break; default: log.debug("nlriType not supported" + nlriType); } mpReachNlri.add(bgpLSNlri); } } else if ((afi == Constants.AFI_FLOWSPEC_VALUE) && ((safi == Constants.SAFI_FLOWSPEC_VALUE) || (safi == Constants.VPN_SAFI_FLOWSPEC_VALUE))) { List<BgpValueType> flowSpecComponents = new LinkedList<>(); RouteDistinguisher routeDistinguisher = null; if (tempCb.readableBytes() > 0) { BgpValueType flowSpecComponent = null; byte nextHopLen = tempCb.readByte(); if (nextHopLen > 0) { InetAddress ipAddress = Validation.toInetAddress(nextHopLen, tempCb); if (ipAddress.isMulticastAddress()) { throw new BgpParseException("Multicast not supported"); } ipNextHop = Ip4Address.valueOf(ipAddress); } byte reserved = tempCb.readByte(); if (safi == Constants.VPN_SAFI_FLOWSPEC_VALUE) { routeDistinguisher = new RouteDistinguisher(); routeDistinguisher = RouteDistinguisher.read(tempCb); } while (tempCb.readableBytes() > 0) { short totNlriLen = tempCb.getUnsignedByte(tempCb.readerIndex()); if (totNlriLen >= BgpFlowSpecNlri.FLOW_SPEC_LEN) { if (tempCb.readableBytes() < 2) { Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR, totNlriLen); } totNlriLen = tempCb.readShort(); } else { totNlriLen = tempCb.readByte(); } if (tempCb.readableBytes() < totNlriLen) { Validation.validateLen(BgpErrorType.UPDATE_MESSAGE_ERROR, BgpErrorType.ATTRIBUTE_LENGTH_ERROR, totNlriLen); } tempBuf = tempCb.readBytes(totNlriLen); while (tempBuf.readableBytes() > 0) { short type = tempBuf.readByte(); switch (type) { case Constants.BGP_FLOWSPEC_DST_PREFIX: flowSpecComponent = BgpFsDestinationPrefix.read(tempBuf); break; case Constants.BGP_FLOWSPEC_SRC_PREFIX: flowSpecComponent = BgpFsSourcePrefix.read(tempBuf); break; case Constants.BGP_FLOWSPEC_IP_PROTO: flowSpecComponent = BgpFsIpProtocol.read(tempBuf); break; case Constants.BGP_FLOWSPEC_PORT: flowSpecComponent = BgpFsPortNum.read(tempBuf); break; case Constants.BGP_FLOWSPEC_DST_PORT: flowSpecComponent = BgpFsDestinationPortNum.read(tempBuf); break; case Constants.BGP_FLOWSPEC_SRC_PORT: flowSpecComponent = BgpFsSourcePortNum.read(tempBuf); break; case Constants.BGP_FLOWSPEC_ICMP_TP: flowSpecComponent = BgpFsIcmpType.read(tempBuf); break; case Constants.BGP_FLOWSPEC_ICMP_CD: flowSpecComponent = BgpFsIcmpCode.read(tempBuf); break; case Constants.BGP_FLOWSPEC_TCP_FLAGS: flowSpecComponent = BgpFsTcpFlags.read(tempBuf); break; case Constants.BGP_FLOWSPEC_PCK_LEN: flowSpecComponent = BgpFsPacketLength.read(tempBuf); break; case Constants.BGP_FLOWSPEC_DSCP: flowSpecComponent = BgpFsDscpValue.read(tempBuf); break; case Constants.BGP_FLOWSPEC_FRAGMENT: flowSpecComponent = BgpFsFragment.read(tempBuf); break; default: log.debug("flow spec type not supported" + type); break; } flowSpecComponents.add(flowSpecComponent); } } } BgpFlowSpecNlri flowSpecDetails = new BgpFlowSpecNlri(flowSpecComponents); flowSpecDetails.setRouteDistinguiher(routeDistinguisher); return new MpReachNlri(flowSpecDetails, afi, safi); } else { throw new BgpParseException("Not Supporting afi " + afi + "safi " + safi); } } return new MpReachNlri(mpReachNlri, afi, safi, ipNextHop, parseFlags.getLength()); } @Override public short getType() { return MPREACHNLRI_TYPE; } /** * Returns AFI. * * @return AFI */ public short afi() { return this.afi; } /** * Returns Nexthop IpAddress. * * @return Nexthop IpAddress */ public Ip4Address nexthop4() { return this.ipNextHop; } /** * Returns SAFI. * * @return SAFI */ public byte safi() { return this.safi; } @Override public int write(ChannelBuffer cb) { int iLenStartIndex = cb.writerIndex(); if ((afi == Constants.AFI_FLOWSPEC_VALUE) && ((safi == Constants.SAFI_FLOWSPEC_VALUE) || (safi == Constants.VPN_SAFI_FLOWSPEC_VALUE))) { List<BgpValueType> flowSpec = bgpFlowSpecNlri.flowSpecComponents(); ListIterator<BgpValueType> listIterator = flowSpec.listIterator(); boolean isAllFlowTypesIdentical = true; cb.writeByte(FLAGS); cb.writeByte(MPREACHNLRI_TYPE); int mpReachDataIndx = cb.writerIndex(); cb.writeShort(0); cb.writeShort(afi); cb.writeByte(safi); //next hop address cb.writeByte(0); //sub network points of attachment cb.writeByte(0); if (bgpFlowSpecNlri.routeDistinguisher() != null) { cb.writeLong(bgpFlowSpecNlri.routeDistinguisher().getRouteDistinguisher()); } BgpValueType tlv1 = null; if (listIterator.hasNext()) { tlv1 = listIterator.next(); } while (listIterator.hasNext()) { BgpValueType tlv = listIterator.next(); if (tlv.getType() != tlv1.getType()) { isAllFlowTypesIdentical = false; break; } } if (isAllFlowTypesIdentical) { BgpFlowSpecNlri.updateBufferIdenticalFlowTypes(cb, bgpFlowSpecNlri()); } else { BgpFlowSpecNlri.updateBufferNonIdenticalFlowTypes(cb, bgpFlowSpecNlri()); } int fsNlriLen = cb.writerIndex() - mpReachDataIndx; cb.setShort(mpReachDataIndx, (short) (fsNlriLen - 2)); } return cb.writerIndex() - iLenStartIndex; } @Override public String toString() { return MoreObjects.toStringHelper(getClass()).omitNullValues() .add("mpReachNlri", mpReachNlri) .add("bgpFlowSpecNlri", bgpFlowSpecNlri) .add("afi", afi) .add("safi", safi) .add("ipNextHop", ipNextHop) .add("length", length) .toString(); } @Override public int compareTo(Object o) { // TODO Auto-generated method stub return 0; } }