diff --git a/crates/bench/benches/full_table.rs b/crates/bench/benches/full_table.rs index 87a4ce6..ce9e0e6 100644 --- a/crates/bench/benches/full_table.rs +++ b/crates/bench/benches/full_table.rs @@ -294,10 +294,10 @@ fn floor(prefixes: &Prefixes, per_peer: &[Vec], routes: usize) { fn key(prefix: &IpPrefix) -> u128 { let mut address = [0u8; 16]; - address[..prefix.prefix.len()].copy_from_slice(&prefix.prefix); + address[..prefix.bytes().len()].copy_from_slice(prefix.bytes()); // The address in the high bits, the length in the low eight. An IPv6 // prefix longer than /120 would not fit; the table has none. - (u128::from_be_bytes(address) & !0xff) | u128::from(prefix.length) + (u128::from_be_bytes(address) & !0xff) | u128::from(prefix.length()) } println!("\n== Straw man: packed prefix -> attribute set number, no actor"); @@ -310,7 +310,7 @@ fn floor(prefixes: &Prefixes, per_peer: &[Vec], routes: usize) { for (number, update) in updates.iter().enumerate() { for prefix in &update.announced_routes { v4.insert( - (key(prefix) >> 64) as u64 | u64::from(prefix.length), + (key(prefix) >> 64) as u64 | u64::from(prefix.length()), number as u32, ); } diff --git a/crates/bench/data/.gitignore b/crates/bench/data/.gitignore new file mode 100644 index 0000000..13742a5 --- /dev/null +++ b/crates/bench/data/.gitignore @@ -0,0 +1,4 @@ +# Table dumps downloaded for benchmarks; see README.md. +* +!.gitignore +!README.md diff --git a/crates/bench/src/lib.rs b/crates/bench/src/lib.rs index 7057ef9..8a43d29 100644 --- a/crates/bench/src/lib.rs +++ b/crates/bench/src/lib.rs @@ -130,13 +130,9 @@ impl Prefixes { let length = rng.pick(&v4_lengths); // Unicast space, 1.0.0.0 to 223.255.255.255. let address = 0x0100_0000 + (rng.next_u64() as u32) % 0xdf00_0000; - let prefix = IpPrefix::new( - AddressFamilyId::Ipv4, - address.to_be_bytes().to_vec(), - length, - ) - .expect("four bytes cover any IPv4 prefix"); - if seen.insert(prefix.clone()) { + let prefix = IpPrefix::new(AddressFamilyId::Ipv4, address.to_be_bytes(), length) + .expect("four bytes cover any IPv4 prefix"); + if seen.insert(prefix) { ipv4.push(prefix); } } @@ -145,13 +141,9 @@ impl Prefixes { let length = rng.pick(&v6_lengths); // Global unicast, 2000::/3. let address = (0x2000_u128 << 112) | (u128::from(rng.next_u64()) << 61 >> 3); - let prefix = IpPrefix::new( - AddressFamilyId::Ipv6, - address.to_be_bytes().to_vec(), - length, - ) - .expect("sixteen bytes cover any IPv6 prefix"); - if seen.insert(prefix.clone()) { + let prefix = IpPrefix::new(AddressFamilyId::Ipv6, address.to_be_bytes(), length) + .expect("sixteen bytes cover any IPv6 prefix"); + if seen.insert(prefix) { ipv6.push(prefix); } } diff --git a/crates/integration-tests/examples/fake_peer.rs b/crates/integration-tests/examples/fake_peer.rs index a375878..ac38be2 100644 --- a/crates/integration-tests/examples/fake_peer.rs +++ b/crates/integration-tests/examples/fake_peer.rs @@ -88,7 +88,7 @@ async fn run(args: &Args, mut peer: TestPeer, addr: std::net::SocketAddr) -> Res for p in &args.announce { let prefix = IpPrefix::try_from(p.as_str())?; - let update = announce(prefix.clone(), vec![args.asn], vec![(args.asn as u16, 1)]); + let update = announce(prefix, vec![args.asn], vec![(args.asn as u16, 1)]); peer.send(&Message::Update(update)).await?; println!("announced {prefix}"); } @@ -157,7 +157,7 @@ async fn echo_back(peer: &mut TestPeer, u: &UpdateMessage, asn: u32) -> Result<( } for prefix in &u.announced_routes { peer.send(&Message::Update(announce( - prefix.clone(), + *prefix, as_path.clone(), communities.clone(), ))) diff --git a/crates/integration-tests/tests/basic_connection.rs b/crates/integration-tests/tests/basic_connection.rs index be5ba95..aafe502 100644 --- a/crates/integration-tests/tests/basic_connection.rs +++ b/crates/integration-tests/tests/basic_connection.rs @@ -218,7 +218,7 @@ async fn test_message_split_across_a_keepalive_tick_is_still_one_message() -> Re Message::Update(UpdateMessage { withdrawn_routes: vec![], path_attributes: mandatory_attributes(), - announced_routes: vec![prefix.clone()], + announced_routes: vec![prefix], }) .to_wire(&peer.ctx, &mut update)?; @@ -403,7 +403,7 @@ async fn test_rib_records_ipv4_announce() -> Result<()> { peer.send(&Message::Update(UpdateMessage { withdrawn_routes: vec![], path_attributes: mandatory_attributes(), - announced_routes: vec![prefix.clone()], + announced_routes: vec![prefix], })) .await?; @@ -437,14 +437,14 @@ async fn test_rib_records_ipv4_withdraw() -> Result<()> { peer.send(&Message::Update(UpdateMessage { withdrawn_routes: vec![], path_attributes: mandatory_attributes(), - announced_routes: vec![prefix.clone()], + announced_routes: vec![prefix], })) .await?; tokio::time::timeout(Duration::from_secs(1), events.recv()).await??; // Now withdraw. peer.send(&Message::Update(UpdateMessage { - withdrawn_routes: vec![prefix.clone()], + withdrawn_routes: vec![prefix], path_attributes: vec![], announced_routes: vec![], })) @@ -482,7 +482,7 @@ async fn test_rib_records_ipv6_announce() -> Result<()> { afi: Afi::IPV6, safi: Safi::UNICAST, next_hop: NlriNextHop::Ipv6("2001:db8::1".parse().unwrap()), - prefixes: vec![prefix.clone()], + prefixes: vec![prefix], }, )), announced_routes: vec![], @@ -523,7 +523,7 @@ async fn test_rib_records_ipv6_withdraw() -> Result<()> { afi: Afi::IPV6, safi: Safi::UNICAST, next_hop: NlriNextHop::Ipv6("2001:db8::1".parse().unwrap()), - prefixes: vec![prefix.clone()], + prefixes: vec![prefix], }, )), announced_routes: vec![], @@ -537,7 +537,7 @@ async fn test_rib_records_ipv6_withdraw() -> Result<()> { path_attributes: vec![PathAttribute::MpUnreachNlri(MpUnreachNlriPathAttribute { afi: Afi::IPV6, safi: Safi::UNICAST, - prefixes: vec![prefix.clone()], + prefixes: vec![prefix], })], announced_routes: vec![], })) diff --git a/crates/packet/src/message.rs b/crates/packet/src/message.rs index 2bc1387..84b95c8 100644 --- a/crates/packet/src/message.rs +++ b/crates/packet/src/message.rs @@ -302,8 +302,8 @@ impl UpdateMessage { let withdrawn_len = prefix_list_wire_len(&self.withdrawn_routes)?; out.put_u16(withdrawn_len); for prefix in &self.withdrawn_routes { - out.put_u8(prefix.length); - out.put(prefix.prefix.as_slice()); + out.put_u8(prefix.length()); + out.put(prefix.bytes()); } // Path attributes. @@ -321,8 +321,8 @@ impl UpdateMessage { // NLRI (consumes the remainder of the message). for prefix in &self.announced_routes { - out.put_u8(prefix.length); - out.put(prefix.prefix.as_slice()); + out.put_u8(prefix.length()); + out.put(prefix.bytes()); } Ok(()) @@ -333,13 +333,13 @@ impl UpdateMessage { // attribute length field. let mut total: u32 = 4; for prefix in &self.withdrawn_routes { - total += 1 + prefix.prefix.len() as u32; + total += 1 + prefix.bytes().len() as u32; } for pa in &self.path_attributes { total += pa.wire_len(ctx)? as u32; } for prefix in &self.announced_routes { - total += 1 + prefix.prefix.len() as u32; + total += 1 + prefix.bytes().len() as u32; } u16::try_from(total).map_err(|_| too_long("UPDATE message", total)) } @@ -349,7 +349,7 @@ impl UpdateMessage { /// appear in the withdrawn or NLRI sections of an UPDATE message (each prefix /// is encoded as a 1-byte length followed by `ceil(length/8)` prefix bytes). fn prefix_list_wire_len(prefixes: &[IpPrefix]) -> Result { - let total: u32 = prefixes.iter().map(|p| 1 + p.prefix.len() as u32).sum(); + let total: u32 = prefixes.iter().map(|p| 1 + p.bytes().len() as u32).sum(); u16::try_from(total).map_err(|_| too_long("prefix list", total)) } @@ -1472,7 +1472,7 @@ pub(crate) fn parse_prefix( let (buf, prefix_len) = be_u8(buf)?; 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) + let prefix = IpPrefix::new(afi, prefix_bytes, prefix_len) .map_err(|e| Failure(BgpParserError::Malformed(e.to_string())))?; Ok((buf, prefix)) } @@ -1574,8 +1574,8 @@ impl MpReachNlriPathAttribute { self.next_hop.to_wire(ctx, out)?; out.put_u8(0); for prefix in &self.prefixes { - out.put_u8(prefix.length); - out.put(&prefix.prefix[..]); + out.put_u8(prefix.length()); + out.put(prefix.bytes()); } Ok(()) } @@ -1587,7 +1587,7 @@ impl MpReachNlriPathAttribute { + self .prefixes .iter() - .map(|p| 1 + p.prefix.len() as u16) + .map(|p| 1 + p.bytes().len() as u16) .sum::()) } } @@ -1628,8 +1628,8 @@ impl MpUnreachNlriPathAttribute { out.put_u16(self.afi.0); out.put_u8(self.safi.0); for prefix in &self.prefixes { - out.put_u8(prefix.length); - out.put(&prefix.prefix[..]); + out.put_u8(prefix.length()); + out.put(prefix.bytes()); } Ok(()) } @@ -1638,7 +1638,7 @@ impl MpUnreachNlriPathAttribute { Ok(3 + self .prefixes .iter() - .map(|p| 1 + p.prefix.len() as u16) + .map(|p| 1 + p.bytes().len() as u16) .sum::()) } } @@ -1861,11 +1861,9 @@ mod tests { global: ipv6!("2001:db8::1"), link_local: ipv6!("fe80::12"), }, - prefixes: vec![IpPrefix { - address_family: AddressFamilyId::Ipv6, - prefix: vec![0x20, 0x01, 0x0d, 0xb8], - length: 32, - }] + prefixes: vec![ + IpPrefix::new(AddressFamilyId::Ipv6, [0x20, 0x01, 0x0d, 0xb8], 32).unwrap() + ] }) ); @@ -1878,11 +1876,9 @@ mod tests { PathAttribute::MpUnreachNlri(MpUnreachNlriPathAttribute { afi: Afi::IPV6, safi: Safi::UNICAST, - prefixes: vec![IpPrefix { - address_family: AddressFamilyId::Ipv6, - prefix: vec![0x20, 0x01, 0x0d, 0xb8], - length: 32, - }], + prefixes: vec![ + IpPrefix::new(AddressFamilyId::Ipv6, [0x20, 0x01, 0x0d, 0xb8], 32).unwrap() + ], }) ); @@ -1973,11 +1969,7 @@ mod tests { // Wrapper to generate a IPv4 prefix used in tests below. fn v4_prefix(length: u8, bytes: &[u8]) -> IpPrefix { - IpPrefix { - address_family: AddressFamilyId::Ipv4, - prefix: bytes.to_vec(), - length, - } + IpPrefix::new(AddressFamilyId::Ipv4, bytes, length).unwrap() } /// A small set of path attributes that commonly accompany an IPv4 unicast diff --git a/crates/packet/src/update_decode.rs b/crates/packet/src/update_decode.rs index 15a1230..f0112a7 100644 --- a/crates/packet/src/update_decode.rs +++ b/crates/packet/src/update_decode.rs @@ -841,7 +841,7 @@ mod tests { [PathAttribute::MpUnreachNlri(MpUnreachNlriPathAttribute { afi: Afi::IPV6, safi: Safi::UNICAST, - prefixes: vec![v6.clone()], + prefixes: vec![v6], })], "{case}" ); diff --git a/crates/packet/tests/properties.rs b/crates/packet/tests/properties.rs index e1a014f..30b753c 100644 --- a/crates/packet/tests/properties.rs +++ b/crates/packet/tests/properties.rs @@ -69,7 +69,7 @@ fn prefix(version: AddressFamilyId) -> impl Strategy { AddressFamilyId::Ipv6 => 128, }; (0..=max_len, any::<[u8; 16]>()).prop_map(move |(length, bytes)| { - IpPrefix::new(version, bytes.to_vec(), length).expect("16 bytes are enough for any prefix") + IpPrefix::new(version, bytes, length).expect("16 bytes are enough for any prefix") }) } diff --git a/crates/primitives/src/ip_prefix.rs b/crates/primitives/src/ip_prefix.rs index e994ca5..f18f16b 100644 --- a/crates/primitives/src/ip_prefix.rs +++ b/crates/primitives/src/ip_prefix.rs @@ -26,25 +26,35 @@ pub enum PrefixError { }, } -/// IpPrefix represents some IP address prefix, for a specific AddressFamilyId. -#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)] +/// An IPv4 or IPv6 prefix. +/// +/// It is a small value with no allocation behind it, cheap to copy, compare +/// and hash: a routing table holds millions of them and looks them up by +/// value. A prefix has one representation: the bits past its length are +/// always zero, so two prefixes are equal exactly when they are the same +/// prefix. +#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Serialize, Deserialize)] pub struct IpPrefix { - pub address_family: AddressFamilyId, - pub prefix: Vec, - pub length: u8, + address_family: AddressFamilyId, + length: u8, + /// The address, left-aligned, zero past `length` bits. + address: [u8; 16], } impl IpPrefix { + /// Makes a prefix from the leading bytes of its address. `prefix` must + /// hold at least the bytes that `length` bits cover; anything past + /// those bits is ignored (RFC 4271 §4.3: such bits are irrelevant). pub fn new( address_family: AddressFamilyId, - prefix: Vec, + prefix: impl AsRef<[u8]>, length: u8, ) -> Result { + let prefix = prefix.as_ref(); let max = address_family.bits(); if length > max { return Err(PrefixError::LengthTooLong { length, max }); } - // Ensure that the prefix we are given contains the right number of bytes corresponding to the prefix length. let needed = usize::from(length.div_ceil(8)); if prefix.len() < needed { return Err(PrefixError::TooFewBytes { @@ -53,26 +63,31 @@ impl IpPrefix { got: prefix.len(), }); } - Ok(Self::normalised(address_family, prefix, length)) - } - - /// Builds the one representation of a prefix: exactly the bytes its - /// length covers, with the bits past the length cleared. Those bits mean - /// nothing (RFC 4271 §4.3), so two prefixes that differ only there are - /// the same prefix and must compare equal. - /// - /// `length` must fit the address family and `prefix` must have at least - /// the bytes it covers. - fn normalised(address_family: AddressFamilyId, mut prefix: Vec, length: u8) -> Self { - prefix.truncate(usize::from(length.div_ceil(8))); - if let (Some(last), rem @ 1..) = (prefix.last_mut(), length % 8) { + let mut address = [0u8; 16]; + address[..needed].copy_from_slice(&prefix[..needed]); + if let (Some(last), rem @ 1..) = (address[..needed].last_mut(), length % 8) { *last &= u8::MAX << (8 - rem); } - Self { + Ok(Self { address_family, - prefix, length, - } + address, + }) + } + + pub fn address_family(&self) -> AddressFamilyId { + self.address_family + } + + /// The prefix length in bits. + pub fn length(&self) -> u8 { + self.length + } + + /// The bytes the prefix length covers, as they go on the wire: none for + /// a default route, three for a /24. + pub fn bytes(&self) -> &[u8] { + &self.address[..usize::from(self.length.div_ceil(8))] } /// Returns true if `other` is equal to or more specific than `self`, i.e. @@ -82,8 +97,8 @@ impl IpPrefix { if self.address_family != other.address_family || other.length < self.length { return false; } - let full_bytes = (self.length / 8) as usize; - if self.prefix[..full_bytes] != other.prefix[..full_bytes] { + let full_bytes = usize::from(self.length / 8); + if self.address[..full_bytes] != other.address[..full_bytes] { return false; } let rem_bits = self.length % 8; @@ -91,28 +106,19 @@ impl IpPrefix { return true; } let mask = u8::MAX << (8 - rem_bits); - (self.prefix[full_bytes] & mask) == (other.prefix[full_bytes] & mask) - } - - /// The prefix as a whole address, zero where the prefix says nothing. - /// The fields are public, so this cannot assume `prefix` has a sensible - /// length: showing a prefix must never fail, whatever is in it. - fn padded(&self) -> [u8; N] { - let mut address = [0u8; N]; - let len = self.prefix.len().min(N); - address[..len].copy_from_slice(&self.prefix[..len]); - address + (self.address[full_bytes] & mask) == (other.address[full_bytes] & mask) } pub fn to_wire(&self, _: &ParserContext, out: &mut BytesMut) -> Result<(), EncodeError> { + let bytes = self.bytes(); // Verify that there is enough space to write the IpPrefix. - if out.remaining() < (self.prefix.len() + 1) { + if out.remaining() < (bytes.len() + 1) { return Err(EncodeError::OutBufferOverflow); } // Write length and prefix. out.put_u8(self.length); - out.put(self.prefix.as_slice()); + out.put(bytes); Ok(()) } @@ -142,10 +148,11 @@ impl Display for IpPrefix { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self.address_family { AddressFamilyId::Ipv4 => { - write!(f, "{}/{}", Ipv4Addr::from(self.padded()), self.length) + let [a, b, c, d, ..] = self.address; + write!(f, "{}/{}", Ipv4Addr::new(a, b, c, d), self.length) } AddressFamilyId::Ipv6 => { - write!(f, "{}/{}", Ipv6Addr::from(self.padded()), self.length) + write!(f, "{}/{}", Ipv6Addr::from(self.address), self.length) } } } @@ -165,9 +172,9 @@ mod tests { fn $name() { let ip_prefix = IpPrefix::try_from($prefix_str).unwrap(); - assert_eq!(ip_prefix.address_family, $afi); - assert_eq!(ip_prefix.prefix, $bytes); - assert_eq!(ip_prefix.length, $length); + assert_eq!(ip_prefix.address_family(), $afi); + assert_eq!(ip_prefix.bytes(), $bytes); + assert_eq!(ip_prefix.length(), $length); let to_str: &str = &ip_prefix.to_string(); assert_eq!(IpPrefix::try_from(to_str).unwrap(), ip_prefix); @@ -268,7 +275,7 @@ mod tests { // Extra bytes and stray bits past the length are dropped. let noisy = IpPrefix::new(AddressFamilyId::Ipv4, vec![10, 0xff, 3, 4], 12).unwrap(); assert_eq!(noisy, IpPrefix::try_from("10.240.0.0/12").unwrap()); - assert_eq!(noisy.prefix, vec![10, 0xf0]); + assert_eq!(noisy.bytes(), [10, 0xf0]); assert_eq!( IpPrefix::new(AddressFamilyId::Ipv4, vec![0xff; 13], 99), Err(PrefixError::LengthTooLong { @@ -278,16 +285,14 @@ mod tests { ); } - /// The fields are public, so a prefix can be put together wrongly. - /// Showing it must still not fail: prefixes are shown in log lines. #[test] - fn showing_a_prefix_never_fails() { - let wrong = IpPrefix { - address_family: AddressFamilyId::Ipv4, - prefix: vec![1, 2, 3, 4, 5, 6], - length: 200, - }; - assert_eq!(wrong.to_string(), "1.2.3.4/200"); + fn a_prefix_is_a_small_value() { + assert!(size_of::() <= 20); + let prefix = IpPrefix::try_from("10.1.2.0/24").unwrap(); + let copy = prefix; + assert_eq!(copy, prefix); + assert_eq!(prefix.bytes(), [10, 1, 2]); + assert_eq!(IpPrefix::try_from("0.0.0.0/0").unwrap().bytes(), [0u8; 0]); } proptest! { @@ -295,9 +300,9 @@ mod tests { fn text_round_trips(version: bool, bytes: [u8; 16], length in 0u8..=128) { let version = if version { AddressFamilyId::Ipv6 } else { AddressFamilyId::Ipv4 }; let length = length.min(version.bits()); - let prefix = IpPrefix::new(version, bytes.to_vec(), length).unwrap(); + let prefix = IpPrefix::new(version, bytes, length).unwrap(); let text = prefix.to_string(); - prop_assert_eq!(IpPrefix::try_from(text.as_str()), Ok(prefix.clone())); + prop_assert_eq!(IpPrefix::try_from(text.as_str()), Ok(prefix)); prop_assert!(prefix.contains(&prefix)); } @@ -314,8 +319,8 @@ mod tests { fn contains_is_a_comparison_of_leading_bits( a: [u8; 4], a_len in 0u8..=32, b: [u8; 4], b_len in 0u8..=32, ) { - let outer = IpPrefix::new(AddressFamilyId::Ipv4, a.to_vec(), a_len).unwrap(); - let inner = IpPrefix::new(AddressFamilyId::Ipv4, b.to_vec(), b_len).unwrap(); + let outer = IpPrefix::new(AddressFamilyId::Ipv4, a, a_len).unwrap(); + let inner = IpPrefix::new(AddressFamilyId::Ipv4, b, b_len).unwrap(); let mask = if a_len == 0 { 0 } else { u32::MAX << (32 - a_len) }; let expected = b_len >= a_len && (u32::from_be_bytes(a) & mask) == (u32::from_be_bytes(b) & mask); diff --git a/crates/rib/src/adj_rib_in.rs b/crates/rib/src/adj_rib_in.rs index 11c9179..9c29a92 100644 --- a/crates/rib/src/adj_rib_in.rs +++ b/crates/rib/src/adj_rib_in.rs @@ -143,7 +143,7 @@ async fn run_actor(mut rx: mpsc::Receiver, events: broadcast::Sender } } for (prefix, entry) in update.announced { - routes.insert(prefix.clone(), entry.clone()); + routes.insert(prefix, entry.clone()); let _ = events.send(RibEvent::Announced { peer, prefix, @@ -168,7 +168,7 @@ async fn run_actor(mut rx: mpsc::Receiver, events: broadcast::Sender .flat_map(|(peer, routes)| { routes.iter().map(|(prefix, entry)| SnapshotEntry { peer: *peer, - prefix: prefix.clone(), + prefix: *prefix, entry: entry.clone(), }) }) diff --git a/crates/rib/src/entry.rs b/crates/rib/src/entry.rs index 616ca2f..15c3e36 100644 --- a/crates/rib/src/entry.rs +++ b/crates/rib/src/entry.rs @@ -83,14 +83,14 @@ impl ReceivedUpdate { let mut announced: Vec<(IpPrefix, RibEntry)> = update .announced_routes .iter() - .map(|prefix| (prefix.clone(), entry(None))) + .map(|prefix| (*prefix, entry(None))) .collect(); for attr in &update.path_attributes { match attr { PathAttribute::MpReachNlri(mp) => announced.extend( mp.prefixes .iter() - .map(|prefix| (prefix.clone(), entry(Some(mp.next_hop.clone())))), + .map(|prefix| (*prefix, entry(Some(mp.next_hop.clone())))), ), PathAttribute::MpUnreachNlri(mp) => withdrawn.extend(mp.prefixes.iter().cloned()), _ => {} @@ -184,7 +184,7 @@ mod tests { let announced: Vec<_> = received .announced .iter() - .map(|(p, e)| (p.clone(), e.next_hop.is_some())) + .map(|(p, e)| (*p, e.next_hop.is_some())) .collect(); assert_eq!( announced, diff --git a/crates/rib/src/local_rib.rs b/crates/rib/src/local_rib.rs index b1f15dc..c7dd3e5 100644 --- a/crates/rib/src/local_rib.rs +++ b/crates/rib/src/local_rib.rs @@ -171,7 +171,7 @@ async fn run_actor(mut rx: mpsc::Receiver, events: broadcast::Sender { - table.insert(route.prefix.clone(), route.clone()); + table.insert(route.prefix, route.clone()); let _ = events.send(LocalRibEvent::Announced(route)); let _ = reply.send(()); } diff --git a/crates/server/src/advertise.rs b/crates/server/src/advertise.rs index 3cbd491..8aa81c3 100644 --- a/crates/server/src/advertise.rs +++ b/crates/server/src/advertise.rs @@ -178,10 +178,10 @@ pub fn build_announce( ]; let mut announced_routes = vec![]; - match (route.prefix.address_family, next_hop) { + match (route.prefix.address_family(), next_hop) { (AddressFamilyId::Ipv4, IpAddr::V4(nh)) => { path_attributes.push(PathAttribute::NextHop(NextHopPathAttribute(nh))); - announced_routes.push(route.prefix.clone()); + announced_routes.push(route.prefix); } (AddressFamilyId::Ipv6, IpAddr::V6(_)) => {} _ => return None, @@ -197,12 +197,12 @@ pub fn build_announce( attrs.communities.clone(), ))); } - if let (AddressFamilyId::Ipv6, IpAddr::V6(nh)) = (route.prefix.address_family, next_hop) { + if let (AddressFamilyId::Ipv6, IpAddr::V6(nh)) = (route.prefix.address_family(), next_hop) { path_attributes.push(PathAttribute::MpReachNlri(MpReachNlriPathAttribute { afi: Afi::IPV6, safi: Safi::UNICAST, next_hop: NlriNextHop::Ipv6(nh), - prefixes: vec![route.prefix.clone()], + prefixes: vec![route.prefix], })); } path_attributes.extend(as4_path); @@ -223,9 +223,9 @@ pub fn build_announce( /// Builds the UPDATE withdrawing `prefix`. pub fn build_withdraw(prefix: &IpPrefix) -> UpdateMessage { - match prefix.address_family { + match prefix.address_family() { AddressFamilyId::Ipv4 => UpdateMessage { - withdrawn_routes: vec![prefix.clone()], + withdrawn_routes: vec![*prefix], path_attributes: vec![], announced_routes: vec![], }, @@ -234,7 +234,7 @@ pub fn build_withdraw(prefix: &IpPrefix) -> UpdateMessage { path_attributes: vec![PathAttribute::MpUnreachNlri(MpUnreachNlriPathAttribute { afi: Afi::IPV6, safi: Safi::UNICAST, - prefixes: vec![prefix.clone()], + prefixes: vec![*prefix], })], announced_routes: vec![], }, diff --git a/crates/server/src/family.rs b/crates/server/src/family.rs index ebaaec6..c45e28c 100644 --- a/crates/server/src/family.rs +++ b/crates/server/src/family.rs @@ -43,7 +43,7 @@ impl FamilySet { /// Whether a unicast route for `prefix` may be exchanged. pub fn carries(&self, prefix: &IpPrefix) -> bool { - self.contains(AfiSafi::unicast(prefix.address_family)) + self.contains(AfiSafi::unicast(prefix.address_family())) } pub fn is_empty(&self) -> bool { diff --git a/crates/server/src/fsm.rs b/crates/server/src/fsm.rs index 84f6aa1..a80d1cf 100644 --- a/crates/server/src/fsm.rs +++ b/crates/server/src/fsm.rs @@ -625,7 +625,7 @@ mod tests { next_hop: NlriNextHop::Ipv6(std::net::Ipv6Addr::LOCALHOST), prefixes: vec![IpPrefix::try_from("2001:db8::/32").unwrap()], })], - announced_routes: vec![v4.clone()], + announced_routes: vec![v4], }; let actions = fsm.handle(Event::Message(Message::Update(update)));