Bmp header message deserializer
Change-Id: I81b6ddc2db8a154c048240005dda0d11ea77f47f
diff --git a/apps/bgpmonitoring/app/src/main/java/org/onosproject/bgpmonitoring/type/BmpHeader.java b/apps/bgpmonitoring/app/src/main/java/org/onosproject/bgpmonitoring/type/BmpHeader.java
new file mode 100644
index 0000000..5405ae2
--- /dev/null
+++ b/apps/bgpmonitoring/app/src/main/java/org/onosproject/bgpmonitoring/type/BmpHeader.java
@@ -0,0 +1,326 @@
+/*
+ * 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 org.onlab.packet.DeserializationException;
+import org.onlab.packet.Deserializer;
+
+import java.nio.ByteBuffer;
+import java.util.function.BiPredicate;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.onosproject.bgpmonitoring.BmpMessage;
+import org.onosproject.bgpmonitoring.BmpVersion;
+import org.onosproject.bgpmonitoring.BmpPacket;
+import org.onosproject.bgpmonitoring.BmpParseException;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * The following common header appears in all BMP messages. The rest of
+ * the data in a BMP message is dependent on the Message Type field in
+ * the common header.
+ * <p>
+ * Version (1 byte): Indicates the BMP version. This is set to '3'
+ * for all messages defined in this specification. ('1' and '2' were
+ * used by draft versions of this document.) Version 0 is reserved
+ * and MUST NOT be sent.
+ * <p>
+ * Message Length (4 bytes): Length of the message in bytes
+ * (including headers, data, and encapsulated messages, if any).
+ * <p>
+ * Message Type (1 byte): This identifies the type of the BMP
+ * message. A BMP implementation MUST ignore unrecognized message
+ * types upon receipt.
+ * <p>
+ * Type = 0: Route Monitoring
+ * Type = 1: Statistics Report
+ * Type = 2: Peer Down Notification
+ * Type = 3: Peer Up Notification
+ * Type = 4: Initiation Message
+ * Type = 5: Termination Message
+ * Type = 6: Route Mirroring Message
+ */
+public final class BmpHeader extends BmpPacket {
+
+ /*
+
+ 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
+ +-+-+-+-+-+-+-+-+
+ | Version |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Message Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Msg. Type |
+ +---------------+
+
+ */
+
+
+ public static final int DEFAULT_HEADER_LENGTH = 6;
+ public static final int DEFAULT_PACKET_MINIMUM_LENGTH = 4;
+
+ private BmpVersion version;
+
+ private BmpType type;
+
+ private int length;
+
+ private BmpMessage message;
+
+
+ public enum BmpType {
+
+ ROUTE_MONITORING(0, BmpRouteMirroring.deserializer()),
+
+ STATISTICS_REPORT(1, BmpStatsReport.deserializer()),
+
+ PEER_DOWN_NOTIFICATION(2, BmpPeerDownNotification.deserializer()),
+
+ PEER_UP_NOTIFICATION(3, BmpPeerUpNotification.deserializer()),
+
+ INITIATION_MESSAGE(4, BmpInitiationMessage.deserializer()),
+
+ TERMINATION_MESSAGE(5, BmpTerminationMessage.deserializer()),
+
+ ROUTE_MIRRORING_MESSAGE(6, BmpRouteMirroring.deserializer());
+
+ private final int value;
+ private final Deserializer<BmpMessage> deserializer;
+
+ /**
+ * Assign value with the value val as the types of BMP message.
+ *
+ * @param val type of BMP message
+ * @param deserializer deserializer
+ */
+ BmpType(int val, Deserializer deserializer) {
+ this.value = val;
+ this.deserializer = deserializer;
+ }
+
+
+ /**
+ * Returns value as type of BMP message.
+ *
+ * @return value type of BMP message
+ */
+ public int getType() {
+ return value;
+ }
+
+ private static Map<Integer, BmpType> parser = new ConcurrentHashMap<>();
+
+ static {
+ Arrays.stream(BmpType.values()).forEach(type -> parser.put(type.value, type));
+ }
+
+ public static BmpType getType(int type) throws DeserializationException {
+ if (type > 6) {
+ throw new DeserializationException("Invalid trap type");
+ }
+ return Optional.of(type)
+ .filter(id -> parser.containsKey(id))
+ .map(id -> parser.get(id))
+ .orElse(ROUTE_MONITORING);
+ }
+
+ public Deserializer<BmpMessage> getDecoder() {
+ return this.deserializer;
+ }
+
+ }
+
+
+ private BmpHeader(Builder builder) {
+ this.version = builder.version;
+ this.length = builder.length;
+ this.type = builder.type;
+ this.message = builder.message;
+ }
+
+
+ /**
+ * Returns message length.
+ *
+ * @return message length
+ */
+ @Override
+ public int getLength() {
+ return this.length;
+ }
+
+ /**
+ * Returns message version.
+ *
+ * @return message version
+ */
+ @Override
+ public BmpVersion getVersion() {
+ return this.version;
+ }
+
+ /**
+ * Returns message type.
+ *
+ * @return message type
+ */
+ @Override
+ public String getType() {
+ return this.type.name();
+ }
+
+ /**
+ * Returns message type.
+ *
+ * @return message type
+ */
+ @Override
+ public BmpMessage getMessage() {
+ return this.message;
+ }
+
+
+ /**
+ * Read from channel buffer and Returns BMP header.
+ *
+ * @return Deserializer Deserializer
+ */
+ public static Deserializer<BmpHeader> 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, DEFAULT_HEADER_LENGTH)) {
+ throw new BmpParseException("Invalid bmp header buffer size.");
+ }
+ Builder builder = new Builder()
+ .version(BmpVersion.getVersion((int) bb.get()))
+ .length(bb.getInt())
+ .type(BmpType.getType((int) bb.get()));
+
+ if (bb.remaining() != (builder.length - DEFAULT_HEADER_LENGTH)) {
+ throw new BmpParseException("Invalid bmp header buffer size.");
+ }
+
+ byte[] msgBytes = new byte[bb.remaining()];
+ bb.get(msgBytes);
+ return builder.message(builder.type.getDecoder()
+ .deserialize(msgBytes, 0, (builder.length - DEFAULT_HEADER_LENGTH)))
+ .build();
+
+ };
+ }
+
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(getClass())
+ .add("version", version)
+ .add("type", type)
+ .add("length", length)
+ .toString();
+ }
+
+ /**
+ * Builder for BMP header.
+ */
+ private static class Builder {
+
+ private BmpVersion version;
+
+ private BmpType type;
+
+ private int length;
+
+ private BmpMessage message;
+
+
+ /**
+ * Setter bmp version.
+ *
+ * @param version bmp version.
+ * @return this class builder.
+ */
+ public Builder version(BmpVersion version) {
+ this.version = version;
+ return this;
+ }
+
+
+ /**
+ * Setter bmp header length.
+ *
+ * @param length bmp header length.
+ * @return this class builder.
+ */
+ public Builder length(int length) {
+ this.length = length;
+ return this;
+ }
+
+ /**
+ * Setter bmp message type.
+ *
+ * @param type bmp message type.
+ * @return this class builder.
+ */
+ public Builder type(BmpType type) {
+ this.type = type;
+ return this;
+ }
+
+
+ /**
+ * Setter bmp message.
+ *
+ * @param message bmp message.
+ * @return this class builder.
+ */
+ public Builder message(BmpMessage message) {
+ this.message = message;
+ return this;
+ }
+
+
+ /**
+ * Checks arguments for bmp header.
+ */
+ private void checkArguments() {
+ checkState(length != 0, "Invalid bmp header length.");
+ checkState(type != null, "Invalid bmp message type.");
+ checkState(message != null, "Invalid bmp message.");
+ }
+
+ /**
+ * Builds BMP header.
+ *
+ * @return BMP header.
+ */
+ public BmpHeader build() {
+ checkArguments();
+ return new BmpHeader(this);
+ }
+ }
+}