From b7c7514d3e0b66d9dc7a5feae7527137d7c63026 Mon Sep 17 00:00:00 2001 From: Rayhaan Jaufeerally Date: Thu, 1 Oct 2026 21:01:26 +0200 Subject: [PATCH] Fix all clippy warnings and enforce lints across the workspace Lints are declared once under [workspace.lints] and every crate opts in: clippy's default set, plus dbg!, todo! and unimplemented!, and unsafe code is forbidden. Every crate now inherits its version, licence, authors and repository from the workspace, so they no longer disagree (four were at 0.0.0). The poptrie module is unfinished and unused; it says so and expects the dead-code lint instead of warning on every build. Its construction method is renamed from new, which took &mut self, to build. Co-Authored-By: Claude Fable 5.1 --- Cargo.lock | 8 ++++---- Cargo.toml | 11 +++++++++++ bin/bgp/Cargo.toml | 15 ++++++++++----- crates/integration-tests/Cargo.toml | 8 ++++++++ crates/integration-tests/tests/announce.rs | 2 +- crates/packet/Cargo.toml | 7 +++++-- crates/packet/src/message.rs | 19 +++++++++---------- crates/primitives/Cargo.toml | 5 ++++- crates/primitives/src/ip_prefix.rs | 10 +++++----- crates/primitives/src/poptrie/mod.rs | 19 ++++++++++++++----- crates/rib/Cargo.toml | 8 ++++++++ crates/server/Cargo.toml | 8 ++++++++ crates/server/build.rs | 2 +- crates/web/Cargo.toml | 8 ++++++++ 14 files changed, 96 insertions(+), 34 deletions(-) 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