blob: cba9f04e5ee8ac5d734183b12757f5915c40e957 [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.
*/
/*
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Local Address (16 bytes) |
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Local Port | Remote Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sent OPEN Message |
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Received OPEN Message |
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Information (variable) |
~ ~
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
package org.onosproject.bgpmonitoring.type;
import org.jboss.netty.buffer.ChannelBuffers;
import com.google.common.base.MoreObjects;
import org.onlab.packet.Deserializer;
import org.onosproject.bgpio.exceptions.BgpParseException;
import org.onosproject.bgpio.protocol.BgpMessage;
import org.onosproject.bgpio.protocol.ver4.BgpMessageVer4;
import org.onosproject.bgpio.types.BgpHeader;
import org.onosproject.bgpmonitoring.PeerUpNotificationMessage;
import org.onosproject.bgpmonitoring.BmpParseException;
import org.onosproject.bgpmonitoring.PerPeer;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.Objects;
import java.util.function.BiPredicate;
import java.nio.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.base.Preconditions.checkState;
/**
* A message sent to indicate that a peering
* session has come up. The message includes information regarding
* the data exchanged between the peers in their OPEN messages, as
* well as information about the peering TCP session itself. In
* addition to being sent whenever a peer transitions to the
* Established state, a Peer Up Notification is sent for each peer in
* the Established state when the BMP session itself comes up.
* <p>
* Local Address: The local IP address associated with the peering
* TCP session. It is 4 bytes long if an IPv4 address is carried in
* this field, as determined by the V flag (with the 12 most
* significant bytes zero-filled) and 16 bytes long if an IPv6
* address is carried in this field.
* <p>
* Local Port: The local port number associated with the peering TCP
* session, or 0 if no TCP session actually exists (see Section 8.2).
* <p>
* Remote Port: The remote port number associated with the peering
* TCP session, or 0 if no TCP session actually exists.
* <p>
* Sent OPEN Message: The full OPEN message transmitted by the
* monitored router to its peer.
* <p>
* Received OPEN Message: The full OPEN message received by the
* monitored router from its peer.
* Information: Information about the peer, using the Information TLV
* format. Only the string type is defined in this
* context; it may be repeated. Inclusion of the Information field
* is OPTIONAL. Its presence or absence can be inferred by
* inspection of the Message Length in the common header.
*/
public final class BmpPeerUpNotification extends PeerUpNotificationMessage {
private static final Logger log = LoggerFactory.getLogger(BmpPeerUpNotification.class);
private PerPeer perPeer;
private InetAddress localAddress;
private int localPort;
private int remotePort;
private BgpMessage sentOpenMsg;
private BgpMessage receivedOpenMsg;
private byte[] information;
private BmpPeerUpNotification(Builder builder) {
this.perPeer = builder.perPeer;
this.localAddress = builder.localAddress;
this.localPort = builder.localPort;
this.remotePort = builder.remotePort;
this.sentOpenMsg = builder.sentOpenMsg;
this.receivedOpenMsg = builder.receivedOpenMsg;
this.information = builder.information;
}
/**
* Returns BMP Peer Header of BMP Message.
*
* @return BMP Peer Header of BMP Message
*/
@Override
public PerPeer getPerPeer() {
return perPeer;
}
/**
* Returns local ip address.
*
* @return local ip address
*/
public InetAddress getLocalAddress() {
return localAddress;
}
/**
* Returns local port number.
*
* @return local port number
*/
public int getLocalPort() {
return localPort;
}
/**
* Returns remote port number.
*
* @return remote port number
*/
public int getRemotePort() {
return remotePort;
}
/**
* Returns Bgp sent open message.
*
* @return Bgp sent open message
*/
public BgpMessage getSentOpenMsg() {
return sentOpenMsg;
}
/**
* Returns Bgp received open message.
*
* @return Bgp received open message
*/
public BgpMessage getReceivedOpenMsg() {
return receivedOpenMsg;
}
/**
* Returns BMP peer information.
*
* @return BMP peer information
*/
public byte[] getInformation() {
return information;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BmpPeerUpNotification that = (BmpPeerUpNotification) o;
return localPort == that.localPort &&
remotePort == that.remotePort &&
Objects.equals(localAddress, that.localAddress) &&
Objects.equals(sentOpenMsg, that.sentOpenMsg) &&
Objects.equals(receivedOpenMsg, that.receivedOpenMsg) &&
Arrays.equals(information, that.information) &&
Objects.equals(perPeer, that.perPeer);
}
@Override
public int hashCode() {
int result = Objects.hash(localAddress, localPort, remotePort, sentOpenMsg,
receivedOpenMsg, perPeer);
result = 31 * result + Arrays.hashCode(information);
return result;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("perPeer", perPeer)
.add("localAddress", localAddress)
.add("localPort", localPort)
.add("remotePort", remotePort)
.add("sentOpenMsg", sentOpenMsg)
.add("receivedOpenMsg", receivedOpenMsg)
.add("information", Arrays.toString(information))
.toString();
}
/**
* Data deserializer function for BMP peer up notification message.
*
* @return data deserializer function
*/
public static Deserializer<BmpPeerUpNotification> 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, PEERUP_NOTIFICATION_HEADER_MIN_LENGTH +
PerPeerPacket.PEER_HEADER_MIN_LENGTH)) {
throw new BmpParseException("Invalid bmp peer up notification message buffer size.");
}
byte[] perPeerBytes = new byte[PerPeerPacket.PEER_HEADER_MIN_LENGTH];
bb.get(perPeerBytes);
Builder builder = new Builder()
.perPeer(PerPeerPacket.deserializer().deserialize(perPeerBytes,
0, PerPeerPacket.PEER_HEADER_MIN_LENGTH));
if (builder.perPeer.isIpv6()) {
builder.localAddress(PerPeerPacket.toInetAddress(IPV6_ADDRS, bb));
} else {
bb.position(bb.position() + (IPV6_ADDRS - IPV4_ADDRS));
builder.localAddress(PerPeerPacket.toInetAddress(IPV4_ADDRS, bb));
}
builder.localPort(bb.getShort())
.remotePort(bb.getShort());
if (bb.remaining() < (PADDING_BYTES + BGP_LENGTH_FIELD)) {
throw new BmpParseException("Invalid bmp peer up notification message buffer size.");
}
bb.position(bb.position() + PADDING_BYTES);
int msgLength = bb.getShort();
bb.position(bb.position() - (PADDING_BYTES + BGP_LENGTH_FIELD));
if (bb.remaining() < msgLength) {
throw new BmpParseException("Not enough readable bytes");
}
byte[] routeBytes = new byte[msgLength];
bb.get(routeBytes);
try {
builder.sentOpenMsg(BgpMessageVer4.READER.readFrom(ChannelBuffers.wrappedBuffer(routeBytes),
new BgpHeader()));
} catch (BgpParseException ex) {
throw new BmpParseException(ex);
}
if (bb.remaining() < (PADDING_BYTES + BGP_LENGTH_FIELD)) {
throw new BmpParseException("Not enough readable bytes");
}
bb.position(bb.position() + PADDING_BYTES);
msgLength = bb.getShort();
bb.position(bb.position() - (PADDING_BYTES + BGP_LENGTH_FIELD));
if (bb.remaining() < msgLength) {
throw new BmpParseException("Not enough readable bytes");
}
routeBytes = new byte[msgLength];
bb.get(routeBytes);
try {
builder.receivedOpenMsg(BgpMessageVer4.READER.readFrom(ChannelBuffers.wrappedBuffer(routeBytes),
new BgpHeader()));
} catch (BgpParseException ex) {
throw new BmpParseException(ex);
}
if (bb.remaining() > 0) {
byte[] information = new byte[bb.remaining()];
bb.get(information);
builder.information(information);
}
return builder.build();
};
}
/**
* Builder for BMP peer up notification message.
*/
private static class Builder {
private PerPeer perPeer;
private InetAddress localAddress;
private int localPort;
private int remotePort;
private BgpMessage sentOpenMsg;
private BgpMessage receivedOpenMsg;
private byte[] information;
/**
* 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 bgp local address.
*
* @param localAddress bgp local address.
* @return this class builder.
*/
public Builder localAddress(InetAddress localAddress) {
this.localAddress = localAddress;
return this;
}
/**
* Setter bgp local port.
*
* @param localPort bgp local port.
* @return this class builder.
*/
public Builder localPort(int localPort) {
this.localPort = localPort;
return this;
}
/**
* Setter bgp remote port.
*
* @param remotePort bgp remote port.
* @return this class builder.
*/
public Builder remotePort(int remotePort) {
this.remotePort = remotePort;
return this;
}
/**
* Setter bgp send open message.
*
* @param sentOpenMsg bgp send open message.
* @return this class builder.
*/
public Builder sentOpenMsg(BgpMessage sentOpenMsg) {
this.sentOpenMsg = sentOpenMsg;
return this;
}
/**
* Setter bgp receive open message.
*
* @param receivedOpenMsg bgp receive open message.
* @return this class builder.
*/
public Builder receivedOpenMsg(BgpMessage receivedOpenMsg) {
this.receivedOpenMsg = receivedOpenMsg;
return this;
}
/**
* Setter bgp information message.
*
* @param information bgp information message.
* @return this class builder.
*/
public Builder information(byte[] information) {
this.information = information;
return this;
}
/**
* Checks arguments for bmp peer up notification.
*/
private void checkArguments() {
checkState(perPeer != null, "Invalid bmp per peer in peer up notification message.");
checkState(sentOpenMsg != null, "Invalid bgp send open message.");
checkState(receivedOpenMsg != null, "Invalid bgp receive open message.");
}
/**
* Builds BMP peer up notification message.
*
* @return BMP peer up notification message.
*/
public BmpPeerUpNotification build() {
checkArguments();
return new BmpPeerUpNotification(this);
}
}
}