blob: b9ee79a11bdb1796b18ffb0272b899e8ef88d80d [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 java.nio.ByteBuffer;
import java.util.function.BiPredicate;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.onlab.packet.BasePacket;
import org.onlab.packet.Deserializer;
import org.onosproject.bgpmonitoring.PerPeer;
import org.onosproject.bgpmonitoring.PeerType;
import org.onosproject.bgpmonitoring.BmpParseException;
import static com.google.common.base.Preconditions.checkState;
/**
* The per-peer header follows the common header for most BMP messages.
* The rest of the data in a BMP message is dependent on the Message
* Type field in the common header.
* <p>
* Peer Type (1 byte): Identifies the type of peer. Currently, three
* types of peers are identified:
* <p>
* * Peer Type = 0: Global Instance Peer
* * Peer Type = 1: RD Instance Peer
* * Peer Type = 2: Local Instance Peer
* <p>
* o Peer Flags (1 byte): These flags provide more information about
* the peer. The flags are defined as follows:
* <p>
* 0 1 2 3 4 5 6 7
* +-+-+-+-+-+-+-+-+
* |V|L|A| Reserved|
* +-+-+-+-+-+-+-+-+
* <p>
* * The V flag indicates that the Peer address is an IPv6 address.
* For IPv4 peers, this is set to 0.
* <p>
* The L flag, if set to 1, indicates that the message reflects
* the post-policy Adj-RIB-In (i.e., its path attributes reflect
* the application of inbound policy). It is set to 0 if the
* message reflects the pre-policy Adj-RIB-In. Locally sourced
* routes also carry an L flag of 1. See Section 5 for further
* detail. This flag has no significance when used with route
* mirroring messages.
* <p>
* * The A flag, if set to 1, indicates that the message is
* formatted using the legacy 2-byte AS_PATH format. If set to 0,
* the message is formatted using the 4-byte AS_PATH format
* [RFC6793]. A BMP speaker MAY choose to propagate the AS_PATH
* information as received from its peer, or it MAY choose to
* reformat all AS_PATH information into a 4-byte format
* regardless of how it was received from the peer. In the latter
* case, AS4_PATH or AS4_AGGREGATOR path attributes SHOULD NOT be
* sent in the BMP UPDATE message. This flag has no significance
* when used with route mirroring messages.
* <p>
* The remaining bits are reserved for future use. They MUST be
* transmitted as 0 and their values MUST be ignored on receipt.
* <p>
* Peer Distinguisher (8 bytes): Routers today can have multiple
* instances (example: Layer 3 Virtual Private Networks (L3VPNs)
* [RFC4364]). This field is present to distinguish peers that
* belong to one address domain from the other.
* <p>
* If the peer is a "Global Instance Peer", this field is zero-
* filled. If the peer is a "RD Instance Peer", it is set to the
* route distinguisher of the particular instance the peer belongs
* to. If the peer is a "Local Instance Peer", it is set to a
* unique, locally defined value. In all cases, the effect is that
* the combination of the Peer Type and Peer Distinguisher is
* sufficient to disambiguate peers for which other identifying
* information might overlap.
* <p>
* Peer Address: The remote IP address associated with the TCP
* session over which the encapsulated PDU was received. It is 4
* bytes long if an IPv4 address is carried in this field (with the
* 12 most significant bytes zero-filled) and 16 bytes long if an
* IPv6 address is carried in this field.
* <p>
* Peer AS: The Autonomous System number of the peer from which the
* encapsulated PDU was received. If a 16-bit AS number is stored in
* this field [RFC6793], it should be padded with zeroes in the 16
* most significant bits.
* <p>
* Timestamp: The time when the encapsulated routes were received
* (one may also think of this as the time when they were installed
* in the Adj-RIB-In), expressed in seconds and microseconds since
* midnight (zero hour), January 1, 1970 (UTC). If zero, the time is
* unavailable. Precision of the timestamp is implementation-
* dependent.
*/
public final class PerPeerPacket extends BasePacket implements PerPeer {
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Peer Type | Peer Flags |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Peer Distinguisher (present based on peer type) |
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Peer Address (16 bytes) |
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Peer AS |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Peer BGP ID |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp (seconds) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Timestamp (microseconds) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public static final int PEER_HEADER_MIN_LENGTH = 42;
public static final int PEER_DISTINGUISHER = 8;
public static final int IPV4_ADDRSZ = 4;
public static final int IPV6_ADDRSZ = 16;
private PeerType type;
private byte flags;
private byte[] peerDistinguisher;
private InetAddress peerAddress;
private int peerAs;
private String peerBgpId;
private int seconds;
private int microseconds;
private PerPeerPacket(Builder builder) {
this.type = builder.type;
this.flags = builder.flags;
this.peerDistinguisher = builder.peerDistinguisher;
this.peerAddress = builder.peerAddress;
this.peerAs = builder.peerAs;
this.peerBgpId = builder.peerBgpId;
this.seconds = builder.seconds;
this.microseconds = builder.microseconds;
}
@Override
public PeerType getType() {
return type;
}
@Override
public byte getFlag() {
return flags;
}
@Override
public byte[] getPeerDistinguisher() {
return peerDistinguisher;
}
@Override
public InetAddress getIntAddress() {
return peerAddress;
}
@Override
public int getPeerAs() {
return peerAs;
}
@Override
public String getPeerBgpId() {
return peerBgpId;
}
@Override
public int getSeconds() {
return seconds;
}
@Override
public int getMicroseconds() {
return microseconds;
}
@Override
public boolean isIpv6() {
return ((flags & 0x80) != 0x00);
}
/**
* Data deserializer function for BMP per peer header.
*
* @return data deserializer function
*/
public static Deserializer<PerPeerPacket> 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, PEER_HEADER_MIN_LENGTH)) {
throw new BmpParseException("Invalid bmp per peer header buffer size.");
}
Builder builder = new Builder();
return builder.type(PeerType.getType((int) bb.get()))
.flags(bb.get())
.peerDistinguisher(bb)
.peerAddress(bb)
.peerAs(bb.getInt())
.peerBgpId(bb.getInt())
.seconds(bb.getInt())
.microseconds(bb.getInt())
.build();
};
}
@Override
public byte[] serialize() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("flags", flags)
.add("type", type)
.add("peerAddress", peerAddress.getHostAddress())
.add("peerAs", peerAs)
.add("seconds", seconds)
.add("microseconds", microseconds)
.toString();
}
public static InetAddress toInetAddress(int length, ByteBuffer bb) {
byte[] address = new byte[length];
bb.get(address);
InetAddress ipAddress = null;
try {
ipAddress = InetAddress.getByAddress(address);
} catch (UnknownHostException ex) {
throw new BmpParseException(ex);
}
return ipAddress;
}
/**
* Builder for BMP per peer header.
*/
private static class Builder {
private PeerType type;
private byte flags;
private byte[] peerDistinguisher;
private InetAddress peerAddress;
private int peerAs;
private String peerBgpId;
private int seconds;
private int microseconds;
/**
* Setter bmp per peer header.
*
* @param perPeer bmp per peer header.
* @return this class builder.
*/
public Builder type(PeerType type) {
this.type = type;
return this;
}
/**
* Setter bmp per peer header flag.
*
* @param flags bmp peer per header flag.
* @return this class builder.
*/
public Builder flags(byte flags) {
this.flags = flags;
return this;
}
/**
* Setter bgp peer distinguisher.
*
* @param bb byte buffer.
* @return this class builder.
*/
public Builder peerDistinguisher(ByteBuffer bb) {
this.peerDistinguisher = new byte[PEER_DISTINGUISHER];
bb.get(peerDistinguisher);
return this;
}
/**
* Setter bgp peer address.
*
* @param bb byte buffer.
* @return this class builder.
*/
public Builder peerAddress(ByteBuffer bb) {
if ((flags & 0x80) != 0x00) {
this.peerAddress = toInetAddress(IPV6_ADDRSZ, bb);
} else {
bb.position(bb.position() + (IPV6_ADDRSZ - IPV4_ADDRSZ));
this.peerAddress = toInetAddress(IPV4_ADDRSZ, bb);
}
return this;
}
/**
* Setter bgp peer As.
*
* @param peerAs peer As.
* @return this class builder.
*/
public Builder peerAs(int peerAs) {
this.peerAs = peerAs;
return this;
}
/**
* Setter bgp router id.
*
* @param id bgp router id.
* @return this class builder.
*/
public Builder peerBgpId(int id) {
StringBuilder sb = new StringBuilder();
int result = 0;
for (int i = 0; i < 4; ++i) {
result = id >> (3 - i) * 8 & 0xff;
sb.append(result);
if (i != 3) {
sb.append(".");
}
}
this.peerBgpId = sb.toString();
return this;
}
/**
* Setter bmp per peer message sent time in seconds.
*
* @param seconds bmp per peer message sent time in seconds.
* @return this class builder.
*/
public Builder seconds(int seconds) {
this.seconds = seconds;
return this;
}
/**
* Setter bmp per peer message sent time in micro seconds.
*
* @param microseconds bmp per peer message sent time in micro seconds.
* @return this class builder.
*/
public Builder microseconds(int microseconds) {
this.microseconds = microseconds;
return this;
}
/**
* Checks arguments for bmp per peer header.
*/
private void checkArguments() {
checkState(type != null, "Invalid bmp per peer type.");
checkState(peerAddress != null, "Invalid bmp per peer address.");
}
/**
* Builds bmp per peer header.
*
* @return bmp per peer header.
*/
public PerPeerPacket build() {
checkArguments();
return new PerPeerPacket(this);
}
}
}