A peer can now send several routes for one prefix, told apart by a path identifier, and each is a route of its own in the table. Wire: - The ADD-PATH capability lists several address families. It was read as exactly one, so the OPEN of a router offering it for IPv4 and IPv6 was malformed and the session never came up. - Prefixes in UPDATEs are `Nlri`: a prefix and a path identifier. The identifier is on the wire, in the body and in MP_REACH/MP_UNREACH, for the families the session uses ADD-PATH for in that direction. Sending and receiving are settled separately, so a session has one codec context for each. Negotiation: - `add_path` on a peer in the configuration: off (the default), receive, send or both, offered for every family offered to the peer. - In use for a family and a direction when one side offered to send and the other to receive. Shown on /statusz and in /api/peers. Table: - A route is known by its peer and path identifier together. Identifiers are stored only in rows that have a non-zero one, so routes of peers that send one route each cost nothing more. - Equal routes from one peer are chosen between by the lower identifier. - /api/routes/received gives each route's path_id. Journal: - A second journal in each shard records every change to any route, for followers that want all the routes of a prefix and not only the best: RibTable::reader_of_all_routes and Event::Routes. This is what sending several routes to a peer will read. It costs nothing while nobody follows it. Sending: prefixes go out with a path identifier where that was agreed, but there is still one route for each prefix to send: only originated routes are announced. Tested with the table and journal model tests extended to path identifiers and to followers of all routes, the codec property tests and fuzz targets extended to ADD-PATH sessions, and end to end in both directions and for the case where only one side offers it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
26 lines
944 B
Rust
26 lines
944 B
Rust
//! A message body behind a correct header, so that the fuzzer spends its
|
|
//! time in the OPEN, UPDATE and NOTIFICATION parsers and not on guessing
|
|
//! the marker and length. The first byte picks the message type and what
|
|
//! the session settled: see `bgp_fuzz::Session`.
|
|
#![no_main]
|
|
|
|
use libfuzzer_sys::fuzz_target;
|
|
|
|
/// The longest body that fits a BGP message (4096 less the 19-byte header).
|
|
const MAX_BODY: usize = 4096 - 19;
|
|
|
|
fuzz_target!(|data: &[u8]| {
|
|
let Some((selector, body)) = data.split_first() else {
|
|
return;
|
|
};
|
|
let body = &body[..body.len().min(MAX_BODY)];
|
|
// Bits 1 to 3; the others pick the session.
|
|
let msg_type = 1 + ((selector >> 1) & 0x07) % 5;
|
|
|
|
let mut wire = vec![0xff; 16];
|
|
wire.extend_from_slice(&((19 + body.len()) as u16).to_be_bytes());
|
|
wire.push(msg_type);
|
|
wire.extend_from_slice(body);
|
|
bgp_fuzz::decode_and_check(bgp_fuzz::Session::from_bits(*selector), &wire);
|
|
});
|