[pve-devel] [PATCH proxmox-ve-rs v4 1/1] ve-config: move types to proxmox-network-types

Christoph Heiss c.heiss at proxmox.com
Tue Apr 15 12:51:51 CEST 2025


FYI: Doesn't apply anymore on latest proxmox-ve-rs master and needs a
rebase, probably due to

  746d7a0be "partially fix #6176: config: guest: change default for
             firewall key"

On Fri Apr 4, 2025 at 3:55 PM CEST, Stefan Hanreich wrote:
> Some of the types defined in this crate have been moved to
> proxmox-network-types so they can be re-used across crates. This is a
> preparation for the fabrics patch series, where those types will get
> used by addtional, new, crates.
>
> Remove the types that have been moved and adjust the imports for them
> accordingly. This patch has no functional changes, except for one in
> the firewall ipset type. There we had a blanket From implementation:
>
>   impl<T: Into<Cidr>> From<T> for IpsetAddress
>
> This is no longer possible due to the orphan rule, so it has been
> replaced with a simple From<Cidr> implementation. All call sites that
> used the blanket implementation for the trait have been adjusted as
> well.
>
> Signed-off-by: Stefan Hanreich <s.hanreich at proxmox.com>
> ---
>
> Notes:
>     This depends on the changes in the proxmox repository.
>
>  Cargo.toml                                    |    2 +
>  proxmox-ve-config/Cargo.toml                  |    1 +
>  proxmox-ve-config/debian/control              |    6 +-
>  proxmox-ve-config/src/firewall/cluster.rs     |    3 +-
>  proxmox-ve-config/src/firewall/ct_helper.rs   |    2 +-
>  proxmox-ve-config/src/firewall/host.rs        |    4 +-
>  .../src/firewall/types/address.rs             | 1395 +----------------
>  proxmox-ve-config/src/firewall/types/alias.rs |    2 +-
>  proxmox-ve-config/src/firewall/types/ipset.rs |    8 +-
>  proxmox-ve-config/src/firewall/types/mod.rs   |    1 -
>  proxmox-ve-config/src/firewall/types/rule.rs  |    5 +-
>  .../src/firewall/types/rule_match.rs          |    6 +-
>  proxmox-ve-config/src/guest/vm.rs             |   87 +-
>  proxmox-ve-config/src/host/utils.rs           |    2 +-
>  proxmox-ve-config/src/sdn/config.rs           |    9 +-
>  proxmox-ve-config/src/sdn/ipam.rs             |   11 +-
>  proxmox-ve-config/src/sdn/mod.rs              |    3 +-
>  proxmox-ve-config/tests/sdn/main.rs           |   11 +-
>  18 files changed, 60 insertions(+), 1498 deletions(-)
>
> diff --git a/Cargo.toml b/Cargo.toml
> index dc7f312..b6e6df7 100644
> --- a/Cargo.toml
> +++ b/Cargo.toml
> @@ -15,3 +15,5 @@ homepage = "https://proxmox.com"
>  exclude = [ "debian" ]
>  rust-version = "1.82"
>
> +[workspace.dependencies]
> +proxmox-network-types = { version = "0.1" }
> diff --git a/proxmox-ve-config/Cargo.toml b/proxmox-ve-config/Cargo.toml
> index b20ced1..2f3544b 100644
> --- a/proxmox-ve-config/Cargo.toml
> +++ b/proxmox-ve-config/Cargo.toml
> @@ -17,6 +17,7 @@ serde_json = "1"
>  serde_plain = "1"
>  serde_with = "3"
>
> +proxmox-network-types = { workspace = true }
>  proxmox-schema = "4"
>  proxmox-sys = "0.6.4"
>  proxmox-sortable-macro = "0.1.3"
> diff --git a/proxmox-ve-config/debian/control b/proxmox-ve-config/debian/control
> index 60ebcbc..d498520 100644
> --- a/proxmox-ve-config/debian/control
> +++ b/proxmox-ve-config/debian/control
> @@ -2,13 +2,14 @@ Source: rust-proxmox-ve-config
>  Section: rust
>  Priority: optional
>  Build-Depends: debhelper-compat (= 13),
> - dh-sequence-cargo,
> - cargo:native <!nocheck>,
> + dh-sequence-cargo
> +Build-Depends-Arch: cargo:native <!nocheck>,
>   rustc:native <!nocheck>,
>   libstd-rust-dev <!nocheck>,
>   librust-anyhow-1+default-dev <!nocheck>,
>   librust-log-0.4+default-dev <!nocheck>,
>   librust-nix-0.26+default-dev <!nocheck>,
> + librust-proxmox-network-types-0.1+default-dev <!nocheck>,
>   librust-proxmox-schema-4+default-dev <!nocheck>,
>   librust-proxmox-sortable-macro-0.1+default-dev (>= 0.1.3-~~) <!nocheck>,
>   librust-proxmox-sys-0.6+default-dev (>= 0.6.4-~~) <!nocheck>,
> @@ -33,6 +34,7 @@ Depends:
>   librust-anyhow-1+default-dev,
>   librust-log-0.4+default-dev,
>   librust-nix-0.26+default-dev,
> + librust-proxmox-network-types-0.1+default-dev,
>   librust-proxmox-schema-4+default-dev,
>   librust-proxmox-sortable-macro-0.1+default-dev (>= 0.1.3-~~),
>   librust-proxmox-sys-0.6+default-dev (>= 0.6.4-~~),
> diff --git a/proxmox-ve-config/src/firewall/cluster.rs b/proxmox-ve-config/src/firewall/cluster.rs
> index ce3dd53..8879a69 100644
> --- a/proxmox-ve-config/src/firewall/cluster.rs
> +++ b/proxmox-ve-config/src/firewall/cluster.rs
> @@ -134,6 +134,8 @@ pub struct Options {
>
>  #[cfg(test)]
>  mod tests {
> +    use proxmox_network_types::ip_address::Cidr;
> +
>      use crate::firewall::types::{
>          address::IpList,
>          alias::{AliasName, AliasScope},
> @@ -143,7 +145,6 @@ mod tests {
>          rule_match::{
>              Icmpv6, Icmpv6Code, IpAddrMatch, IpMatch, Ports, Protocol, RuleMatch, Tcp, Udp,
>          },
> -        Cidr,
>      };
>
>      use super::*;
> diff --git a/proxmox-ve-config/src/firewall/ct_helper.rs b/proxmox-ve-config/src/firewall/ct_helper.rs
> index 40e4fee..57fe9aa 100644
> --- a/proxmox-ve-config/src/firewall/ct_helper.rs
> +++ b/proxmox-ve-config/src/firewall/ct_helper.rs
> @@ -3,7 +3,7 @@ use serde::Deserialize;
>  use std::collections::HashMap;
>  use std::sync::OnceLock;
>
> -use crate::firewall::types::address::Family;
> +use proxmox_network_types::ip_address::Family;
>  use crate::firewall::types::rule_match::{Ports, Protocol, Tcp, Udp};
>
>  #[derive(Clone, Debug, Deserialize)]
> diff --git a/proxmox-ve-config/src/firewall/host.rs b/proxmox-ve-config/src/firewall/host.rs
> index 394896c..dcb49bb 100644
> --- a/proxmox-ve-config/src/firewall/host.rs
> +++ b/proxmox-ve-config/src/firewall/host.rs
> @@ -4,13 +4,15 @@ use std::net::IpAddr;
>  use anyhow::{bail, Error};
>  use serde::Deserialize;
>
> +use proxmox_network_types::ip_address::Cidr;
> +
>  use crate::host::utils::{host_ips, network_interface_cidrs};
>  use proxmox_sys::nodename;
>
>  use crate::firewall::parse;
>  use crate::firewall::types::log::LogLevel;
>  use crate::firewall::types::rule::Direction;
> -use crate::firewall::types::{Alias, Cidr, Rule};
> +use crate::firewall::types::{Alias, Rule};
>
>  /// default setting for the enabled key
>  pub const HOST_ENABLED_DEFAULT: bool = true;
> diff --git a/proxmox-ve-config/src/firewall/types/address.rs b/proxmox-ve-config/src/firewall/types/address.rs
> index 9b73d3d..548b813 100644
> --- a/proxmox-ve-config/src/firewall/types/address.rs
> +++ b/proxmox-ve-config/src/firewall/types/address.rs
> @@ -1,600 +1,9 @@
> -use std::fmt::{self, Display};
> -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
> +use std::fmt;
>  use std::ops::Deref;
>
> -use anyhow::{bail, format_err, Error};
> -use serde_with::{DeserializeFromStr, SerializeDisplay};
> -
> -#[derive(Clone, Copy, Debug, Eq, PartialEq)]
> -pub enum Family {
> -    V4,
> -    V6,
> -}
> -
> -impl Family {
> -    pub fn is_ipv4(&self) -> bool {
> -        *self == Self::V4
> -    }
> -
> -    pub fn is_ipv6(&self) -> bool {
> -        *self == Self::V6
> -    }
> -}
> -
> -impl fmt::Display for Family {
> -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
> -        match self {
> -            Family::V4 => f.write_str("Ipv4"),
> -            Family::V6 => f.write_str("Ipv6"),
> -        }
> -    }
> -}
> -
> -#[derive(
> -    Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash, SerializeDisplay, DeserializeFromStr,
> -)]
> -pub enum Cidr {
> -    Ipv4(Ipv4Cidr),
> -    Ipv6(Ipv6Cidr),
> -}
> -
> -impl Cidr {
> -    pub fn new_v4(addr: impl Into<Ipv4Addr>, mask: u8) -> Result<Self, Error> {
> -        Ok(Cidr::Ipv4(Ipv4Cidr::new(addr, mask)?))
> -    }
> -
> -    pub fn new_v6(addr: impl Into<Ipv6Addr>, mask: u8) -> Result<Self, Error> {
> -        Ok(Cidr::Ipv6(Ipv6Cidr::new(addr, mask)?))
> -    }
> -
> -    pub const fn family(&self) -> Family {
> -        match self {
> -            Cidr::Ipv4(_) => Family::V4,
> -            Cidr::Ipv6(_) => Family::V6,
> -        }
> -    }
> -
> -    pub fn is_ipv4(&self) -> bool {
> -        matches!(self, Cidr::Ipv4(_))
> -    }
> -
> -    pub fn is_ipv6(&self) -> bool {
> -        matches!(self, Cidr::Ipv6(_))
> -    }
> -
> -    pub fn contains_address(&self, ip: &IpAddr) -> bool {
> -        match (self, ip) {
> -            (Cidr::Ipv4(cidr), IpAddr::V4(ip)) => cidr.contains_address(ip),
> -            (Cidr::Ipv6(cidr), IpAddr::V6(ip)) => cidr.contains_address(ip),
> -            _ => false,
> -        }
> -    }
> -}
> -
> -impl fmt::Display for Cidr {
> -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
> -        match self {
> -            Self::Ipv4(ip) => f.write_str(ip.to_string().as_str()),
> -            Self::Ipv6(ip) => f.write_str(ip.to_string().as_str()),
> -        }
> -    }
> -}
> -
> -impl std::str::FromStr for Cidr {
> -    type Err = Error;
> -
> -    fn from_str(s: &str) -> Result<Self, Error> {
> -        if let Ok(ip) = s.parse::<Ipv4Cidr>() {
> -            return Ok(Cidr::Ipv4(ip));
> -        }
> -
> -        if let Ok(ip) = s.parse::<Ipv6Cidr>() {
> -            return Ok(Cidr::Ipv6(ip));
> -        }
> -
> -        bail!("invalid ip address or CIDR: {s:?}");
> -    }
> -}
> -
> -impl From<Ipv4Cidr> for Cidr {
> -    fn from(cidr: Ipv4Cidr) -> Self {
> -        Cidr::Ipv4(cidr)
> -    }
> -}
> -
> -impl From<Ipv6Cidr> for Cidr {
> -    fn from(cidr: Ipv6Cidr) -> Self {
> -        Cidr::Ipv6(cidr)
> -    }
> -}
> -
> -impl From<IpAddr> for Cidr {
> -    fn from(value: IpAddr) -> Self {
> -        match value {
> -            IpAddr::V4(addr) => Ipv4Cidr::from(addr).into(),
> -            IpAddr::V6(addr) => Ipv6Cidr::from(addr).into(),
> -        }
> -    }
> -}
> -
> -const IPV4_LENGTH: u8 = 32;
> -
> -#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
> -pub struct Ipv4Cidr {
> -    addr: Ipv4Addr,
> -    mask: u8,
> -}
> -
> -impl Ipv4Cidr {
> -    pub fn new(addr: impl Into<Ipv4Addr>, mask: u8) -> Result<Self, Error> {
> -        if mask > 32 {
> -            bail!("mask out of range for ipv4 cidr ({mask})");
> -        }
> -
> -        Ok(Self {
> -            addr: addr.into(),
> -            mask,
> -        })
> -    }
> -
> -    pub fn contains_address(&self, other: &Ipv4Addr) -> bool {
> -        let bits = u32::from_be_bytes(self.addr.octets());
> -        let other_bits = u32::from_be_bytes(other.octets());
> -
> -        let shift_amount: u32 = IPV4_LENGTH.saturating_sub(self.mask).into();
> -
> -        bits.checked_shr(shift_amount).unwrap_or(0)
> -            == other_bits.checked_shr(shift_amount).unwrap_or(0)
> -    }
> -
> -    pub fn address(&self) -> &Ipv4Addr {
> -        &self.addr
> -    }
> -
> -    pub fn mask(&self) -> u8 {
> -        self.mask
> -    }
> -}
> -
> -impl<T: Into<Ipv4Addr>> From<T> for Ipv4Cidr {
> -    fn from(value: T) -> Self {
> -        Self {
> -            addr: value.into(),
> -            mask: 32,
> -        }
> -    }
> -}
> -
> -impl std::str::FromStr for Ipv4Cidr {
> -    type Err = Error;
> -
> -    fn from_str(s: &str) -> Result<Self, Error> {
> -        Ok(match s.find('/') {
> -            None => Self {
> -                addr: s.parse()?,
> -                mask: 32,
> -            },
> -            Some(pos) => {
> -                let mask: u8 = s[(pos + 1)..]
> -                    .parse()
> -                    .map_err(|_| format_err!("invalid mask in ipv4 cidr: {s:?}"))?;
> -
> -                Self::new(s[..pos].parse::<Ipv4Addr>()?, mask)?
> -            }
> -        })
> -    }
> -}
> -
> -impl fmt::Display for Ipv4Cidr {
> -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
> -        write!(f, "{}/{}", &self.addr, self.mask)
> -    }
> -}
> -
> -const IPV6_LENGTH: u8 = 128;
> -
> -#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
> -pub struct Ipv6Cidr {
> -    addr: Ipv6Addr,
> -    mask: u8,
> -}
> -
> -impl Ipv6Cidr {
> -    pub fn new(addr: impl Into<Ipv6Addr>, mask: u8) -> Result<Self, Error> {
> -        if mask > IPV6_LENGTH {
> -            bail!("mask out of range for ipv6 cidr");
> -        }
> -
> -        Ok(Self {
> -            addr: addr.into(),
> -            mask,
> -        })
> -    }
> -
> -    pub fn contains_address(&self, other: &Ipv6Addr) -> bool {
> -        let bits = u128::from_be_bytes(self.addr.octets());
> -        let other_bits = u128::from_be_bytes(other.octets());
> -
> -        let shift_amount: u32 = IPV6_LENGTH.saturating_sub(self.mask).into();
> -
> -        bits.checked_shr(shift_amount).unwrap_or(0)
> -            == other_bits.checked_shr(shift_amount).unwrap_or(0)
> -    }
> -
> -    pub fn address(&self) -> &Ipv6Addr {
> -        &self.addr
> -    }
> -
> -    pub fn mask(&self) -> u8 {
> -        self.mask
> -    }
> -}
> -
> -impl std::str::FromStr for Ipv6Cidr {
> -    type Err = Error;
> -
> -    fn from_str(s: &str) -> Result<Self, Error> {
> -        Ok(match s.find('/') {
> -            None => Self {
> -                addr: s.parse()?,
> -                mask: 128,
> -            },
> -            Some(pos) => {
> -                let mask: u8 = s[(pos + 1)..]
> -                    .parse()
> -                    .map_err(|_| format_err!("invalid mask in ipv6 cidr: {s:?}"))?;
> -
> -                Self::new(s[..pos].parse::<Ipv6Addr>()?, mask)?
> -            }
> -        })
> -    }
> -}
> -
> -impl fmt::Display for Ipv6Cidr {
> -    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
> -        write!(f, "{}/{}", &self.addr, self.mask)
> -    }
> -}
> -
> -impl<T: Into<Ipv6Addr>> From<T> for Ipv6Cidr {
> -    fn from(addr: T) -> Self {
> -        Self {
> -            addr: addr.into(),
> -            mask: 128,
> -        }
> -    }
> -}
> -
> -#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)]
> -pub enum IpRangeError {
> -    MismatchedFamilies,
> -    StartGreaterThanLast,
> -    InvalidFormat,
> -}
> -
> -impl std::error::Error for IpRangeError {}
> -
> -impl Display for IpRangeError {
> -    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> -        f.write_str(match self {
> -            IpRangeError::MismatchedFamilies => "mismatched ip address families",
> -            IpRangeError::StartGreaterThanLast => "start is greater than last",
> -            IpRangeError::InvalidFormat => "invalid ip range format",
> -        })
> -    }
> -}
> -
> -/// Represents a range of IPv4 or IPv6 addresses.
> -///
> -/// For more information see [`AddressRange`]
> -#[derive(
> -    Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, SerializeDisplay, DeserializeFromStr,
> -)]
> -pub enum IpRange {
> -    V4(AddressRange<Ipv4Addr>),
> -    V6(AddressRange<Ipv6Addr>),
> -}
> -
> -impl IpRange {
> -    /// Returns the family of the IpRange.
> -    pub fn family(&self) -> Family {
> -        match self {
> -            IpRange::V4(_) => Family::V4,
> -            IpRange::V6(_) => Family::V6,
> -        }
> -    }
> -
> -    /// Creates a new [`IpRange`] from two [`IpAddr`].
> -    ///
> -    /// # Errors
> -    ///
> -    /// This function will return an error if start and last IP address are not from the same family.
> -    pub fn new(start: impl Into<IpAddr>, last: impl Into<IpAddr>) -> Result<Self, IpRangeError> {
> -        match (start.into(), last.into()) {
> -            (IpAddr::V4(start), IpAddr::V4(last)) => Self::new_v4(start, last),
> -            (IpAddr::V6(start), IpAddr::V6(last)) => Self::new_v6(start, last),
> -            _ => Err(IpRangeError::MismatchedFamilies),
> -        }
> -    }
> -
> -    /// construct a new Ipv4 Range
> -    pub fn new_v4(
> -        start: impl Into<Ipv4Addr>,
> -        last: impl Into<Ipv4Addr>,
> -    ) -> Result<Self, IpRangeError> {
> -        Ok(IpRange::V4(AddressRange::new_v4(start, last)?))
> -    }
> -
> -    pub fn new_v6(
> -        start: impl Into<Ipv6Addr>,
> -        last: impl Into<Ipv6Addr>,
> -    ) -> Result<Self, IpRangeError> {
> -        Ok(IpRange::V6(AddressRange::new_v6(start, last)?))
> -    }
> -
> -    /// Converts an IpRange into the minimal amount of CIDRs.
> -    ///
> -    /// see the concrete implementations of [`AddressRange<Ipv4Addr>`] or [`AddressRange<Ipv6Addr>`]
> -    /// respectively
> -    pub fn to_cidrs(&self) -> Vec<Cidr> {
> -        match self {
> -            IpRange::V4(range) => range.to_cidrs().into_iter().map(Cidr::from).collect(),
> -            IpRange::V6(range) => range.to_cidrs().into_iter().map(Cidr::from).collect(),
> -        }
> -    }
> -}
> -
> -impl std::str::FromStr for IpRange {
> -    type Err = IpRangeError;
> -
> -    fn from_str(s: &str) -> Result<Self, Self::Err> {
> -        if let Ok(range) = s.parse() {
> -            return Ok(IpRange::V4(range));
> -        }
> -
> -        if let Ok(range) = s.parse() {
> -            return Ok(IpRange::V6(range));
> -        }
> -
> -        Err(IpRangeError::InvalidFormat)
> -    }
> -}
> -
> -impl fmt::Display for IpRange {
> -    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> -        match self {
> -            IpRange::V4(range) => range.fmt(f),
> -            IpRange::V6(range) => range.fmt(f),
> -        }
> -    }
> -}
> -
> -/// Represents a range of IP addresses from start to last.
> -///
> -/// This type is for encapsulation purposes for the [`IpRange`] enum and should be instantiated via
> -/// that enum.
> -///
> -/// # Invariants
> -///
> -/// * start and last have the same IP address family
> -/// * start is less than or equal to last
> -///
> -/// # Textual representation
> -///
> -/// Two IP addresses separated by a hyphen, e.g.: `127.0.0.1-127.0.0.255`
> -#[derive(
> -    Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, SerializeDisplay, DeserializeFromStr,
> -)]
> -pub struct AddressRange<T> {
> -    start: T,
> -    last: T,
> -}
> -
> -impl AddressRange<Ipv4Addr> {
> -    pub(crate) fn new_v4(
> -        start: impl Into<Ipv4Addr>,
> -        last: impl Into<Ipv4Addr>,
> -    ) -> Result<AddressRange<Ipv4Addr>, IpRangeError> {
> -        let (start, last) = (start.into(), last.into());
> -
> -        if start > last {
> -            return Err(IpRangeError::StartGreaterThanLast);
> -        }
> -
> -        Ok(Self { start, last })
> -    }
> -
> -    /// Returns the minimum amount of CIDRs that exactly represent the range
> -    ///
> -    /// The idea behind this algorithm is as follows:
> -    ///
> -    /// Start iterating with current = start of the IP range
> -    ///
> -    /// Find two netmasks
> -    /// * The largest CIDR that the current IP can be the first of
> -    /// * The largest CIDR that *only* contains IPs from current - last
> -    ///
> -    /// Add the smaller of the two CIDRs to our result and current to the first IP that is in
> -    /// the range but not in the CIDR we just added. Proceed until we reached the last of the IP
> -    /// range.
> -    ///
> -    pub fn to_cidrs(&self) -> Vec<Ipv4Cidr> {
> -        let mut cidrs = Vec::new();
> -
> -        let mut current = u32::from_be_bytes(self.start.octets());
> -        let last = u32::from_be_bytes(self.last.octets());
> -
> -        if current == last {
> -            // valid Ipv4 since netmask is 32
> -            cidrs.push(Ipv4Cidr::new(current, 32).unwrap());
> -            return cidrs;
> -        }
> -
> -        // special case this, since this is the only possibility of overflow
> -        // when calculating delta_min_mask - makes everything a lot easier
> -        if current == u32::MIN && last == u32::MAX {
> -            // valid Ipv4 since it is `0.0.0.0/0`
> -            cidrs.push(Ipv4Cidr::new(current, 0).unwrap());
> -            return cidrs;
> -        }
> -
> -        while current <= last {
> -            // netmask of largest CIDR that current IP can be the first of
> -            // cast is safe, because trailing zeroes can at most be 32
> -            let current_max_mask = IPV4_LENGTH - (current.trailing_zeros() as u8);
> -
> -            // netmask of largest CIDR that *only* contains IPs of the remaining range
> -            // is at most 32 due to unwrap_or returning 32 and ilog2 being at most 31
> -            let delta_min_mask = ((last - current) + 1) // safe due to special case above
> -                .checked_ilog2() // should never occur due to special case, but for good measure
> -                .map(|mask| IPV4_LENGTH - mask as u8)
> -                .unwrap_or(IPV4_LENGTH);
> -
> -            // at most 32, due to current/delta being at most 32
> -            let netmask = u8::max(current_max_mask, delta_min_mask);
> -
> -            // netmask is at most 32, therefore safe to unwrap
> -            cidrs.push(Ipv4Cidr::new(current, netmask).unwrap());
> -
> -            let delta = 2u32.saturating_pow((IPV4_LENGTH - netmask).into());
> -
> -            if let Some(result) = current.checked_add(delta) {
> -                current = result
> -            } else {
> -                // we reached the end of IP address space
> -                break;
> -            }
> -        }
> -
> -        cidrs
> -    }
> -}
> -
> -impl AddressRange<Ipv6Addr> {
> -    pub(crate) fn new_v6(
> -        start: impl Into<Ipv6Addr>,
> -        last: impl Into<Ipv6Addr>,
> -    ) -> Result<AddressRange<Ipv6Addr>, IpRangeError> {
> -        let (start, last) = (start.into(), last.into());
> -
> -        if start > last {
> -            return Err(IpRangeError::StartGreaterThanLast);
> -        }
> -
> -        Ok(Self { start, last })
> -    }
> -
> -    /// Returns the minimum amount of CIDRs that exactly represent the [`AddressRange`].
> -    ///
> -    /// This function works analogous to the IPv4 version, please refer to the respective
> -    /// documentation of [`AddressRange<Ipv4Addr>`]
> -    pub fn to_cidrs(&self) -> Vec<Ipv6Cidr> {
> -        let mut cidrs = Vec::new();
> -
> -        let mut current = u128::from_be_bytes(self.start.octets());
> -        let last = u128::from_be_bytes(self.last.octets());
> -
> -        if current == last {
> -            // valid Ipv6 since netmask is 128
> -            cidrs.push(Ipv6Cidr::new(current, 128).unwrap());
> -            return cidrs;
> -        }
> -
> -        // special case this, since this is the only possibility of overflow
> -        // when calculating delta_min_mask - makes everything a lot easier
> -        if current == u128::MIN && last == u128::MAX {
> -            // valid Ipv6 since it is `::/0`
> -            cidrs.push(Ipv6Cidr::new(current, 0).unwrap());
> -            return cidrs;
> -        }
> -
> -        while current <= last {
> -            // netmask of largest CIDR that current IP can be the first of
> -            // cast is safe, because trailing zeroes can at most be 128
> -            let current_max_mask = IPV6_LENGTH - (current.trailing_zeros() as u8);
> -
> -            // netmask of largest CIDR that *only* contains IPs of the remaining range
> -            // is at most 128 due to unwrap_or returning 128 and ilog2 being at most 31
> -            let delta_min_mask = ((last - current) + 1) // safe due to special case above
> -                .checked_ilog2() // should never occur due to special case, but for good measure
> -                .map(|mask| IPV6_LENGTH - mask as u8)
> -                .unwrap_or(IPV6_LENGTH);
> -
> -            // at most 128, due to current/delta being at most 128
> -            let netmask = u8::max(current_max_mask, delta_min_mask);
> -
> -            // netmask is at most 128, therefore safe to unwrap
> -            cidrs.push(Ipv6Cidr::new(current, netmask).unwrap());
> -
> -            let delta = 2u128.saturating_pow((IPV6_LENGTH - netmask).into());
> -
> -            if let Some(result) = current.checked_add(delta) {
> -                current = result
> -            } else {
> -                // we reached the end of IP address space
> -                break;
> -            }
> -        }
> -
> -        cidrs
> -    }
> -}
> -
> -impl<T> AddressRange<T> {
> -    pub fn start(&self) -> &T {
> -        &self.start
> -    }
> -
> -    pub fn last(&self) -> &T {
> -        &self.last
> -    }
> -}
> -
> -impl std::str::FromStr for AddressRange<Ipv4Addr> {
> -    type Err = IpRangeError;
> -
> -    fn from_str(s: &str) -> Result<Self, Self::Err> {
> -        if let Some((start, last)) = s.split_once('-') {
> -            let start_address = start
> -                .parse::<Ipv4Addr>()
> -                .map_err(|_| IpRangeError::InvalidFormat)?;
> -
> -            let last_address = last
> -                .parse::<Ipv4Addr>()
> -                .map_err(|_| IpRangeError::InvalidFormat)?;
> -
> -            return Self::new_v4(start_address, last_address);
> -        }
> -
> -        Err(IpRangeError::InvalidFormat)
> -    }
> -}
> -
> -impl std::str::FromStr for AddressRange<Ipv6Addr> {
> -    type Err = IpRangeError;
> -
> -    fn from_str(s: &str) -> Result<Self, Self::Err> {
> -        if let Some((start, last)) = s.split_once('-') {
> -            let start_address = start
> -                .parse::<Ipv6Addr>()
> -                .map_err(|_| IpRangeError::InvalidFormat)?;
> -
> -            let last_address = last
> -                .parse::<Ipv6Addr>()
> -                .map_err(|_| IpRangeError::InvalidFormat)?;
> -
> -            return Self::new_v6(start_address, last_address);
> -        }
> -
> -        Err(IpRangeError::InvalidFormat)
> -    }
> -}
> -
> -impl<T: fmt::Display> fmt::Display for AddressRange<T> {
> -    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> -        write!(f, "{}-{}", self.start, self.last)
> -    }
> -}
> +use anyhow::{bail, Error};
> +use proxmox_network_types::ip_address::{Cidr, Family, IpRange};
> +use serde_with::DeserializeFromStr;
>
>  #[derive(Clone, Debug)]
>  #[cfg_attr(test, derive(Eq, PartialEq))]
> @@ -741,84 +150,6 @@ impl IpList {
>  #[cfg(test)]
>  mod tests {
>      use super::*;
> -    use std::net::{Ipv4Addr, Ipv6Addr};
> -
> -    #[test]
> -    fn test_v4_cidr() {
> -        let mut cidr: Ipv4Cidr = "0.0.0.0/0".parse().expect("valid IPv4 CIDR");
> -
> -        assert_eq!(cidr.addr, Ipv4Addr::new(0, 0, 0, 0));
> -        assert_eq!(cidr.mask, 0);
> -
> -        assert!(cidr.contains_address(&Ipv4Addr::new(0, 0, 0, 0)));
> -        assert!(cidr.contains_address(&Ipv4Addr::new(255, 255, 255, 255)));
> -
> -        cidr = "192.168.100.1".parse().expect("valid IPv4 CIDR");
> -
> -        assert_eq!(cidr.addr, Ipv4Addr::new(192, 168, 100, 1));
> -        assert_eq!(cidr.mask, 32);
> -
> -        assert!(cidr.contains_address(&Ipv4Addr::new(192, 168, 100, 1)));
> -        assert!(!cidr.contains_address(&Ipv4Addr::new(192, 168, 100, 2)));
> -        assert!(!cidr.contains_address(&Ipv4Addr::new(192, 168, 100, 0)));
> -
> -        cidr = "10.100.5.0/24".parse().expect("valid IPv4 CIDR");
> -
> -        assert_eq!(cidr.mask, 24);
> -
> -        assert!(cidr.contains_address(&Ipv4Addr::new(10, 100, 5, 0)));
> -        assert!(cidr.contains_address(&Ipv4Addr::new(10, 100, 5, 1)));
> -        assert!(cidr.contains_address(&Ipv4Addr::new(10, 100, 5, 100)));
> -        assert!(cidr.contains_address(&Ipv4Addr::new(10, 100, 5, 255)));
> -        assert!(!cidr.contains_address(&Ipv4Addr::new(10, 100, 4, 255)));
> -        assert!(!cidr.contains_address(&Ipv4Addr::new(10, 100, 6, 0)));
> -
> -        "0.0.0.0/-1".parse::<Ipv4Cidr>().unwrap_err();
> -        "0.0.0.0/33".parse::<Ipv4Cidr>().unwrap_err();
> -        "256.256.256.256/10".parse::<Ipv4Cidr>().unwrap_err();
> -
> -        "fe80::1/64".parse::<Ipv4Cidr>().unwrap_err();
> -        "qweasd".parse::<Ipv4Cidr>().unwrap_err();
> -        "".parse::<Ipv4Cidr>().unwrap_err();
> -    }
> -
> -    #[test]
> -    fn test_v6_cidr() {
> -        let mut cidr: Ipv6Cidr = "abab::1/64".parse().expect("valid IPv6 CIDR");
> -
> -        assert_eq!(cidr.addr, Ipv6Addr::new(0xABAB, 0, 0, 0, 0, 0, 0, 1));
> -        assert_eq!(cidr.mask, 64);
> -
> -        assert!(cidr.contains_address(&Ipv6Addr::new(0xABAB, 0, 0, 0, 0, 0, 0, 0)));
> -        assert!(cidr.contains_address(&Ipv6Addr::new(
> -            0xABAB, 0, 0, 0, 0xAAAA, 0xAAAA, 0xAAAA, 0xAAAA
> -        )));
> -        assert!(cidr.contains_address(&Ipv6Addr::new(
> -            0xABAB, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
> -        )));
> -        assert!(!cidr.contains_address(&Ipv6Addr::new(0xABAB, 0, 0, 1, 0, 0, 0, 0)));
> -        assert!(!cidr.contains_address(&Ipv6Addr::new(
> -            0xABAA, 0, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
> -        )));
> -
> -        cidr = "eeee::1".parse().expect("valid IPv6 CIDR");
> -
> -        assert_eq!(cidr.mask, 128);
> -
> -        assert!(cidr.contains_address(&Ipv6Addr::new(0xEEEE, 0, 0, 0, 0, 0, 0, 1)));
> -        assert!(!cidr.contains_address(&Ipv6Addr::new(
> -            0xEEED, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
> -        )));
> -        assert!(!cidr.contains_address(&Ipv6Addr::new(0xEEEE, 0, 0, 0, 0, 0, 0, 0)));
> -
> -        "eeee::1/-1".parse::<Ipv6Cidr>().unwrap_err();
> -        "eeee::1/129".parse::<Ipv6Cidr>().unwrap_err();
> -        "gggg::1/64".parse::<Ipv6Cidr>().unwrap_err();
> -
> -        "192.168.0.1".parse::<Ipv6Cidr>().unwrap_err();
> -        "qweasd".parse::<Ipv6Cidr>().unwrap_err();
> -        "".parse::<Ipv6Cidr>().unwrap_err();
> -    }
>
>      #[test]
>      fn test_parse_ip_entry() {
> @@ -942,721 +273,5 @@ mod tests {
>          ])
>          .expect_err("cannot mix ip families in ip list");
>      }
> -
> -    #[test]
> -    fn test_ip_range() {
> -        IpRange::new([10, 0, 0, 2], [10, 0, 0, 1]).unwrap_err();
> -
> -        IpRange::new(
> -            [0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x1000],
> -            [0x2001, 0x0db8, 0, 0, 0, 0, 0, 0],
> -        )
> -        .unwrap_err();
> -
> -        let v4_range = IpRange::new([10, 0, 0, 0], [10, 0, 0, 100]).unwrap();
> -        assert_eq!(v4_range.family(), Family::V4);
> -
> -        let v6_range = IpRange::new(
> -            [0x2001, 0x0db8, 0, 0, 0, 0, 0, 0],
> -            [0x2001, 0x0db8, 0, 0, 0, 0, 0, 0x1000],
> -        )
> -        .unwrap();
> -        assert_eq!(v6_range.family(), Family::V6);
> -
> -        "10.0.0.1-10.0.0.100".parse::<IpRange>().unwrap();
> -        "2001:db8::1-2001:db8::f".parse::<IpRange>().unwrap();
> -
> -        "10.0.0.1-2001:db8::1000".parse::<IpRange>().unwrap_err();
> -        "2001:db8::1-192.168.0.2".parse::<IpRange>().unwrap_err();
> -
> -        "10.0.0.1-10.0.0.0".parse::<IpRange>().unwrap_err();
> -        "2001:db8::1-2001:db8::0".parse::<IpRange>().unwrap_err();
> -    }
> -
> -    #[test]
> -    fn test_ipv4_to_cidrs() {
> -        let range = AddressRange::new_v4([192, 168, 0, 100], [192, 168, 0, 100]).unwrap();
> -
> -        assert_eq!(
> -            [Ipv4Cidr::new([192, 168, 0, 100], 32).unwrap()],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([192, 168, 0, 100], [192, 168, 0, 200]).unwrap();
> -
> -        assert_eq!(
> -            [
> -                Ipv4Cidr::new([192, 168, 0, 100], 30).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 104], 29).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 112], 28).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 128], 26).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 192], 29).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 200], 32).unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([192, 168, 0, 101], [192, 168, 0, 200]).unwrap();
> -
> -        assert_eq!(
> -            [
> -                Ipv4Cidr::new([192, 168, 0, 101], 32).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 102], 31).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 104], 29).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 112], 28).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 128], 26).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 192], 29).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 200], 32).unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([192, 168, 0, 101], [192, 168, 0, 101]).unwrap();
> -
> -        assert_eq!(
> -            [Ipv4Cidr::new([192, 168, 0, 101], 32).unwrap()],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([192, 168, 0, 101], [192, 168, 0, 201]).unwrap();
> -
> -        assert_eq!(
> -            [
> -                Ipv4Cidr::new([192, 168, 0, 101], 32).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 102], 31).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 104], 29).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 112], 28).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 128], 26).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 192], 29).unwrap(),
> -                Ipv4Cidr::new([192, 168, 0, 200], 31).unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([192, 168, 0, 0], [192, 168, 0, 255]).unwrap();
> -
> -        assert_eq!(
> -            [Ipv4Cidr::new([192, 168, 0, 0], 24).unwrap(),],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([0, 0, 0, 0], [255, 255, 255, 255]).unwrap();
> -
> -        assert_eq!(
> -            [Ipv4Cidr::new([0, 0, 0, 0], 0).unwrap(),],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([0, 0, 0, 1], [255, 255, 255, 255]).unwrap();
> -
> -        assert_eq!(
> -            [
> -                Ipv4Cidr::new([0, 0, 0, 1], 32).unwrap(),
> -                Ipv4Cidr::new([0, 0, 0, 2], 31).unwrap(),
> -                Ipv4Cidr::new([0, 0, 0, 4], 30).unwrap(),
> -                Ipv4Cidr::new([0, 0, 0, 8], 29).unwrap(),
> -                Ipv4Cidr::new([0, 0, 0, 16], 28).unwrap(),
> -                Ipv4Cidr::new([0, 0, 0, 32], 27).unwrap(),
> -                Ipv4Cidr::new([0, 0, 0, 64], 26).unwrap(),
> -                Ipv4Cidr::new([0, 0, 0, 128], 25).unwrap(),
> -                Ipv4Cidr::new([0, 0, 1, 0], 24).unwrap(),
> -                Ipv4Cidr::new([0, 0, 2, 0], 23).unwrap(),
> -                Ipv4Cidr::new([0, 0, 4, 0], 22).unwrap(),
> -                Ipv4Cidr::new([0, 0, 8, 0], 21).unwrap(),
> -                Ipv4Cidr::new([0, 0, 16, 0], 20).unwrap(),
> -                Ipv4Cidr::new([0, 0, 32, 0], 19).unwrap(),
> -                Ipv4Cidr::new([0, 0, 64, 0], 18).unwrap(),
> -                Ipv4Cidr::new([0, 0, 128, 0], 17).unwrap(),
> -                Ipv4Cidr::new([0, 1, 0, 0], 16).unwrap(),
> -                Ipv4Cidr::new([0, 2, 0, 0], 15).unwrap(),
> -                Ipv4Cidr::new([0, 4, 0, 0], 14).unwrap(),
> -                Ipv4Cidr::new([0, 8, 0, 0], 13).unwrap(),
> -                Ipv4Cidr::new([0, 16, 0, 0], 12).unwrap(),
> -                Ipv4Cidr::new([0, 32, 0, 0], 11).unwrap(),
> -                Ipv4Cidr::new([0, 64, 0, 0], 10).unwrap(),
> -                Ipv4Cidr::new([0, 128, 0, 0], 9).unwrap(),
> -                Ipv4Cidr::new([1, 0, 0, 0], 8).unwrap(),
> -                Ipv4Cidr::new([2, 0, 0, 0], 7).unwrap(),
> -                Ipv4Cidr::new([4, 0, 0, 0], 6).unwrap(),
> -                Ipv4Cidr::new([8, 0, 0, 0], 5).unwrap(),
> -                Ipv4Cidr::new([16, 0, 0, 0], 4).unwrap(),
> -                Ipv4Cidr::new([32, 0, 0, 0], 3).unwrap(),
> -                Ipv4Cidr::new([64, 0, 0, 0], 2).unwrap(),
> -                Ipv4Cidr::new([128, 0, 0, 0], 1).unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([0, 0, 0, 0], [255, 255, 255, 254]).unwrap();
> -
> -        assert_eq!(
> -            [
> -                Ipv4Cidr::new([0, 0, 0, 0], 1).unwrap(),
> -                Ipv4Cidr::new([128, 0, 0, 0], 2).unwrap(),
> -                Ipv4Cidr::new([192, 0, 0, 0], 3).unwrap(),
> -                Ipv4Cidr::new([224, 0, 0, 0], 4).unwrap(),
> -                Ipv4Cidr::new([240, 0, 0, 0], 5).unwrap(),
> -                Ipv4Cidr::new([248, 0, 0, 0], 6).unwrap(),
> -                Ipv4Cidr::new([252, 0, 0, 0], 7).unwrap(),
> -                Ipv4Cidr::new([254, 0, 0, 0], 8).unwrap(),
> -                Ipv4Cidr::new([255, 0, 0, 0], 9).unwrap(),
> -                Ipv4Cidr::new([255, 128, 0, 0], 10).unwrap(),
> -                Ipv4Cidr::new([255, 192, 0, 0], 11).unwrap(),
> -                Ipv4Cidr::new([255, 224, 0, 0], 12).unwrap(),
> -                Ipv4Cidr::new([255, 240, 0, 0], 13).unwrap(),
> -                Ipv4Cidr::new([255, 248, 0, 0], 14).unwrap(),
> -                Ipv4Cidr::new([255, 252, 0, 0], 15).unwrap(),
> -                Ipv4Cidr::new([255, 254, 0, 0], 16).unwrap(),
> -                Ipv4Cidr::new([255, 255, 0, 0], 17).unwrap(),
> -                Ipv4Cidr::new([255, 255, 128, 0], 18).unwrap(),
> -                Ipv4Cidr::new([255, 255, 192, 0], 19).unwrap(),
> -                Ipv4Cidr::new([255, 255, 224, 0], 20).unwrap(),
> -                Ipv4Cidr::new([255, 255, 240, 0], 21).unwrap(),
> -                Ipv4Cidr::new([255, 255, 248, 0], 22).unwrap(),
> -                Ipv4Cidr::new([255, 255, 252, 0], 23).unwrap(),
> -                Ipv4Cidr::new([255, 255, 254, 0], 24).unwrap(),
> -                Ipv4Cidr::new([255, 255, 255, 0], 25).unwrap(),
> -                Ipv4Cidr::new([255, 255, 255, 128], 26).unwrap(),
> -                Ipv4Cidr::new([255, 255, 255, 192], 27).unwrap(),
> -                Ipv4Cidr::new([255, 255, 255, 224], 28).unwrap(),
> -                Ipv4Cidr::new([255, 255, 255, 240], 29).unwrap(),
> -                Ipv4Cidr::new([255, 255, 255, 248], 30).unwrap(),
> -                Ipv4Cidr::new([255, 255, 255, 252], 31).unwrap(),
> -                Ipv4Cidr::new([255, 255, 255, 254], 32).unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([0, 0, 0, 0], [0, 0, 0, 0]).unwrap();
> -
> -        assert_eq!(
> -            [Ipv4Cidr::new([0, 0, 0, 0], 32).unwrap(),],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v4([255, 255, 255, 255], [255, 255, 255, 255]).unwrap();
> -
> -        assert_eq!(
> -            [Ipv4Cidr::new([255, 255, 255, 255], 32).unwrap(),],
> -            range.to_cidrs().as_slice()
> -        );
> -    }
> -
> -    #[test]
> -    fn test_ipv6_to_cidrs() {
> -        let range = AddressRange::new_v6(
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1000],
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1000],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1000], 128).unwrap()],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1000],
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x2000],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1000], 116).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x2000], 128).unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1001],
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x2000],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1001], 128).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1002], 127).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1004], 126).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1008], 125).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1010], 124).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1020], 123).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1040], 122).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1080], 121).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1100], 120).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1200], 119).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1400], 118).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1800], 117).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x2000], 128).unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1001],
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1001],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1001], 128).unwrap(),],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1001],
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x2001],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1001], 128).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1002], 127).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1004], 126).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1008], 125).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1010], 124).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1020], 123).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1040], 122).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1080], 121).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1100], 120).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1200], 119).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1400], 118).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x1800], 117).unwrap(),
> -                Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0x2000], 127).unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0],
> -            [0x2001, 0x0DB8, 0, 0, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [Ipv6Cidr::new([0x2001, 0x0DB8, 0, 0, 0, 0, 0, 0], 64).unwrap()],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [0, 0, 0, 0, 0, 0, 0, 0],
> -            [
> -                0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
> -            ],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [Ipv6Cidr::new([0, 0, 0, 0, 0, 0, 0, 0], 0).unwrap(),],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [0, 0, 0, 0, 0, 0, 0, 0x0001],
> -            [
> -                0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
> -            ],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [
> -                "::1/128".parse::<Ipv6Cidr>().unwrap(),
> -                "::2/127".parse::<Ipv6Cidr>().unwrap(),
> -                "::4/126".parse::<Ipv6Cidr>().unwrap(),
> -                "::8/125".parse::<Ipv6Cidr>().unwrap(),
> -                "::10/124".parse::<Ipv6Cidr>().unwrap(),
> -                "::20/123".parse::<Ipv6Cidr>().unwrap(),
> -                "::40/122".parse::<Ipv6Cidr>().unwrap(),
> -                "::80/121".parse::<Ipv6Cidr>().unwrap(),
> -                "::100/120".parse::<Ipv6Cidr>().unwrap(),
> -                "::200/119".parse::<Ipv6Cidr>().unwrap(),
> -                "::400/118".parse::<Ipv6Cidr>().unwrap(),
> -                "::800/117".parse::<Ipv6Cidr>().unwrap(),
> -                "::1000/116".parse::<Ipv6Cidr>().unwrap(),
> -                "::2000/115".parse::<Ipv6Cidr>().unwrap(),
> -                "::4000/114".parse::<Ipv6Cidr>().unwrap(),
> -                "::8000/113".parse::<Ipv6Cidr>().unwrap(),
> -                "::1:0/112".parse::<Ipv6Cidr>().unwrap(),
> -                "::2:0/111".parse::<Ipv6Cidr>().unwrap(),
> -                "::4:0/110".parse::<Ipv6Cidr>().unwrap(),
> -                "::8:0/109".parse::<Ipv6Cidr>().unwrap(),
> -                "::10:0/108".parse::<Ipv6Cidr>().unwrap(),
> -                "::20:0/107".parse::<Ipv6Cidr>().unwrap(),
> -                "::40:0/106".parse::<Ipv6Cidr>().unwrap(),
> -                "::80:0/105".parse::<Ipv6Cidr>().unwrap(),
> -                "::100:0/104".parse::<Ipv6Cidr>().unwrap(),
> -                "::200:0/103".parse::<Ipv6Cidr>().unwrap(),
> -                "::400:0/102".parse::<Ipv6Cidr>().unwrap(),
> -                "::800:0/101".parse::<Ipv6Cidr>().unwrap(),
> -                "::1000:0/100".parse::<Ipv6Cidr>().unwrap(),
> -                "::2000:0/99".parse::<Ipv6Cidr>().unwrap(),
> -                "::4000:0/98".parse::<Ipv6Cidr>().unwrap(),
> -                "::8000:0/97".parse::<Ipv6Cidr>().unwrap(),
> -                "::1:0:0/96".parse::<Ipv6Cidr>().unwrap(),
> -                "::2:0:0/95".parse::<Ipv6Cidr>().unwrap(),
> -                "::4:0:0/94".parse::<Ipv6Cidr>().unwrap(),
> -                "::8:0:0/93".parse::<Ipv6Cidr>().unwrap(),
> -                "::10:0:0/92".parse::<Ipv6Cidr>().unwrap(),
> -                "::20:0:0/91".parse::<Ipv6Cidr>().unwrap(),
> -                "::40:0:0/90".parse::<Ipv6Cidr>().unwrap(),
> -                "::80:0:0/89".parse::<Ipv6Cidr>().unwrap(),
> -                "::100:0:0/88".parse::<Ipv6Cidr>().unwrap(),
> -                "::200:0:0/87".parse::<Ipv6Cidr>().unwrap(),
> -                "::400:0:0/86".parse::<Ipv6Cidr>().unwrap(),
> -                "::800:0:0/85".parse::<Ipv6Cidr>().unwrap(),
> -                "::1000:0:0/84".parse::<Ipv6Cidr>().unwrap(),
> -                "::2000:0:0/83".parse::<Ipv6Cidr>().unwrap(),
> -                "::4000:0:0/82".parse::<Ipv6Cidr>().unwrap(),
> -                "::8000:0:0/81".parse::<Ipv6Cidr>().unwrap(),
> -                "::1:0:0:0/80".parse::<Ipv6Cidr>().unwrap(),
> -                "::2:0:0:0/79".parse::<Ipv6Cidr>().unwrap(),
> -                "::4:0:0:0/78".parse::<Ipv6Cidr>().unwrap(),
> -                "::8:0:0:0/77".parse::<Ipv6Cidr>().unwrap(),
> -                "::10:0:0:0/76".parse::<Ipv6Cidr>().unwrap(),
> -                "::20:0:0:0/75".parse::<Ipv6Cidr>().unwrap(),
> -                "::40:0:0:0/74".parse::<Ipv6Cidr>().unwrap(),
> -                "::80:0:0:0/73".parse::<Ipv6Cidr>().unwrap(),
> -                "::100:0:0:0/72".parse::<Ipv6Cidr>().unwrap(),
> -                "::200:0:0:0/71".parse::<Ipv6Cidr>().unwrap(),
> -                "::400:0:0:0/70".parse::<Ipv6Cidr>().unwrap(),
> -                "::800:0:0:0/69".parse::<Ipv6Cidr>().unwrap(),
> -                "::1000:0:0:0/68".parse::<Ipv6Cidr>().unwrap(),
> -                "::2000:0:0:0/67".parse::<Ipv6Cidr>().unwrap(),
> -                "::4000:0:0:0/66".parse::<Ipv6Cidr>().unwrap(),
> -                "::8000:0:0:0/65".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:1::/64".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:2::/63".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:4::/62".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:8::/61".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:10::/60".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:20::/59".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:40::/58".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:80::/57".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:100::/56".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:200::/55".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:400::/54".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:800::/53".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:1000::/52".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:2000::/51".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:4000::/50".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:0:8000::/49".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:1::/48".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:2::/47".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:4::/46".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:8::/45".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:10::/44".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:20::/43".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:40::/42".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:80::/41".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:100::/40".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:200::/39".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:400::/38".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:800::/37".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:1000::/36".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:2000::/35".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:4000::/34".parse::<Ipv6Cidr>().unwrap(),
> -                "0:0:8000::/33".parse::<Ipv6Cidr>().unwrap(),
> -                "0:1::/32".parse::<Ipv6Cidr>().unwrap(),
> -                "0:2::/31".parse::<Ipv6Cidr>().unwrap(),
> -                "0:4::/30".parse::<Ipv6Cidr>().unwrap(),
> -                "0:8::/29".parse::<Ipv6Cidr>().unwrap(),
> -                "0:10::/28".parse::<Ipv6Cidr>().unwrap(),
> -                "0:20::/27".parse::<Ipv6Cidr>().unwrap(),
> -                "0:40::/26".parse::<Ipv6Cidr>().unwrap(),
> -                "0:80::/25".parse::<Ipv6Cidr>().unwrap(),
> -                "0:100::/24".parse::<Ipv6Cidr>().unwrap(),
> -                "0:200::/23".parse::<Ipv6Cidr>().unwrap(),
> -                "0:400::/22".parse::<Ipv6Cidr>().unwrap(),
> -                "0:800::/21".parse::<Ipv6Cidr>().unwrap(),
> -                "0:1000::/20".parse::<Ipv6Cidr>().unwrap(),
> -                "0:2000::/19".parse::<Ipv6Cidr>().unwrap(),
> -                "0:4000::/18".parse::<Ipv6Cidr>().unwrap(),
> -                "0:8000::/17".parse::<Ipv6Cidr>().unwrap(),
> -                "1::/16".parse::<Ipv6Cidr>().unwrap(),
> -                "2::/15".parse::<Ipv6Cidr>().unwrap(),
> -                "4::/14".parse::<Ipv6Cidr>().unwrap(),
> -                "8::/13".parse::<Ipv6Cidr>().unwrap(),
> -                "10::/12".parse::<Ipv6Cidr>().unwrap(),
> -                "20::/11".parse::<Ipv6Cidr>().unwrap(),
> -                "40::/10".parse::<Ipv6Cidr>().unwrap(),
> -                "80::/9".parse::<Ipv6Cidr>().unwrap(),
> -                "100::/8".parse::<Ipv6Cidr>().unwrap(),
> -                "200::/7".parse::<Ipv6Cidr>().unwrap(),
> -                "400::/6".parse::<Ipv6Cidr>().unwrap(),
> -                "800::/5".parse::<Ipv6Cidr>().unwrap(),
> -                "1000::/4".parse::<Ipv6Cidr>().unwrap(),
> -                "2000::/3".parse::<Ipv6Cidr>().unwrap(),
> -                "4000::/2".parse::<Ipv6Cidr>().unwrap(),
> -                "8000::/1".parse::<Ipv6Cidr>().unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [0, 0, 0, 0, 0, 0, 0, 0],
> -            [
> -                0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFE,
> -            ],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [
> -                "::/1".parse::<Ipv6Cidr>().unwrap(),
> -                "8000::/2".parse::<Ipv6Cidr>().unwrap(),
> -                "c000::/3".parse::<Ipv6Cidr>().unwrap(),
> -                "e000::/4".parse::<Ipv6Cidr>().unwrap(),
> -                "f000::/5".parse::<Ipv6Cidr>().unwrap(),
> -                "f800::/6".parse::<Ipv6Cidr>().unwrap(),
> -                "fc00::/7".parse::<Ipv6Cidr>().unwrap(),
> -                "fe00::/8".parse::<Ipv6Cidr>().unwrap(),
> -                "ff00::/9".parse::<Ipv6Cidr>().unwrap(),
> -                "ff80::/10".parse::<Ipv6Cidr>().unwrap(),
> -                "ffc0::/11".parse::<Ipv6Cidr>().unwrap(),
> -                "ffe0::/12".parse::<Ipv6Cidr>().unwrap(),
> -                "fff0::/13".parse::<Ipv6Cidr>().unwrap(),
> -                "fff8::/14".parse::<Ipv6Cidr>().unwrap(),
> -                "fffc::/15".parse::<Ipv6Cidr>().unwrap(),
> -                "fffe::/16".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff::/17".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:8000::/18".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:c000::/19".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:e000::/20".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:f000::/21".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:f800::/22".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:fc00::/23".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:fe00::/24".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ff00::/25".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ff80::/26".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffc0::/27".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffe0::/28".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:fff0::/29".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:fff8::/30".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:fffc::/31".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:fffe::/32".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff::/33".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:8000::/34".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:c000::/35".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:e000::/36".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:f000::/37".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:f800::/38".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:fc00::/39".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:fe00::/40".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ff00::/41".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ff80::/42".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffc0::/43".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffe0::/44".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:fff0::/45".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:fff8::/46".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:fffc::/47".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:fffe::/48".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff::/49".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:8000::/50".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:c000::/51".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:e000::/52".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:f000::/53".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:f800::/54".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:fc00::/55".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:fe00::/56".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ff00::/57".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ff80::/58".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffc0::/59".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffe0::/60".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:fff0::/61".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:fff8::/62".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:fffc::/63".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:fffe::/64".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff::/65".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:8000::/66".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:c000::/67".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:e000::/68".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:f000::/69".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:f800::/70".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:fc00::/71".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:fe00::/72".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:ff00::/73".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:ff80::/74".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:ffc0::/75".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:ffe0::/76".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:fff0::/77".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:fff8::/78".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:fffc::/79".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:fffe::/80".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff::/81".parse::<Ipv6Cidr>().unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:8000::/82"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:c000::/83"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:e000::/84"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:f000::/85"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:f800::/86"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:fc00::/87"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:fe00::/88"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ff00::/89"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ff80::/90"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffc0::/91"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffe0::/92"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:fff0::/93"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:fff8::/94"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:fffc::/95"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:fffe::/96"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff::/97"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:8000:0/98"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:c000:0/99"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:e000:0/100"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:f000:0/101"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:f800:0/102"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:fc00:0/103"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:fe00:0/104"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ff00:0/105"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ff80:0/106"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffc0:0/107"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffe0:0/108"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:fff0:0/109"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:fff8:0/110"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:fffc:0/111"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:fffe:0/112"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:0/113"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:8000/114"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:c000/115"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:e000/116"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:f000/117"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:f800/118"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fc00/119"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fe00/120"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00/121"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80/122"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffc0/123"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffe0/124"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff0/125"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fff8/126"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffc/127"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -                "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe/128"
> -                    .parse::<Ipv6Cidr>()
> -                    .unwrap(),
> -            ],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range =
> -            AddressRange::new_v6([0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0]).unwrap();
> -
> -        assert_eq!(
> -            [Ipv6Cidr::new([0, 0, 0, 0, 0, 0, 0, 0], 128).unwrap(),],
> -            range.to_cidrs().as_slice()
> -        );
> -
> -        let range = AddressRange::new_v6(
> -            [
> -                0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
> -            ],
> -            [
> -                0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
> -            ],
> -        )
> -        .unwrap();
> -
> -        assert_eq!(
> -            [Ipv6Cidr::new(
> -                [0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF],
> -                128
> -            )
> -            .unwrap(),],
> -            range.to_cidrs().as_slice()
> -        );
> -    }
>  }
> +
> diff --git a/proxmox-ve-config/src/firewall/types/alias.rs b/proxmox-ve-config/src/firewall/types/alias.rs
> index 7bc2fb8..a463e52 100644
> --- a/proxmox-ve-config/src/firewall/types/alias.rs
> +++ b/proxmox-ve-config/src/firewall/types/alias.rs
> @@ -2,10 +2,10 @@ use std::fmt::Display;
>  use std::str::FromStr;
>
>  use anyhow::{bail, format_err, Error};
> +use proxmox_network_types::ip_address::Cidr;
>  use serde_with::{DeserializeFromStr, SerializeDisplay};
>
>  use crate::firewall::parse::{match_name, match_non_whitespace};
> -use crate::firewall::types::address::Cidr;
>
>  #[derive(Debug, Clone)]
>  #[cfg_attr(test, derive(Eq, PartialEq))]
> diff --git a/proxmox-ve-config/src/firewall/types/ipset.rs b/proxmox-ve-config/src/firewall/types/ipset.rs
> index fe5a930..2aaf261 100644
> --- a/proxmox-ve-config/src/firewall/types/ipset.rs
> +++ b/proxmox-ve-config/src/firewall/types/ipset.rs
> @@ -3,10 +3,10 @@ use std::ops::{Deref, DerefMut};
>  use std::str::FromStr;
>
>  use anyhow::{bail, format_err, Error};
> +use proxmox_network_types::ip_address::{Cidr, IpRange};
>  use serde_with::DeserializeFromStr;
>
>  use crate::firewall::parse::match_non_whitespace;
> -use crate::firewall::types::address::{Cidr, IpRange};
>  use crate::firewall::types::alias::AliasName;
>  use crate::guest::vm::NetworkConfig;
>
> @@ -112,9 +112,9 @@ impl FromStr for IpsetAddress {
>      }
>  }
>
> -impl<T: Into<Cidr>> From<T> for IpsetAddress {
> -    fn from(cidr: T) -> Self {
> -        IpsetAddress::Cidr(cidr.into())
> +impl From<Cidr> for IpsetAddress {
> +    fn from(cidr: Cidr) -> Self {
> +        IpsetAddress::Cidr(cidr)
>      }
>  }
>
> diff --git a/proxmox-ve-config/src/firewall/types/mod.rs b/proxmox-ve-config/src/firewall/types/mod.rs
> index 8fd551e..567b302 100644
> --- a/proxmox-ve-config/src/firewall/types/mod.rs
> +++ b/proxmox-ve-config/src/firewall/types/mod.rs
> @@ -7,7 +7,6 @@ pub mod port;
>  pub mod rule;
>  pub mod rule_match;
>
> -pub use address::Cidr;
>  pub use alias::Alias;
>  pub use group::Group;
>  pub use ipset::Ipset;
> diff --git a/proxmox-ve-config/src/firewall/types/rule.rs b/proxmox-ve-config/src/firewall/types/rule.rs
> index 2c8f49c..b6b83d2 100644
> --- a/proxmox-ve-config/src/firewall/types/rule.rs
> +++ b/proxmox-ve-config/src/firewall/types/rule.rs
> @@ -247,13 +247,14 @@ impl FromStr for RuleGroup {
>
>  #[cfg(test)]
>  mod tests {
> +    use proxmox_network_types::ip_address::{Cidr, IpRange};
> +
>      use crate::firewall::types::{
> -        address::{IpEntry, IpList, IpRange},
> +        address::{IpEntry, IpList},
>          alias::{AliasName, AliasScope},
>          ipset::{IpsetName, IpsetScope},
>          log::LogLevel,
>          rule_match::{Icmp, IcmpCode, IpAddrMatch, IpMatch, Ports, Protocol, Udp},
> -        Cidr,
>      };
>
>      use super::*;
> diff --git a/proxmox-ve-config/src/firewall/types/rule_match.rs b/proxmox-ve-config/src/firewall/types/rule_match.rs
> index 94d8624..3256497 100644
> --- a/proxmox-ve-config/src/firewall/types/rule_match.rs
> +++ b/proxmox-ve-config/src/firewall/types/rule_match.rs
> @@ -7,10 +7,11 @@ use serde::Deserialize;
>  use anyhow::{bail, format_err, Error};
>  use serde::de::IntoDeserializer;
>
> +use proxmox_network_types::ip_address::Family;
>  use proxmox_sortable_macro::sortable;
>
>  use crate::firewall::parse::{match_name, match_non_whitespace, SomeStr};
> -use crate::firewall::types::address::{Family, IpList};
> +use crate::firewall::types::address::IpList;
>  use crate::firewall::types::alias::AliasName;
>  use crate::firewall::types::ipset::IpsetName;
>  use crate::firewall::types::log::LogLevel;
> @@ -770,7 +771,8 @@ impl fmt::Display for Icmpv6Code {
>
>  #[cfg(test)]
>  mod tests {
> -    use crate::firewall::types::{alias::AliasScope::Guest, Cidr};
> +    use proxmox_network_types::ip_address::Cidr;
> +    use crate::firewall::types::alias::AliasScope::Guest;
>
>      use super::*;
>
> diff --git a/proxmox-ve-config/src/guest/vm.rs b/proxmox-ve-config/src/guest/vm.rs
> index 3476b93..aa47e26 100644
> --- a/proxmox-ve-config/src/guest/vm.rs
> +++ b/proxmox-ve-config/src/guest/vm.rs
> @@ -1,79 +1,14 @@
> -use core::fmt::Display;
>  use std::io;
>  use std::str::FromStr;
> -use std::{collections::HashMap, net::Ipv6Addr};
> +use std::collections::HashMap;
>
>  use proxmox_schema::property_string::PropertyIterator;
>
>  use anyhow::{bail, Error};
> -use serde_with::DeserializeFromStr;
> +use proxmox_network_types::ip_address::{Ipv4Cidr, Ipv6Cidr};
> +use proxmox_network_types::mac_address::MacAddress;
>
>  use crate::firewall::parse::{match_digits, parse_bool};
> -use crate::firewall::types::address::{Ipv4Cidr, Ipv6Cidr};
> -
> -#[derive(Clone, Debug, DeserializeFromStr, PartialEq, Eq, Hash, PartialOrd, Ord)]
> -pub struct MacAddress([u8; 6]);
> -
> -static LOCAL_PART: [u8; 8] = [0xFE, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
> -static EUI64_MIDDLE_PART: [u8; 2] = [0xFF, 0xFE];
> -
> -impl MacAddress {
> -    pub fn new(address: [u8; 6]) -> Self {
> -        Self(address)
> -    }
> -
> -    /// generates a link local IPv6-address according to RFC 4291 (Appendix A)
> -    pub fn eui64_link_local_address(&self) -> Ipv6Addr {
> -        let head = &self.0[..3];
> -        let tail = &self.0[3..];
> -
> -        let mut eui64_address: Vec<u8> = LOCAL_PART
> -            .iter()
> -            .chain(head.iter())
> -            .chain(EUI64_MIDDLE_PART.iter())
> -            .chain(tail.iter())
> -            .copied()
> -            .collect();
> -
> -        // we need to flip the 7th bit of the first eui64 byte
> -        eui64_address[8] ^= 0x02;
> -
> -        Ipv6Addr::from(
> -            TryInto::<[u8; 16]>::try_into(eui64_address).expect("is an u8 array with 16 entries"),
> -        )
> -    }
> -}
> -
> -impl FromStr for MacAddress {
> -    type Err = Error;
> -
> -    fn from_str(s: &str) -> Result<Self, Self::Err> {
> -        let split = s.split(':');
> -
> -        let parsed = split
> -            .into_iter()
> -            .map(|elem| u8::from_str_radix(elem, 16))
> -            .collect::<Result<Vec<u8>, _>>()
> -            .map_err(Error::msg)?;
> -
> -        if parsed.len() != 6 {
> -            bail!("Invalid amount of elements in MAC address!");
> -        }
> -
> -        let address = &parsed.as_slice()[0..6];
> -        Ok(Self(address.try_into().unwrap()))
> -    }
> -}
> -
> -impl Display for MacAddress {
> -    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
> -        write!(
> -            f,
> -            "{:<02X}:{:<02X}:{:<02X}:{:<02X}:{:<02X}:{:<02X}",
> -            self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
> -        )
> -    }
> -}
>
>  #[derive(Debug, Clone, Copy)]
>  #[cfg_attr(test, derive(Eq, PartialEq))]
> @@ -266,6 +201,8 @@ impl NetworkConfig {
>
>  #[cfg(test)]
>  mod tests {
> +    use std::net::Ipv6Addr;
> +
>      use super::*;
>
>      #[test]
> @@ -314,7 +251,7 @@ mod tests {
>              network_device,
>              NetworkDevice {
>                  model: NetworkDeviceModel::VirtIO,
> -                mac_address: MacAddress([0xAA, 0xAA, 0xAA, 0x17, 0x19, 0x81]),
> +                mac_address: MacAddress::new([0xAA, 0xAA, 0xAA, 0x17, 0x19, 0x81]),
>                  firewall: true,
>                  ip: None,
>                  ip6: None,
> @@ -329,7 +266,7 @@ mod tests {
>              network_device,
>              NetworkDevice {
>                  model: NetworkDeviceModel::VirtIO,
> -                mac_address: MacAddress([0xAA, 0xAA, 0xAA, 0x17, 0x19, 0x81]),
> +                mac_address: MacAddress::new([0xAA, 0xAA, 0xAA, 0x17, 0x19, 0x81]),
>                  firewall: true,
>                  ip: None,
>                  ip6: None,
> @@ -345,7 +282,7 @@ mod tests {
>              network_device,
>              NetworkDevice {
>                  model: NetworkDeviceModel::Veth,
> -                mac_address: MacAddress([0xAA, 0xAA, 0xAA, 0xE2, 0x3E, 0x24]),
> +                mac_address: MacAddress::new([0xAA, 0xAA, 0xAA, 0xE2, 0x3E, 0x24]),
>                  firewall: false,
>                  ip: None,
>                  ip6: None,
> @@ -435,7 +372,7 @@ vmgenid: 706fbe99-d28b-4047-a9cd-3677c859ca8a"
>              network_config.network_devices()[&0],
>              NetworkDevice {
>                  model: NetworkDeviceModel::VirtIO,
> -                mac_address: MacAddress([0xAA, 0xBB, 0xCC, 0xF2, 0xFE, 0x75]),
> +                mac_address: MacAddress::new([0xAA, 0xBB, 0xCC, 0xF2, 0xFE, 0x75]),
>                  firewall: true,
>                  ip: None,
>                  ip6: None,
> @@ -465,7 +402,7 @@ unprivileged: 1"
>              network_config.network_devices()[&0],
>              NetworkDevice {
>                  model: NetworkDeviceModel::Veth,
> -                mac_address: MacAddress([0xBC, 0x24, 0x11, 0x47, 0x83, 0x11]),
> +                mac_address: MacAddress::new([0xBC, 0x24, 0x11, 0x47, 0x83, 0x11]),
>                  firewall: true,
>                  ip: None,
>                  ip6: None,
> @@ -476,7 +413,7 @@ unprivileged: 1"
>              network_config.network_devices()[&2],
>              NetworkDevice {
>                  model: NetworkDeviceModel::Veth,
> -                mac_address: MacAddress([0xBC, 0x24, 0x11, 0x47, 0x83, 0x12]),
> +                mac_address: MacAddress::new([0xBC, 0x24, 0x11, 0x47, 0x83, 0x12]),
>                  firewall: false,
>                  ip: Some(Ipv4Cidr::from_str("123.123.123.123/24").expect("valid ipv4")),
>                  ip6: None,
> @@ -487,7 +424,7 @@ unprivileged: 1"
>              network_config.network_devices()[&5],
>              NetworkDevice {
>                  model: NetworkDeviceModel::Veth,
> -                mac_address: MacAddress([0xBC, 0x24, 0x11, 0x47, 0x83, 0x13]),
> +                mac_address: MacAddress::new([0xBC, 0x24, 0x11, 0x47, 0x83, 0x13]),
>                  firewall: true,
>                  ip: None,
>                  ip6: Some(Ipv6Cidr::from_str("fd80::1/64").expect("valid ipv6")),
> diff --git a/proxmox-ve-config/src/host/utils.rs b/proxmox-ve-config/src/host/utils.rs
> index b1dc8e9..3dee72b 100644
> --- a/proxmox-ve-config/src/host/utils.rs
> +++ b/proxmox-ve-config/src/host/utils.rs
> @@ -1,6 +1,6 @@
>  use std::net::{IpAddr, ToSocketAddrs};
>
> -use crate::firewall::types::Cidr;
> +use proxmox_network_types::ip_address::Cidr;
>
>  use nix::sys::socket::{AddressFamily, SockaddrLike};
>  use proxmox_sys::nodename;
> diff --git a/proxmox-ve-config/src/sdn/config.rs b/proxmox-ve-config/src/sdn/config.rs
> index 7ee1101..9949be0 100644
> --- a/proxmox-ve-config/src/sdn/config.rs
> +++ b/proxmox-ve-config/src/sdn/config.rs
> @@ -6,17 +6,16 @@ use std::{
>      str::FromStr,
>  };
>
> +use proxmox_network_types::ip_address::{Cidr, IpRange, IpRangeError};
>  use proxmox_schema::{property_string::PropertyString, ApiType, ObjectSchema, StringSchema};
> -
>  use serde::Deserialize;
>  use serde_with::{DeserializeFromStr, SerializeDisplay};
>
>  use crate::{
>      common::Allowlist,
>      firewall::types::{
> -        address::{IpRange, IpRangeError},
>          ipset::{IpsetEntry, IpsetName, IpsetScope},
> -        Cidr, Ipset,
> +        Ipset,
>      },
>      sdn::{SdnNameError, SubnetName, VnetName, ZoneName},
>  };
> @@ -587,10 +586,10 @@ impl SdnConfig {
>                      ipset_all_wo_gateway.push((*subnet.cidr()).into());
>
>                      if let Some(gateway) = subnet.gateway {
> -                        let gateway_nomatch = IpsetEntry::new(gateway, true, None);
> +                        let gateway_nomatch = IpsetEntry::new(Cidr::from(gateway), true, None);
>                          ipset_all_wo_gateway.push(gateway_nomatch);
>
> -                        ipset_gateway.push(gateway.into());
> +                        ipset_gateway.push(Cidr::from(gateway).into());
>                      }
>
>                      ipset_dhcp.extend(subnet.dhcp_range.iter().cloned().map(IpsetEntry::from));
> diff --git a/proxmox-ve-config/src/sdn/ipam.rs b/proxmox-ve-config/src/sdn/ipam.rs
> index 598b835..9c6985b 100644
> --- a/proxmox-ve-config/src/sdn/ipam.rs
> +++ b/proxmox-ve-config/src/sdn/ipam.rs
> @@ -7,13 +7,16 @@ use std::{
>
>  use serde::Deserialize;
>
> +use proxmox_network_types::ip_address::Cidr;
> +use proxmox_network_types::mac_address::MacAddress;
> +
>  use crate::{
>      common::Allowlist,
>      firewall::types::{
> -        ipset::{IpsetEntry, IpsetScope},
> -        Cidr, Ipset,
> +        ipset::IpsetScope,
> +        Ipset,
>      },
> -    guest::{types::Vmid, vm::MacAddress},
> +    guest::types::Vmid,
>      sdn::{SdnNameError, SubnetName, ZoneName},
>  };
>
> @@ -339,7 +342,7 @@ impl Ipam {
>                      .or_insert_with(|| {
>                          Ipset::from_parts(IpsetScope::Sdn, format!("guest-ipam-{}", entry.vmid))
>                      })
> -                    .push(IpsetEntry::from(entry.ip));
> +                    .push(Cidr::from(entry.ip).into());
>
>                  acc
>              })
> diff --git a/proxmox-ve-config/src/sdn/mod.rs b/proxmox-ve-config/src/sdn/mod.rs
> index c8dc724..cde6fed 100644
> --- a/proxmox-ve-config/src/sdn/mod.rs
> +++ b/proxmox-ve-config/src/sdn/mod.rs
> @@ -3,10 +3,9 @@ pub mod ipam;
>
>  use std::{error::Error, fmt::Display, str::FromStr};
>
> +use proxmox_network_types::ip_address::Cidr;
>  use serde_with::DeserializeFromStr;
>
> -use crate::firewall::types::Cidr;
> -
>  #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
>  pub enum SdnNameError {
>      Empty,
> diff --git a/proxmox-ve-config/tests/sdn/main.rs b/proxmox-ve-config/tests/sdn/main.rs
> index 1815bec..2ab0e5c 100644
> --- a/proxmox-ve-config/tests/sdn/main.rs
> +++ b/proxmox-ve-config/tests/sdn/main.rs
> @@ -3,18 +3,17 @@ use std::{
>      str::FromStr,
>  };
>
> -use proxmox_ve_config::{
> -    firewall::types::{address::IpRange, Cidr},
> -    guest::vm::MacAddress,
> -    sdn::{
> +use proxmox_network_types::ip_address::{Cidr, IpRange};
> +use proxmox_network_types::mac_address::MacAddress;
> +
> +use proxmox_ve_config::sdn::{
>          config::{
>              RunningConfig, SdnConfig, SdnConfigError, SubnetConfig, VnetConfig, ZoneConfig,
>              ZoneType,
>          },
>          ipam::{Ipam, IpamDataVm, IpamEntry, IpamJson},
>          SubnetName, VnetName, ZoneName,
> -    },
> -};
> +    };
>
>  #[test]
>  fn parse_running_config() {





More information about the pve-devel mailing list