[pve-devel] [PATCH proxmox-ve-rs v2 14/25] sdn: ipam: add method for generating ipsets
Wolfgang Bumiller
w.bumiller at proxmox.com
Wed Nov 6 16:12:44 CET 2024
On Thu, Oct 10, 2024 at 05:56:26PM GMT, Stefan Hanreich wrote:
> For every guest that has at least one entry in the IPAM we generate an
> ipset with the name `+sdn/guest-ipam-{vmid}`. The ipset contains all
> IPs from all zones for a guest with {vmid}.
>
> Signed-off-by: Stefan Hanreich <s.hanreich at proxmox.com>
> ---
> .../src/firewall/types/address.rs | 9 ++++
> proxmox-ve-config/src/sdn/ipam.rs | 54 ++++++++++++++++++-
> 2 files changed, 62 insertions(+), 1 deletion(-)
>
> diff --git a/proxmox-ve-config/src/firewall/types/address.rs b/proxmox-ve-config/src/firewall/types/address.rs
> index a7bb6ad..e5a3709 100644
> --- a/proxmox-ve-config/src/firewall/types/address.rs
> +++ b/proxmox-ve-config/src/firewall/types/address.rs
> @@ -108,6 +108,15 @@ impl From<Ipv6Cidr> for 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)]
> diff --git a/proxmox-ve-config/src/sdn/ipam.rs b/proxmox-ve-config/src/sdn/ipam.rs
> index 682bbe7..075c0f3 100644
> --- a/proxmox-ve-config/src/sdn/ipam.rs
> +++ b/proxmox-ve-config/src/sdn/ipam.rs
> @@ -8,7 +8,11 @@ use std::{
> use serde::Deserialize;
>
> use crate::{
> - firewall::types::Cidr,
> + common::Allowlist,
> + firewall::types::{
> + ipset::{IpsetEntry, IpsetScope},
> + Cidr, Ipset,
> + },
> guest::{types::Vmid, vm::MacAddress},
> sdn::{SdnNameError, SubnetName, ZoneName},
> };
> @@ -309,6 +313,54 @@ impl Ipam {
> }
> }
>
> +impl Ipam {
> + /// generates an [`Ipset`] for all guests with at least one entry in the IPAM
> + ///
> + /// # Arguments
> + /// * `filter` - A [`Allowlist<Vmid>`] for which IPsets should get returned
> + ///
> + /// It contains all IPs in all VNets, that a guest has stored in IPAM.
> + /// Ipset name is of the form `guest-ipam-<vmid>`
> + pub fn ipsets<'a>(
> + &self,
> + filter: impl Into<Option<&'a Allowlist<Vmid>>>,
^ Why the `impl Into`? All our current uses should work for just the
Option directly (and then we can also drop the named lifetime).
> + ) -> impl Iterator<Item = Ipset> + '_ {
> + let filter = filter.into();
> +
> + self.entries
> + .iter()
> + .flat_map(|(_, entries)| entries.iter())
> + .filter_map(|entry| {
> + if let IpamData::Vm(data) = &entry.data() {
> + if filter
> + .map(|list| list.is_allowed(&data.vmid))
> + .unwrap_or(true)
Let's bump MSRV to 1.82 and use
if filter.is_none_or(|list| list.is_allowed(&data.vmid)) {
? :)
> + {
> + return Some(data);
> + }
> + }
> +
> + None
> + })
> + .fold(HashMap::<Vmid, Ipset>::new(), |mut acc, entry| {
> + match acc.get_mut(&entry.vmid) {
> + Some(ipset) => {
> + ipset.push(IpsetEntry::from(entry.ip));
> + }
> + None => {
> + let ipset_name = format!("guest-ipam-{}", entry.vmid);
> + let mut ipset = Ipset::from_parts(IpsetScope::Sdn, ipset_name);
> + ipset.push(IpsetEntry::from(entry.ip));
> + acc.insert(entry.vmid, ipset);
> + }
> + };
Mhhhh. The `ipset.upsh()` is identical in both cases, and vmid is a
simple Copy type, so we could use the entry api for this:
acc.entry(entry.vmid)
.or_insert_with(|| {
Ipset::from_parts(IpsetScope::Sdn, format!("guest-ipam-{}", entry.vmid))
})
.push(IpsetEntry::from(entry.ip));
> +
> + acc
> + })
> + .into_values()
> + }
> +}
> +
> impl TryFrom<IpamJson> for Ipam {
> type Error = IpamError;
>
> --
> 2.39.5
More information about the pve-devel
mailing list