diff --git a/Cargo.lock b/Cargo.lock index cf8ca99..138d5c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,7 +158,7 @@ dependencies = [ [[package]] name = "bgp-integration-tests" -version = "0.0.0" +version = "0.0.2" dependencies = [ "bgp-packet", "bgp-primitives", @@ -204,7 +204,7 @@ dependencies = [ [[package]] name = "bgp-rib" -version = "0.0.0" +version = "0.0.2" dependencies = [ "bgp-packet", "bgp-primitives", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "bgp-server" -version = "0.0.0" +version = "0.0.2" dependencies = [ "bgp-packet", "bgp-primitives", @@ -236,7 +236,7 @@ dependencies = [ [[package]] name = "bgp-web" -version = "0.0.0" +version = "0.0.2" dependencies = [ "axum", "bgp-packet", diff --git a/Cargo.toml b/Cargo.toml index 2cc6b5d..9feec9f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,17 @@ license = "Apache-2.0" repository = "https://git.rayhaan.net/rayhaan/ferrix" version = "0.0.2" +# Every crate opts in with `[lints] workspace = true`. CI turns warnings into +# errors, so a lint added here is enforced. +[workspace.lints.rust] +unsafe_code = "forbid" + +[workspace.lints.clippy] +all = { level = "warn", priority = -1 } +dbg_macro = "warn" +todo = "warn" +unimplemented = "warn" + [workspace.dependencies] # --- Our crates --- bgp-packet = { path = "crates/packet" } diff --git a/bin/bgp/Cargo.toml b/bin/bgp/Cargo.toml index c1bf949..9a3a02c 100644 --- a/bin/bgp/Cargo.toml +++ b/bin/bgp/Cargo.toml @@ -1,10 +1,12 @@ [package] -description = "A Border Gateway Protocol implementation" -edition.workspace = true +name = "bgp" +description = "A Border Gateway Protocol implementation" +authors.workspace = true +edition.workspace = true homepage.workspace = true -license.workspace = true -name = "bgp" -version.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true [dependencies] bgp-server.workspace = true @@ -14,3 +16,6 @@ eyre.workspace = true protobuf.workspace = true tokio.workspace = true tracing.workspace = true + +[lints] +workspace = true diff --git a/crates/integration-tests/Cargo.toml b/crates/integration-tests/Cargo.toml index cdb8079..7d0e14e 100644 --- a/crates/integration-tests/Cargo.toml +++ b/crates/integration-tests/Cargo.toml @@ -1,6 +1,11 @@ [package] name = "bgp-integration-tests" +authors.workspace = true edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true publish = false [dependencies] @@ -15,3 +20,6 @@ eyre.workspace = true reqwest.workspace = true serde_json.workspace = true tokio.workspace = true + +[lints] +workspace = true diff --git a/crates/integration-tests/tests/announce.rs b/crates/integration-tests/tests/announce.rs index 5325324..e3431ea 100644 --- a/crates/integration-tests/tests/announce.rs +++ b/crates/integration-tests/tests/announce.rs @@ -435,7 +435,7 @@ async fn test_configured_routes_are_announced_to_every_new_session() -> Result<( for router_id in [Ipv4Addr::new(10, 0, 0, 1), Ipv4Addr::new(10, 0, 0, 2)] { let mut peer = established_peer_with_id(&server, router_id).await?; - let mut seen = vec![next_update(&mut peer).await?, next_update(&mut peer).await?]; + let mut seen = [next_update(&mut peer).await?, next_update(&mut peer).await?]; seen.sort_by_key(|u| u.announced_routes[0].to_string()); assert_eq!(seen[0].announced_routes, vec![prefix("10.100.1.0/24")]); assert!( diff --git a/crates/packet/Cargo.toml b/crates/packet/Cargo.toml index 0faf785..b8d3315 100644 --- a/crates/packet/Cargo.toml +++ b/crates/packet/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bgp-packet" - -description.workspace = true +description = "Parsing and serialisation of BGP messages" +authors.workspace = true edition.workspace = true homepage.workspace = true license.workspace = true @@ -18,3 +18,6 @@ serde_repr.workspace = true thiserror.workspace = true strum.workspace = true bgp-primitives.workspace = true + +[lints] +workspace = true diff --git a/crates/packet/src/message.rs b/crates/packet/src/message.rs index c70222f..de8863c 100644 --- a/crates/packet/src/message.rs +++ b/crates/packet/src/message.rs @@ -956,11 +956,10 @@ impl ExtendedCommunitiesPathAttribute { } pub fn wire_len(&self, ctx: &ParserContext) -> Result { - Ok(self - .extended_communities + self.extended_communities .iter() .map(|ec| ec.wire_len(ctx)) - .sum::>()?) + .sum::>() } } @@ -1011,7 +1010,7 @@ impl ExtendedCommunity { let (buf, sub_typ) = be_u8(buf)?; let (buf, parsed) = match (typ, sub_typ) { // Route Target Extended Community. - (0x00 | 0x01 | 0x02, 0x02) => { + (0x00..=0x02, 0x02) => { let (buf, global_admin) = be_u32(buf)?; let (buf, local_admin) = be_u16(buf)?; ( @@ -1025,7 +1024,7 @@ impl ExtendedCommunity { ) } // Route Origin Extended Community. - (0x00 | 0x01 | 0x02, 0x03) => { + (0x00..=0x02, 0x03) => { let (buf, global_admin) = be_u16(buf)?; let (buf, local_admin) = be_u32(buf)?; ( @@ -1084,7 +1083,7 @@ impl ExtendedCommunity { } }; - return Ok((buf, parsed)); + Ok((buf, parsed)) } pub fn to_wire(&self, _: &ParserContext, out: &mut BytesMut) -> Result<()> { @@ -1252,12 +1251,12 @@ impl NlriNextHop { } // parse_prefix is a helper function that implements an NLRI parser for the given AFI. -fn parse_prefix<'a>( +fn parse_prefix( afi: AddressFamilyId, - buf: &'a [u8], -) -> IResult<&'a [u8], IpPrefix, BgpParserError<&'a [u8]>> { + buf: &[u8], +) -> IResult<&[u8], IpPrefix, BgpParserError<&[u8]>> { let (buf, prefix_len) = be_u8(buf)?; - let byte_len = (prefix_len + 7) / 8; + let byte_len = prefix_len.div_ceil(8); let (buf, prefix_bytes) = nom::bytes::take(byte_len as usize).parse(buf)?; let prefix = IpPrefix::new(afi, prefix_bytes.to_vec(), prefix_len) .map_err(|e| Failure(BgpParserError::Eyre(e)))?; diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 20a6ec9..df5ca5d 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "bgp-primitives" - description = "Primitive types for working with routing information" +authors.workspace = true edition.workspace = true homepage.workspace = true license.workspace = true @@ -17,3 +17,6 @@ serde.workspace = true serde_repr.workspace = true thiserror.workspace = true strum.workspace = true + +[lints] +workspace = true diff --git a/crates/primitives/src/ip_prefix.rs b/crates/primitives/src/ip_prefix.rs index cc29cac..6b28a79 100644 --- a/crates/primitives/src/ip_prefix.rs +++ b/crates/primitives/src/ip_prefix.rs @@ -20,7 +20,7 @@ pub struct IpPrefix { impl IpPrefix { pub fn new(address_family: AddressFamilyId, prefix: Vec, length: u8) -> Result { // Ensure that the prefix we are given contains the right number of bytes corresponding to the prefix length. - if prefix.len() < ((length + 7) / 8).into() { + if prefix.len() < length.div_ceil(8).into() { bail!( "Mismatched prefix {:?} for given prefix length: {}", prefix, @@ -80,7 +80,7 @@ impl TryFrom<&str> for IpPrefix { ); } - let length: u8 = u8::from_str_radix(parts[1], 10).map_err(eyre::Error::from)?; + let length: u8 = parts[1].parse().map_err(eyre::Error::from)?; let mut octets; let afi: AddressFamilyId; @@ -97,7 +97,7 @@ impl TryFrom<&str> for IpPrefix { } // Truncate the octets we have to the right number of bytes to match the prefix length.. - if length % 8 == 0 { + if length.is_multiple_of(8) { // We can cleanly truncate the number of bytes since we are at a byte boundary. octets.truncate((length / 8).into()); } else { @@ -125,7 +125,7 @@ impl Display for IpPrefix { // Pad the prefix with 0 bytes if it's less than 4 bytes long. let bytes = &mut self.prefix.clone(); if bytes.len() < 4 { - bytes.extend(std::iter::repeat(0).take(4 - bytes.len())); + bytes.extend(std::iter::repeat_n(0, 4 - bytes.len())); } let four_bytes: [u8; 4] = bytes .as_slice() @@ -137,7 +137,7 @@ impl Display for IpPrefix { AddressFamilyId::Ipv6 => { let bytes = &mut self.prefix.clone(); if bytes.len() < 16 { - bytes.extend(std::iter::repeat(0).take(16 - bytes.len())); + bytes.extend(std::iter::repeat_n(0, 16 - bytes.len())); } let sixteen_bytes: [u8; 16] = bytes .as_slice() diff --git a/crates/primitives/src/poptrie/mod.rs b/crates/primitives/src/poptrie/mod.rs index e8cead5..b53623e 100644 --- a/crates/primitives/src/poptrie/mod.rs +++ b/crates/primitives/src/poptrie/mod.rs @@ -1,3 +1,10 @@ +//! A Poptrie (Asai and Ohara, SIGCOMM 2015): a compressed multiway trie for +//! longest-prefix matching. +//! +//! Work in progress. Nothing in the daemon uses it yet, and the construction +//! side has no public entry point, hence the lint expectation below. +#![expect(dead_code, reason = "not yet wired into a RIB")] + use std::collections::BTreeMap; #[derive(Debug)] @@ -75,7 +82,8 @@ impl Poptrie { result } - fn new(&mut self, rt: BTreeMap<(u32, u8), T>) { + /// Fills the trie from a routing table keyed by (address, prefix length). + fn build(&mut self, rt: BTreeMap<(u32, u8), T>) { const DEPTH: u8 = 6; let mut forest = vec![(0, rt)]; @@ -168,9 +176,10 @@ mod tests { leaves: vec![], }; - poptrie.new(map); - println!("Success"); - - dbg!(poptrie); + poptrie.build(map); + assert!( + !poptrie.inners.is_empty(), + "building from a non-empty table yields nodes" + ); } } diff --git a/crates/rib/Cargo.toml b/crates/rib/Cargo.toml index 42c4a32..8eb31f6 100644 --- a/crates/rib/Cargo.toml +++ b/crates/rib/Cargo.toml @@ -1,6 +1,11 @@ [package] name = "bgp-rib" +authors.workspace = true edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true [dependencies] bgp-packet.workspace = true @@ -9,3 +14,6 @@ serde.workspace = true thiserror.workspace = true tokio = { workspace = true, features = ["full"] } tracing.workspace = true + +[lints] +workspace = true diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml index 9ba77ba..4892562 100644 --- a/crates/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -1,6 +1,11 @@ [package] name = "bgp-server" +authors.workspace = true edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true [dependencies] bgp-packet.workspace = true @@ -19,3 +24,6 @@ thiserror.workspace = true [build-dependencies] protobuf-codegen.workspace = true + +[lints] +workspace = true diff --git a/crates/server/build.rs b/crates/server/build.rs index a33c9c6..9ddd8c7 100644 --- a/crates/server/build.rs +++ b/crates/server/build.rs @@ -6,7 +6,7 @@ fn main() { // on the machine (routers and minimal containers rarely have one). .pure() .input("proto/config.proto") - .includes(&["proto"]) + .includes(["proto"]) .cargo_out_dir("protos") .run_from_script(); } diff --git a/crates/web/Cargo.toml b/crates/web/Cargo.toml index 573ecc6..34fa11b 100644 --- a/crates/web/Cargo.toml +++ b/crates/web/Cargo.toml @@ -1,7 +1,12 @@ [package] name = "bgp-web" description = "HTTP API, event stream and metrics for the BGP daemon" +authors.workspace = true edition.workspace = true +homepage.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true [dependencies] axum.workspace = true @@ -15,3 +20,6 @@ serde.workspace = true tokio.workspace = true tokio-stream.workspace = true tracing.workspace = true + +[lints] +workspace = true