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]]
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",
+11
View File
@@ -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" }
+10 -5
View File
@@ -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
+8
View File
@@ -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
+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)] {
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!(
+5 -2
View File
@@ -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
+9 -10
View File
@@ -956,11 +956,10 @@ impl ExtendedCommunitiesPathAttribute {
}
pub fn wire_len(&self, ctx: &ParserContext) -> Result<u16> {
Ok(self
.extended_communities
self.extended_communities
.iter()
.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, 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)))?;
+4 -1
View File
@@ -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
+5 -5
View File
@@ -20,7 +20,7 @@ pub struct IpPrefix {
impl IpPrefix {
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.
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()
+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;
#[derive(Debug)]
@@ -75,7 +82,8 @@ impl<T: Clone> Poptrie<T> {
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"
);
}
}
+8
View File
@@ -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
+8
View File
@@ -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
+1 -1
View File
@@ -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();
}
+8
View File
@@ -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