blob: 54f46c119cb37d44903d92962b09811dcc24fdd0 [file] [log] [blame]
/*
* Copyright 2024-present Open Networking Foundation
*
* 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.bgpmonitoring.type;
import com.google.common.base.MoreObjects;
import com.google.common.collect.Lists;
import java.util.List;
import java.util.Objects;
import java.util.stream.IntStream;
import java.util.function.BiPredicate;
import java.nio.ByteBuffer;
import org.onosproject.bgpmonitoring.StatsMessage;
import org.onosproject.bgpmonitoring.BmpStats;
import org.onosproject.bgpmonitoring.PerPeer;
import org.onosproject.bgpmonitoring.BmpParseException;
import org.onlab.packet.DeserializationException;
import org.onlab.packet.Deserializer;
import static com.google.common.base.Preconditions.checkState;
/**
* An ongoing dump of statistics that can be used
* by the monitoring station as a high-level indication of the
* activity going on in the router.
* <p>
* These messages contain information that could be used by the
* monitoring station to observe interesting events that occur on the
* router.
* <p>
* Transmission of SR messages could be timer triggered or event driven
* (for example, when a significant event occurs or a threshold is
* reached). This specification does not impose any timing restrictions
* on when and on what event these reports have to be transmitted. It
* is left to the implementation to determine transmission timings --
* however, configuration control should be provided of the timer and/or
* threshold values. This document only specifies the form and content
* of SR messages.
* <p>
* Following the common BMP header and per-peer header is a 4-byte field
* that indicates the number of counters in the stats message where each
* counter is encoded as a TLV.
* <p>
* Stat Type = 1: (32-bit Counter) Number of (known) duplicate prefix
* advertisements.
* <p>
* Stat Type = 2: (32-bit Counter) Number of (known) duplicate
* withdraws.
* <p>
* Stat Type = 3: (32-bit Counter) Number of updates invalidated due
* to CLUSTER_LIST loop.
* <p>
* Stat Type = 4: (32-bit Counter) Number of updates invalidated due
* to AS_PATH loop.
* <p>
* Stat Type = 5: (32-bit Counter) Number of updates invalidated due
* to ORIGINATOR_ID.
* <p>
* Stat Type = 6: (32-bit Counter) Number of updates invalidated due
* to AS_CONFED loop.
* <p>
* Stat Type = 7: (64-bit Gauge) Number of routes in Adj-RIBs-In.
* <p>
* Stat Type = 8: (64-bit Gauge) Number of routes in Loc-RIB.
* <p>
* Stat Type = 9: Number of routes in per-AFI/SAFI Adj-RIB-In. The
* value is structured as: 2-byte Address Family Identifier (AFI),
* 1-byte Subsequent Address Family Identifier (SAFI), followed by a
* 64-bit Gauge.
* <p>
* Stat Type = 10: Number of routes in per-AFI/SAFI Loc-RIB. The
* value is structured as: 2-byte AFI, 1-byte SAFI, followed by a
* 64-bit Gauge.
* <p>
* Stat Type = 11: (32-bit Counter) Number of updates subjected to
* treat-as-withdraw treatment [RFC7606].
* <p>
* Stat Type = 12: (32-bit Counter) Number of prefixes subjected to
* treat-as-withdraw treatment [RFC7606].
* <p>
* Stat Type = 13: (32-bit Counter) Number of duplicate update
* messages received.
* <p>
* Although the current specification only specifies 4-byte counters and
* 8-byte gauges as "Stat Data", this does not preclude future versions
* from incorporating more complex TLV-type "Stat Data" (for example,
* one that can carry prefix-specific data). SR messages are optional.
* However, if an SR message is transmitted, at least one statistic MUST
* be carried in it.
*/
public final class BmpStatsReport extends StatsMessage {
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stats Count |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Each counter is encoded as follows:
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stat Type | Stat Len |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Stat Data |
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
private PerPeer perPeer;
private int statsCount;
private List<BmpStats> stats;
private BmpStatsReport(Builder builder) {
this.perPeer = builder.perPeer;
this.statsCount = builder.statsCount;
this.stats = builder.stats;
}
/**
* Returns number of BMP statistics records.
*
* @return number of BMP statistics records
*/
public int getStatsCount() {
return statsCount;
}
/**
* Returns BGP statistics.
*
* @return BGP statistics
*/
public List<BmpStats> getStats() {
return stats;
}
/**
* Returns BMP Peer Header of BMP Message.
*
* @return BMP Peer Header of BMP Message
*/
@Override
public PerPeer getPerPeer() {
return perPeer;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BmpStatsReport that = (BmpStatsReport) o;
return statsCount == that.statsCount &&
Objects.equals(stats, that.stats);
}
@Override
public int hashCode() {
return Objects.hash(statsCount, stats);
}
/**
* Data deserializer function for BMP statistics.
*
* @return data deserializer function
*/
public static Deserializer<BmpStatsReport> deserializer() {
return (data, offset, length) -> {
BiPredicate<ByteBuffer, Integer> isValidBuffer = (b, l)
-> b.hasRemaining() && b.remaining() >= l;
ByteBuffer bb = ByteBuffer.wrap(data, offset, length);
if (!isValidBuffer.test(bb,
STATS_REPORT_HEADER_MIN_LENGTH +
PerPeerPacket.PEER_HEADER_MIN_LENGTH +
BmpStatistics.STATISTICS_HEADER_MIN_LENGTH)) {
throw new BmpParseException("Invalid bmp statistics message buffer size.");
}
byte[] perPeer = new byte[PerPeerPacket.PEER_HEADER_MIN_LENGTH];
bb.get(perPeer);
Builder builder = new Builder()
.perPeer(PerPeerPacket.deserializer().deserialize(perPeer,
0, PerPeerPacket.PEER_HEADER_MIN_LENGTH))
.statsCount(bb.getInt());
IntStream.range(0, builder.statsCount)
.forEach(index -> {
if (bb.hasRemaining()) {
int statsType = bb.getShort();
int newLength = bb.getShort();
bb.position(bb.position() - BmpStatistics.STATISTICS_HEADER_MIN_LENGTH);
int statsLength = newLength + BmpStatistics.STATISTICS_HEADER_MIN_LENGTH;
if (bb.remaining() < statsLength) {
throw new BmpParseException("Invalid bmp statistics message buffer size.");
}
byte[] statsBytes = new byte[statsLength];
bb.get(statsBytes);
try {
builder.stats((BmpStats) BmpStatistics.deserializer()
.deserialize(statsBytes, 0, statsLength));
} catch (DeserializationException ex) {
throw new BmpParseException(ex);
}
}
});
return builder.build();
};
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("perPeer", perPeer)
.add("statsCount", statsCount)
.add("stats", stats)
.toString();
}
/**
* Builder for BMP statistics message.
*/
private static class Builder {
private PerPeer perPeer;
private int statsCount;
private List<BmpStats> stats = Lists.newArrayList();
/**
* Setter bmp per peer header.
*
* @param perPeer bmp per peer header.
* @return this class builder.
*/
public Builder perPeer(PerPeer perPeer) {
this.perPeer = perPeer;
return this;
}
/**
* Setter bmp statistics record count.
*
* @param statsCount bmp statistics record count.
* @return this class builder.
*/
public Builder statsCount(int statsCount) {
this.statsCount = statsCount;
return this;
}
/**
* Setter bmp statistics records.
*
* @param stats bmp statistics records.
* @return this class builder.
*/
public Builder stats(List<BmpStats> stats) {
this.stats = stats;
return this;
}
/**
* Setter bmp statistics record.
*
* @param stats bmp statistics record.
* @return this class builder.
*/
public Builder stats(BmpStats stats) {
this.stats.add(stats);
return this;
}
/**
* Checks arguments for bmp statistics record.
*/
private void checkArguments() {
checkState(perPeer != null, "Invalid bmp statistics per peer buffer.");
checkState(statsCount != 0, "Invalid bmp statistics records.");
}
/**
* Builds BMP statistics message.
*
* @return BMP statistics message.
*/
public BmpStatsReport build() {
checkArguments();
return new BmpStatsReport(this);
}
}
}