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 <noreply@anthropic.com>
This commit is contained in:
Rayhaan JaufeerallyandClaude Fable 5.1 committed 2026-10-01 21:01:26 +02:00
1 parent 126368852a
commit b7c7514d3e
14 files changed
+96 -34

No files matched your search

Generated
+4 -4
View File
@@ -158,7 +158,7 @@ dependencies = [
[[package]] [[package]]
name = "bgp-integration-tests" name = "bgp-integration-tests"
version = "0.0.0" version = "0.0.2"
dependencies = [ dependencies = [
"bgp-packet", "bgp-packet",
"bgp-primitives", "bgp-primitives",
@@ -204,7 +204,7 @@ dependencies = [
[[package]] [[package]]
name = "bgp-rib" name = "bgp-rib"
version = "0.0.0" version = "0.0.2"
dependencies = [ dependencies = [
"bgp-packet", "bgp-packet",
"bgp-primitives", "bgp-primitives",
@@ -216,7 +216,7 @@ dependencies = [
[[package]] [[package]]
name = "bgp-server" name = "bgp-server"
version = "0.0.0" version = "0.0.2"
dependencies = [ dependencies = [
"bgp-packet", "bgp-packet",
"bgp-primitives", "bgp-primitives",
@@ -236,7 +236,7 @@ dependencies = [
[[package]] [[package]]
name = "bgp-web" name = "bgp-web"
version = "0.0.0" version = "0.0.2"
dependencies = [ dependencies = [
"axum", "axum",
"bgp-packet", "bgp-packet",
+11
View File
@@ -12,6 +12,17 @@ license = "Apache-2.0"
repository = "https://git.rayhaan.net/rayhaan/ferrix" repository = "https://git.rayhaan.net/rayhaan/ferrix"
version = "0.0.2" 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] [workspace.dependencies]
# --- Our crates --- # --- Our crates ---
bgp-packet = { path = "crates/packet" } bgp-packet = { path = "crates/packet" }
+10 -5
View File
@@ -1,10 +1,12 @@
[package] [package]
description = "A Border Gateway Protocol implementation" name = "bgp"
edition.workspace = true description = "A Border Gateway Protocol implementation"
authors.workspace = true
edition.workspace = true
homepage.workspace = true homepage.workspace = true
license.workspace = true license.workspace = true
name = "bgp" repository.workspace = true
version.workspace = true version.workspace = true
[dependencies] [dependencies]
bgp-server.workspace = true bgp-server.workspace = true
@@ -14,3 +16,6 @@ eyre.workspace = true
protobuf.workspace = true protobuf.workspace = true
tokio.workspace = true tokio.workspace = true
tracing.workspace = true tracing.workspace = true
[lints]
workspace = true
+8
View File
@@ -1,6 +1,11 @@
[package] [package]
name = "bgp-integration-tests" name = "bgp-integration-tests"
authors.workspace = true
edition.workspace = true edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
version.workspace = true
publish = false publish = false
[dependencies] [dependencies]
@@ -15,3 +20,6 @@ eyre.workspace = true
reqwest.workspace = true reqwest.workspace = true
serde_json.workspace = true serde_json.workspace = true
tokio.workspace = true tokio.workspace = true
[lints]
workspace = true
+1 -1
View File
@@ -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)] { 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 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()); 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_eq!(seen[0].announced_routes, vec![prefix("10.100.1.0/24")]);
assert!( assert!(
+5 -2
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "bgp-packet" name = "bgp-packet"
description = "Parsing and serialisation of BGP messages"
description.workspace = true authors.workspace = true
edition.workspace = true edition.workspace = true
homepage.workspace = true homepage.workspace = true
license.workspace = true license.workspace = true
@@ -18,3 +18,6 @@ serde_repr.workspace = true
thiserror.workspace = true thiserror.workspace = true
strum.workspace = true strum.workspace = true
bgp-primitives.workspace = true bgp-primitives.workspace = true
[lints]
workspace = true
+9 -10
View File
@@ -956,11 +956,10 @@ impl ExtendedCommunitiesPathAttribute {
} }
pub fn wire_len(&self, ctx: &ParserContext) -> Result<u16> { pub fn wire_len(&self, ctx: &ParserContext) -> Result<u16> {
Ok(self self.extended_communities
.extended_communities
.iter() .iter()
.map(|ec| ec.wire_len(ctx)) .map(|ec| ec.wire_len(ctx))
.sum::<Result<u16>>()?) .sum::<Result<u16>>()
} }
} }
@@ -1011,7 +1010,7 @@ impl ExtendedCommunity {
let (buf, sub_typ) = be_u8(buf)?; let (buf, sub_typ) = be_u8(buf)?;
let (buf, parsed) = match (typ, sub_typ) { let (buf, parsed) = match (typ, sub_typ) {
// Route Target Extended Community. // Route Target Extended Community.
(0x00 | 0x01 | 0x02, 0x02) => { (0x00..=0x02, 0x02) => {
let (buf, global_admin) = be_u32(buf)?; let (buf, global_admin) = be_u32(buf)?;
let (buf, local_admin) = be_u16(buf)?; let (buf, local_admin) = be_u16(buf)?;
( (
@@ -1025,7 +1024,7 @@ impl ExtendedCommunity {
) )
} }
// Route Origin Extended Community. // Route Origin Extended Community.
(0x00 | 0x01 | 0x02, 0x03) => { (0x00..=0x02, 0x03) => {
let (buf, global_admin) = be_u16(buf)?; let (buf, global_admin) = be_u16(buf)?;
let (buf, local_admin) = be_u32(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<()> { 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. // parse_prefix is a helper function that implements an NLRI parser for the given AFI.
fn parse_prefix<'a>( fn parse_prefix(
afi: AddressFamilyId, afi: AddressFamilyId,
buf: &'a [u8], buf: &[u8],
) -> IResult<&'a [u8], IpPrefix, BgpParserError<&'a [u8]>> { ) -> IResult<&[u8], IpPrefix, BgpParserError<&[u8]>> {
let (buf, prefix_len) = be_u8(buf)?; 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 (buf, prefix_bytes) = nom::bytes::take(byte_len as usize).parse(buf)?;
let prefix = IpPrefix::new(afi, prefix_bytes.to_vec(), prefix_len) let prefix = IpPrefix::new(afi, prefix_bytes.to_vec(), prefix_len)
.map_err(|e| Failure(BgpParserError::Eyre(e)))?; .map_err(|e| Failure(BgpParserError::Eyre(e)))?;
+4 -1
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "bgp-primitives" name = "bgp-primitives"
description = "Primitive types for working with routing information" description = "Primitive types for working with routing information"
authors.workspace = true
edition.workspace = true edition.workspace = true
homepage.workspace = true homepage.workspace = true
license.workspace = true license.workspace = true
@@ -17,3 +17,6 @@ serde.workspace = true
serde_repr.workspace = true serde_repr.workspace = true
thiserror.workspace = true thiserror.workspace = true
strum.workspace = true strum.workspace = true
[lints]
workspace = true
+5 -5
View File
@@ -20,7 +20,7 @@ pub struct IpPrefix {
impl IpPrefix { impl IpPrefix {
pub fn new(address_family: AddressFamilyId, prefix: Vec<u8>, length: u8) -> Result<Self> { pub fn new(address_family: AddressFamilyId, prefix: Vec<u8>, length: u8) -> Result<Self> {
// Ensure that the prefix we are given contains the right number of bytes corresponding to the prefix length. // 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!( bail!(
"Mismatched prefix {:?} for given prefix length: {}", "Mismatched prefix {:?} for given prefix length: {}",
prefix, 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 mut octets;
let afi: AddressFamilyId; 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.. // 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. // We can cleanly truncate the number of bytes since we are at a byte boundary.
octets.truncate((length / 8).into()); octets.truncate((length / 8).into());
} else { } else {
@@ -125,7 +125,7 @@ impl Display for IpPrefix {
// Pad the prefix with 0 bytes if it's less than 4 bytes long. // Pad the prefix with 0 bytes if it's less than 4 bytes long.
let bytes = &mut self.prefix.clone(); let bytes = &mut self.prefix.clone();
if bytes.len() < 4 { 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 let four_bytes: [u8; 4] = bytes
.as_slice() .as_slice()
@@ -137,7 +137,7 @@ impl Display for IpPrefix {
AddressFamilyId::Ipv6 => { AddressFamilyId::Ipv6 => {
let bytes = &mut self.prefix.clone(); let bytes = &mut self.prefix.clone();
if bytes.len() < 16 { 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 let sixteen_bytes: [u8; 16] = bytes
.as_slice() .as_slice()
+14 -5
View File
@@ -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; use std::collections::BTreeMap;
#[derive(Debug)] #[derive(Debug)]
@@ -75,7 +82,8 @@ impl<T: Clone> Poptrie<T> {
result 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; const DEPTH: u8 = 6;
let mut forest = vec![(0, rt)]; let mut forest = vec![(0, rt)];
@@ -168,9 +176,10 @@ mod tests {
leaves: vec![], leaves: vec![],
}; };
poptrie.new(map); poptrie.build(map);
println!("Success"); assert!(
!poptrie.inners.is_empty(),
dbg!(poptrie); "building from a non-empty table yields nodes"
);
} }
} }
+8
View File
@@ -1,6 +1,11 @@
[package] [package]
name = "bgp-rib" name = "bgp-rib"
authors.workspace = true
edition.workspace = true edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
version.workspace = true
[dependencies] [dependencies]
bgp-packet.workspace = true bgp-packet.workspace = true
@@ -9,3 +14,6 @@ serde.workspace = true
thiserror.workspace = true thiserror.workspace = true
tokio = { workspace = true, features = ["full"] } tokio = { workspace = true, features = ["full"] }
tracing.workspace = true tracing.workspace = true
[lints]
workspace = true
+8
View File
@@ -1,6 +1,11 @@
[package] [package]
name = "bgp-server" name = "bgp-server"
authors.workspace = true
edition.workspace = true edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
version.workspace = true
[dependencies] [dependencies]
bgp-packet.workspace = true bgp-packet.workspace = true
@@ -19,3 +24,6 @@ thiserror.workspace = true
[build-dependencies] [build-dependencies]
protobuf-codegen.workspace = true protobuf-codegen.workspace = true
[lints]
workspace = true
+1 -1
View File
@@ -6,7 +6,7 @@ fn main() {
// on the machine (routers and minimal containers rarely have one). // on the machine (routers and minimal containers rarely have one).
.pure() .pure()
.input("proto/config.proto") .input("proto/config.proto")
.includes(&["proto"]) .includes(["proto"])
.cargo_out_dir("protos") .cargo_out_dir("protos")
.run_from_script(); .run_from_script();
} }
+8
View File
@@ -1,7 +1,12 @@
[package] [package]
name = "bgp-web" name = "bgp-web"
description = "HTTP API, event stream and metrics for the BGP daemon" description = "HTTP API, event stream and metrics for the BGP daemon"
authors.workspace = true
edition.workspace = true edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true
version.workspace = true
[dependencies] [dependencies]
axum.workspace = true axum.workspace = true
@@ -15,3 +20,6 @@ serde.workspace = true
tokio.workspace = true tokio.workspace = true
tokio-stream.workspace = true tokio-stream.workspace = true
tracing.workspace = true tracing.workspace = true
[lints]
workspace = true