/* * Copyright 2015 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.ver4; import java.util.LinkedList; import java.util.List; import org.jboss.netty.buffer.ChannelBuffer; import org.onlab.packet.IpPrefix; import org.onosproject.bgpio.exceptions.BGPParseException; import org.onosproject.bgpio.protocol.BGPMessageReader; import org.onosproject.bgpio.protocol.BGPType; import org.onosproject.bgpio.protocol.BgpUpdateMsg; import org.onosproject.bgpio.types.BGPErrorType; import org.onosproject.bgpio.types.BGPHeader; import org.onosproject.bgpio.util.Validation; import org.onosproject.bgpio.protocol.BGPVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.MoreObjects; /** * BGP Update Message: UPDATE messages are used to transfer routing information * between BGP peers. The information in the UPDATE message is used by core to * construct a graph */ public class BgpUpdateMsgVer4 implements BgpUpdateMsg { /* 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + + | | + + | Marker | + + | | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length | Type | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Withdrawn Routes Length (2 octets) | +-----------------------------------------------------+ | Withdrawn Routes (variable) | +-----------------------------------------------------+ | Total Path Attribute Length (2 octets) | +-----------------------------------------------------+ | Path Attributes (variable) | +-----------------------------------------------------+ | Network Layer Reachability Information (variable) | +-----------------------------------------------------+ REFERENCE : RFC 4271 */ protected static final Logger log = LoggerFactory .getLogger(BgpUpdateMsgVer4.class); public static final byte PACKET_VERSION = 4; //Withdrawn Routes Length(2) + Total Path Attribute Length(2) public static final int PACKET_MINIMUM_LENGTH = 4; public static final int BYTE_IN_BITS = 8; public static final int MIN_LEN_AFTER_WITHDRW_ROUTES = 2; public static final int MINIMUM_COMMON_HEADER_LENGTH = 19; public static final BGPType MSG_TYPE = BGPType.UPDATE; public static final BgpUpdateMsgVer4.Reader READER = new Reader(); private List withdrawnRoutes; private BgpPathAttributes bgpPathAttributes; private BGPHeader bgpHeader; private List nlri; /** * Constructor to initialize parameters for BGP Update message. * * @param bgpHeader in Update message * @param withdrawnRoutes withdrawn routes * @param bgpPathAttributes BGP Path attributes * @param nlri Network Layer Reachability Information */ public BgpUpdateMsgVer4(BGPHeader bgpHeader, List withdrawnRoutes, BgpPathAttributes bgpPathAttributes, List nlri) { this.bgpHeader = bgpHeader; this.withdrawnRoutes = withdrawnRoutes; this.bgpPathAttributes = bgpPathAttributes; this.nlri = nlri; } /** * Reader reads BGP Update Message from the channel buffer. */ static class Reader implements BGPMessageReader { @Override public BgpUpdateMsg readFrom(ChannelBuffer cb, BGPHeader bgpHeader) throws BGPParseException { if (cb.readableBytes() != (bgpHeader.getLength() - MINIMUM_COMMON_HEADER_LENGTH)) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.BAD_MESSAGE_LENGTH, bgpHeader.getLength()); } LinkedList withDrwRoutes = new LinkedList<>(); LinkedList nlri = new LinkedList<>(); BgpPathAttributes bgpPathAttributes = new BgpPathAttributes(); // Reading Withdrawn Routes Length Short withDrwLen = cb.readShort(); if (cb.readableBytes() < withDrwLen) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.MALFORMED_ATTRIBUTE_LIST, cb.readableBytes()); } ChannelBuffer tempCb = cb.readBytes(withDrwLen); if (withDrwLen != 0) { // Parsing WithdrawnRoutes withDrwRoutes = parseWithdrawnRoutes(tempCb); } if (cb.readableBytes() < MIN_LEN_AFTER_WITHDRW_ROUTES) { log.debug("Bgp Path Attribute len field not present"); throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.MALFORMED_ATTRIBUTE_LIST, null); } // Reading Total Path Attribute Length short totPathAttrLen = cb.readShort(); int len = withDrwLen + totPathAttrLen + PACKET_MINIMUM_LENGTH; if (len > bgpHeader.getLength()) { throw new BGPParseException(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.MALFORMED_ATTRIBUTE_LIST, null); } if (totPathAttrLen != 0) { // Parsing BGPPathAttributes if (cb.readableBytes() < totPathAttrLen) { Validation .validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.MALFORMED_ATTRIBUTE_LIST, cb.readableBytes()); } tempCb = cb.readBytes(totPathAttrLen); bgpPathAttributes = BgpPathAttributes.read(tempCb); } if (cb.readableBytes() > 0) { // Parsing NLRI nlri = parseNlri(cb); } return new BgpUpdateMsgVer4(bgpHeader, withDrwRoutes, bgpPathAttributes, nlri); } } /** * Parses NLRI from channel buffer. * * @param cb channelBuffer * @return list of IP Prefix * @throws BGPParseException while parsing NLRI */ public static LinkedList parseNlri(ChannelBuffer cb) throws BGPParseException { LinkedList nlri = new LinkedList<>(); while (cb.readableBytes() > 0) { int length = cb.readByte(); IpPrefix ipPrefix; if (length == 0) { byte[] prefix = new byte[] {0}; ipPrefix = Validation.bytesToPrefix(prefix, length); nlri.add(ipPrefix); } else { int len = length / BYTE_IN_BITS; int reminder = length % BYTE_IN_BITS; if (reminder > 0) { len = len + 1; } if (cb.readableBytes() < len) { Validation.validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.MALFORMED_ATTRIBUTE_LIST, cb.readableBytes()); } byte[] prefix = new byte[len]; cb.readBytes(prefix, 0, len); ipPrefix = Validation.bytesToPrefix(prefix, length); nlri.add(ipPrefix); } } return nlri; } /** * Parsing withdrawn routes from channel buffer. * * @param cb channelBuffer * @return list of IP prefix * @throws BGPParseException while parsing withdrawn routes */ public static LinkedList parseWithdrawnRoutes(ChannelBuffer cb) throws BGPParseException { LinkedList withDrwRoutes = new LinkedList<>(); while (cb.readableBytes() > 0) { int length = cb.readByte(); IpPrefix ipPrefix; if (length == 0) { byte[] prefix = new byte[] {0}; ipPrefix = Validation.bytesToPrefix(prefix, length); withDrwRoutes.add(ipPrefix); } else { int len = length / BYTE_IN_BITS; int reminder = length % BYTE_IN_BITS; if (reminder > 0) { len = len + 1; } if (cb.readableBytes() < len) { Validation .validateLen(BGPErrorType.UPDATE_MESSAGE_ERROR, BGPErrorType.MALFORMED_ATTRIBUTE_LIST, cb.readableBytes()); } byte[] prefix = new byte[len]; cb.readBytes(prefix, 0, len); ipPrefix = Validation.bytesToPrefix(prefix, length); withDrwRoutes.add(ipPrefix); } } return withDrwRoutes; } @Override public BGPVersion getVersion() { return BGPVersion.BGP_4; } @Override public BGPType getType() { return BGPType.UPDATE; } @Override public void writeTo(ChannelBuffer channelBuffer) throws BGPParseException { //Not to be implemented as of now } @Override public BgpPathAttributes bgpPathAttributes() { return this.bgpPathAttributes; } @Override public List withdrawnRoutes() { return withdrawnRoutes; } @Override public List nlri() { return nlri; } @Override public BGPHeader getHeader() { return this.bgpHeader; } @Override public String toString() { return MoreObjects.toStringHelper(getClass()) .omitNullValues() .add("bgpHeader", bgpHeader) .add("withDrawnRoutes", withdrawnRoutes) .add("nlri", nlri) .add("bgpPathAttributes", bgpPathAttributes) .toString(); } }