Niraj Dubey | a828719 | 2021-03-23 19:54:17 +0530 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2021-present Open Networking Foundation |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package org.onlab.packet.bmp; |
| 18 | |
| 19 | import com.google.common.base.MoreObjects; |
| 20 | import org.onlab.packet.BasePacket; |
| 21 | import org.onlab.packet.Deserializer; |
| 22 | import org.slf4j.Logger; |
| 23 | |
| 24 | import java.net.InetAddress; |
| 25 | import java.net.UnknownHostException; |
| 26 | import java.nio.ByteBuffer; |
| 27 | |
| 28 | import static org.onlab.packet.PacketUtils.checkInput; |
| 29 | import static org.slf4j.LoggerFactory.getLogger; |
| 30 | |
| 31 | /** |
| 32 | * The per-peer header follows the common header for most BMP messages. |
| 33 | * The rest of the data in a BMP message is dependent on the Message |
| 34 | * Type field in the common header. |
| 35 | * <p> |
| 36 | * Peer Type (1 byte): Identifies the type of peer. Currently, three |
| 37 | * types of peers are identified: |
| 38 | * <p> |
| 39 | * * Peer Type = 0: Global Instance Peer |
| 40 | * * Peer Type = 1: RD Instance Peer |
| 41 | * * Peer Type = 2: Local Instance Peer |
| 42 | * <p> |
| 43 | * o Peer Flags (1 byte): These flags provide more information about |
| 44 | * the peer. The flags are defined as follows: |
| 45 | * <p> |
| 46 | * 0 1 2 3 4 5 6 7 |
| 47 | * +-+-+-+-+-+-+-+-+ |
| 48 | * |V|L|A| Reserved| |
| 49 | * +-+-+-+-+-+-+-+-+ |
| 50 | * <p> |
| 51 | * * The V flag indicates that the Peer address is an IPv6 address. |
| 52 | * For IPv4 peers, this is set to 0. |
| 53 | * <p> |
| 54 | * The L flag, if set to 1, indicates that the message reflects |
| 55 | * the post-policy Adj-RIB-In (i.e., its path attributes reflect |
| 56 | * the application of inbound policy). It is set to 0 if the |
| 57 | * message reflects the pre-policy Adj-RIB-In. Locally sourced |
| 58 | * routes also carry an L flag of 1. See Section 5 for further |
| 59 | * detail. This flag has no significance when used with route |
| 60 | * mirroring messages. |
| 61 | * <p> |
| 62 | * * The A flag, if set to 1, indicates that the message is |
| 63 | * formatted using the legacy 2-byte AS_PATH format. If set to 0, |
| 64 | * the message is formatted using the 4-byte AS_PATH format |
| 65 | * [RFC6793]. A BMP speaker MAY choose to propagate the AS_PATH |
| 66 | * information as received from its peer, or it MAY choose to |
| 67 | * reformat all AS_PATH information into a 4-byte format |
| 68 | * regardless of how it was received from the peer. In the latter |
| 69 | * case, AS4_PATH or AS4_AGGREGATOR path attributes SHOULD NOT be |
| 70 | * sent in the BMP UPDATE message. This flag has no significance |
| 71 | * when used with route mirroring messages. |
| 72 | * <p> |
| 73 | * The remaining bits are reserved for future use. They MUST be |
| 74 | * transmitted as 0 and their values MUST be ignored on receipt. |
| 75 | * <p> |
| 76 | * Peer Distinguisher (8 bytes): Routers today can have multiple |
| 77 | * instances (example: Layer 3 Virtual Private Networks (L3VPNs) |
| 78 | * [RFC4364]). This field is present to distinguish peers that |
| 79 | * belong to one address domain from the other. |
| 80 | * <p> |
| 81 | * If the peer is a "Global Instance Peer", this field is zero- |
| 82 | * filled. If the peer is a "RD Instance Peer", it is set to the |
| 83 | * route distinguisher of the particular instance the peer belongs |
| 84 | * to. If the peer is a "Local Instance Peer", it is set to a |
| 85 | * unique, locally defined value. In all cases, the effect is that |
| 86 | * the combination of the Peer Type and Peer Distinguisher is |
| 87 | * sufficient to disambiguate peers for which other identifying |
| 88 | * information might overlap. |
| 89 | * <p> |
| 90 | * Peer Address: The remote IP address associated with the TCP |
| 91 | * session over which the encapsulated PDU was received. It is 4 |
| 92 | * bytes long if an IPv4 address is carried in this field (with the |
| 93 | * 12 most significant bytes zero-filled) and 16 bytes long if an |
| 94 | * IPv6 address is carried in this field. |
| 95 | * <p> |
| 96 | * Peer AS: The Autonomous System number of the peer from which the |
| 97 | * encapsulated PDU was received. If a 16-bit AS number is stored in |
| 98 | * this field [RFC6793], it should be padded with zeroes in the 16 |
| 99 | * most significant bits. |
| 100 | * <p> |
| 101 | * Timestamp: The time when the encapsulated routes were received |
| 102 | * (one may also think of this as the time when they were installed |
| 103 | * in the Adj-RIB-In), expressed in seconds and microseconds since |
| 104 | * midnight (zero hour), January 1, 1970 (UTC). If zero, the time is |
| 105 | * unavailable. Precision of the timestamp is implementation- |
| 106 | * dependent. |
| 107 | * <p> |
| 108 | * 4.3. Initiation Message |
| 109 | * <p> |
| 110 | * The initiation message provides a means for the monitored router to |
| 111 | * inform the monitoring station of its vendor, software version, and so |
| 112 | * on. An initiation message MUST be sent as the first message after |
| 113 | * the TCP session comes up. An initiation message MAY be sent at any |
| 114 | * point thereafter, if warranted by a change on the monitored router. |
| 115 | * <p> |
| 116 | * The initiation message consists of the common BMP header followed by |
| 117 | * two or more Information TLVs containing information |
| 118 | * about the monitored router. The sysDescr and sysName Information |
| 119 | * TLVs MUST be sent, any others are optional. The string TLV MAY be |
| 120 | * included multiple times. |
| 121 | */ |
| 122 | public class BmpPeer extends BasePacket { |
| 123 | |
| 124 | /* |
| 125 | 0 1 2 3 |
| 126 | 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 |
| 127 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 128 | | Peer Type | Peer Flags | |
| 129 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 130 | | Peer Distinguisher (present based on peer type) | |
| 131 | | | |
| 132 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 133 | | Peer Address (16 bytes) | |
| 134 | ~ ~ |
| 135 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 136 | | Peer AS | |
| 137 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 138 | | Peer BGP ID | |
| 139 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 140 | | Timestamp (seconds) | |
| 141 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 142 | | Timestamp (microseconds) | |
| 143 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| 144 | */ |
| 145 | public static final short PEER_HEADER_MINIMUM_LENGTH = 42; |
| 146 | |
| 147 | public static final short PEER_DISTINGUISHER = 8; |
| 148 | public static final short IPV4_ADDRSZ = 4; |
| 149 | public static final short IPV6_ADDRSZ = 16; |
| 150 | |
| 151 | protected byte type; |
| 152 | |
| 153 | protected byte flags; |
| 154 | |
| 155 | protected byte[] peerDistinguisher; |
| 156 | |
| 157 | protected InetAddress peerAddress; |
| 158 | |
| 159 | protected int peerAs; |
| 160 | |
| 161 | protected int peerBgpId; |
| 162 | |
| 163 | protected long seconds; |
| 164 | |
| 165 | protected long microseconds; |
| 166 | |
| 167 | private static Logger log = getLogger(BmpPeer.class); |
| 168 | |
| 169 | |
| 170 | /** |
| 171 | * Returns Peer Type. |
| 172 | * |
| 173 | * @return the peer type |
| 174 | */ |
| 175 | public byte getType() { |
| 176 | return type; |
| 177 | } |
| 178 | |
| 179 | /** |
| 180 | * Returns Peer Flag. |
| 181 | * |
| 182 | * @return the peer flag |
| 183 | */ |
| 184 | public byte getFlag() { |
| 185 | return flags; |
| 186 | } |
| 187 | |
| 188 | /** |
| 189 | * Returns Peer Distinguisher. |
| 190 | * |
| 191 | * @return the peer distingusiher |
| 192 | */ |
| 193 | public byte[] getPeerDistinguisher() { |
| 194 | return peerDistinguisher; |
| 195 | } |
| 196 | |
| 197 | /** |
| 198 | * Returns Peer IP Address. |
| 199 | * |
| 200 | * @return the peer ip address |
| 201 | */ |
| 202 | public InetAddress getIntAddress() { |
| 203 | return peerAddress; |
| 204 | } |
| 205 | |
| 206 | /** |
| 207 | * Returns Peer Autonomous System number. |
| 208 | * |
| 209 | * @return the peer AS number |
| 210 | */ |
| 211 | public int getPeerAs() { |
| 212 | return peerAs; |
| 213 | } |
| 214 | |
| 215 | /** |
| 216 | * Returns Peer Bgp Id. |
| 217 | * |
| 218 | * @return the bgp id |
| 219 | */ |
| 220 | public int getPeerBgpId() { |
| 221 | return peerBgpId; |
| 222 | } |
| 223 | |
| 224 | /** |
| 225 | * Returns timestamp in sec. |
| 226 | * |
| 227 | * @return the timestamp in sec |
| 228 | */ |
| 229 | public long getSeconds() { |
| 230 | return seconds; |
| 231 | } |
| 232 | |
| 233 | /** |
| 234 | * Returns timestamp in micro second. |
| 235 | * |
| 236 | * @return the timestamp in micro second |
| 237 | */ |
| 238 | public long getMicroseconds() { |
| 239 | return microseconds; |
| 240 | } |
| 241 | |
| 242 | |
| 243 | @Override |
| 244 | public byte[] serialize() { |
| 245 | final byte[] data = new byte[PEER_HEADER_MINIMUM_LENGTH]; |
| 246 | final ByteBuffer bb = ByteBuffer.wrap(data); |
| 247 | |
| 248 | bb.put(this.type); |
| 249 | bb.put(this.flags); |
| 250 | bb.put(this.peerDistinguisher); |
| 251 | bb.put(this.peerAddress.getAddress()); |
| 252 | bb.putInt(this.peerAs); |
| 253 | bb.putInt(this.peerBgpId); |
| 254 | bb.putLong(this.seconds); |
| 255 | bb.putLong(this.microseconds); |
| 256 | |
| 257 | return data; |
| 258 | } |
| 259 | |
| 260 | public static Deserializer<BmpPeer> deserializer() { |
| 261 | return (data, offset, length) -> { |
| 262 | checkInput(data, offset, length, PEER_HEADER_MINIMUM_LENGTH); |
| 263 | |
| 264 | ByteBuffer bb = ByteBuffer.wrap(data, offset, length); |
| 265 | BmpPeer bmpPeer = new BmpPeer(); |
| 266 | |
| 267 | bmpPeer.type = bb.get(); |
| 268 | bmpPeer.flags = bb.get(); |
| 269 | bmpPeer.peerDistinguisher = new byte[PEER_DISTINGUISHER]; |
| 270 | bb.get(bmpPeer.peerDistinguisher, 0, PEER_DISTINGUISHER); |
| 271 | |
| 272 | if ((bmpPeer.flags & 0x80) != 0x00) { |
| 273 | bmpPeer.peerAddress = toInetAddress(IPV6_ADDRSZ, bb); |
| 274 | } else { |
| 275 | bb.position(bb.position() + (IPV6_ADDRSZ - IPV4_ADDRSZ)); |
| 276 | bmpPeer.peerAddress = toInetAddress(IPV4_ADDRSZ, bb); |
| 277 | } |
| 278 | |
| 279 | bmpPeer.peerAs = bb.getInt(); |
| 280 | bmpPeer.peerBgpId = bb.getInt(); |
| 281 | bmpPeer.seconds = bb.getInt(); |
| 282 | bmpPeer.microseconds = bb.getInt(); |
| 283 | |
| 284 | return bmpPeer; |
| 285 | }; |
| 286 | } |
| 287 | |
| 288 | private static InetAddress toInetAddress(int length, ByteBuffer bb) { |
| 289 | byte[] address = new byte[length]; |
| 290 | bb.get(address, 0, length); |
| 291 | InetAddress ipAddress = null; |
| 292 | try { |
| 293 | ipAddress = InetAddress.getByAddress(address); |
| 294 | } catch (UnknownHostException e) { |
| 295 | log.error("InetAddress conversion failed"); |
| 296 | } |
| 297 | |
| 298 | return ipAddress; |
| 299 | } |
| 300 | |
| 301 | @Override |
| 302 | public String toString() { |
| 303 | |
| 304 | return MoreObjects.toStringHelper(getClass()) |
| 305 | .add("flags", flags) |
| 306 | .add("type", type) |
| 307 | .add("peerAddress", peerAddress.getHostAddress()) |
| 308 | .add("peerAs", peerAs) |
| 309 | .add("seconds", seconds) |
| 310 | .add("microseconds", microseconds) |
| 311 | .toString(); |
| 312 | } |
| 313 | |
| 314 | } |