all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Christoph Heiss <c.heiss@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [PATCH proxmox-backup 3/3] api: network: reuse interface create/update methods from network-api
Date: Fri, 25 Sep 2026 14:34:32 +0200	[thread overview]
Message-ID: <20260925123459.424903-4-c.heiss@proxmox.com> (raw)
In-Reply-To: <20260925123459.424903-1-c.heiss@proxmox.com>

They are nearly identical in parameters and implementation, only that the
network-api crate uses a struct instead of a long list of single
parameters.

The only real difference are bit more strict checks, namely:
- the 'auto' method is now rejected for IPv4, which is IPv6 only
- enforces that the method is 'static' when explicitly setting CIDR/GW

Signed-off-by: Christoph Heiss <c.heiss@proxmox.com>
---
In combination w/ the earlier patches in the series; also fixes #6121
[0].

[0] https://bugzilla.proxmox.com/show_bug.cgi?id=6121

 src/api2/node/network.rs | 674 ++-------------------------------------
 1 file changed, 18 insertions(+), 656 deletions(-)

diff --git a/src/api2/node/network.rs b/src/api2/node/network.rs
index 07ef4bb64..591b4b6e8 100644
--- a/src/api2/node/network.rs
+++ b/src/api2/node/network.rs
@@ -1,5 +1,4 @@
-use anyhow::{Error, bail};
-use serde::{Deserialize, Serialize};
+use anyhow::Error;
 use serde_json::{Value, to_value};
 
 use proxmox_router::{ApiMethod, Permission, Router, RpcEnvironment};
@@ -9,86 +8,14 @@ use pbs_api_types::{
     Authid, NODE_SCHEMA, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY, PROXMOX_CONFIG_DIGEST_SCHEMA,
 };
 
+use proxmox_config_digest::ConfigDigest;
 use proxmox_network_api::{
-    self as network, BondXmitHashPolicy, CIDR_V4_SCHEMA, CIDR_V6_SCHEMA, IP_V4_SCHEMA,
-    IP_V6_SCHEMA, Interface, LinuxBondMode, NETWORK_INTERFACE_ARRAY_SCHEMA,
-    NETWORK_INTERFACE_LIST_SCHEMA, NETWORK_INTERFACE_NAME_SCHEMA, NetworkConfig,
-    NetworkConfigMethod, NetworkInterfaceType, parse_vlan_id_from_name,
-    parse_vlan_raw_device_from_name,
+    self as network, DeletableInterfaceProperty, Interface, InterfaceUpdater,
+    NETWORK_INTERFACE_NAME_SCHEMA,
 };
 
 use proxmox_rest_server::WorkerTask;
 
-fn split_interface_list(list: &str) -> Result<Vec<String>, Error> {
-    let value = NETWORK_INTERFACE_ARRAY_SCHEMA.parse_property_string(list)?;
-    Ok(value
-        .as_array()
-        .unwrap()
-        .iter()
-        .map(|v| v.as_str().unwrap().to_string())
-        .collect())
-}
-
-fn check_duplicate_gateway_v4(config: &NetworkConfig, iface: &str) -> Result<(), Error> {
-    let current_gateway_v4 = config
-        .interfaces
-        .iter()
-        .find(|(_, interface)| interface.gateway.is_some())
-        .map(|(name, _)| name.to_string());
-
-    if let Some(current_gateway_v4) = current_gateway_v4 {
-        if current_gateway_v4 != iface {
-            bail!(
-                "Default IPv4 gateway already exists on interface '{}'",
-                current_gateway_v4
-            );
-        }
-    }
-    Ok(())
-}
-
-fn check_duplicate_gateway_v6(config: &NetworkConfig, iface: &str) -> Result<(), Error> {
-    let current_gateway_v6 = config
-        .interfaces
-        .iter()
-        .find(|(_, interface)| interface.gateway6.is_some())
-        .map(|(name, _)| name.to_string());
-
-    if let Some(current_gateway_v6) = current_gateway_v6 {
-        if current_gateway_v6 != iface {
-            bail!(
-                "Default IPv6 gateway already exists on interface '{}'",
-                current_gateway_v6
-            );
-        }
-    }
-    Ok(())
-}
-
-fn set_bridge_ports(iface: &mut Interface, ports: Vec<String>) -> Result<(), Error> {
-    if iface.interface_type != NetworkInterfaceType::Bridge {
-        bail!(
-            "interface '{}' is no bridge (type is {:?})",
-            iface.name,
-            iface.interface_type
-        );
-    }
-    iface.bridge_ports = Some(ports);
-    Ok(())
-}
-
-fn set_bond_slaves(iface: &mut Interface, slaves: Vec<String>) -> Result<(), Error> {
-    if iface.interface_type != NetworkInterfaceType::Bond {
-        bail!(
-            "interface '{}' is no bond (type is {:?})",
-            iface.name,
-            iface.interface_type
-        );
-    }
-    iface.slaves = Some(slaves);
-    Ok(())
-}
-
 #[api(
     input: {
         properties: {
@@ -175,89 +102,9 @@ pub fn read_interface(iface: String) -> Result<Value, Error> {
             iface: {
                 schema: NETWORK_INTERFACE_NAME_SCHEMA,
             },
-            "type": {
-                type: NetworkInterfaceType,
-                optional: true,
-            },
-            autostart: {
-                description: "Autostart interface.",
-                type: bool,
-                optional: true,
-            },
-            method: {
-                type: NetworkConfigMethod,
-                optional: true,
-            },
-            method6: {
-                type: NetworkConfigMethod,
-                optional: true,
-            },
-            comments: {
-                description: "Comments (inet, may span multiple lines)",
-                type: String,
-                optional: true,
-            },
-            comments6: {
-                description: "Comments (inet5, may span multiple lines)",
-                type: String,
-                optional: true,
-            },
-            cidr: {
-                schema: CIDR_V4_SCHEMA,
-                optional: true,
-            },
-            cidr6: {
-                schema: CIDR_V6_SCHEMA,
-                optional: true,
-            },
-            gateway: {
-                schema: IP_V4_SCHEMA,
-                optional: true,
-            },
-            gateway6: {
-                schema: IP_V6_SCHEMA,
-                optional: true,
-            },
-            mtu: {
-                description: "Maximum Transmission Unit.",
-                optional: true,
-                minimum: 46,
-                maximum: 65535,
-                default: 1500,
-            },
-            bridge_ports: {
-                schema: NETWORK_INTERFACE_LIST_SCHEMA,
-                optional: true,
-            },
-            bridge_vlan_aware: {
-                description: "Enable bridge vlan support.",
-                type: bool,
-                optional: true,
-            },
-            "vlan-id": {
-                description: "VLAN ID.",
-                type: u16,
-                optional: true,
-            },
-            "vlan-raw-device": {
-                schema: NETWORK_INTERFACE_NAME_SCHEMA,
-                optional: true,
-            },
-            bond_mode: {
-                type: LinuxBondMode,
-                optional: true,
-            },
-            "bond-primary": {
-                schema: NETWORK_INTERFACE_NAME_SCHEMA,
-                optional: true,
-            },
-            bond_xmit_hash_policy: {
-                type: BondXmitHashPolicy,
-                optional: true,
-            },
-            slaves: {
-                schema: NETWORK_INTERFACE_LIST_SCHEMA,
-                optional: true,
+            config: {
+                type: InterfaceUpdater,
+                flatten: true,
             },
         },
     },
@@ -266,210 +113,8 @@ pub fn read_interface(iface: String) -> Result<Value, Error> {
     },
 )]
 /// Create network interface configuration.
-#[allow(clippy::too_many_arguments)]
-pub fn create_interface(
-    iface: String,
-    autostart: Option<bool>,
-    method: Option<NetworkConfigMethod>,
-    method6: Option<NetworkConfigMethod>,
-    comments: Option<String>,
-    comments6: Option<String>,
-    cidr: Option<String>,
-    gateway: Option<String>,
-    cidr6: Option<String>,
-    gateway6: Option<String>,
-    mtu: Option<u64>,
-    bridge_ports: Option<String>,
-    bridge_vlan_aware: Option<bool>,
-    vlan_id: Option<u16>,
-    vlan_raw_device: Option<String>,
-    bond_mode: Option<LinuxBondMode>,
-    bond_primary: Option<String>,
-    bond_xmit_hash_policy: Option<BondXmitHashPolicy>,
-    slaves: Option<String>,
-    param: Value,
-) -> Result<(), Error> {
-    let interface_type = pbs_tools::json::required_string_param(&param, "type")?;
-    let interface_type: NetworkInterfaceType = serde_json::from_value(interface_type.into())?;
-
-    let _lock = network::lock_config()?;
-
-    let (mut config, _digest) = network::config()?;
-
-    if config.interfaces.contains_key(&iface) {
-        bail!("interface '{}' already exists", iface);
-    }
-
-    let mut interface = Interface::new(iface.clone());
-    interface.interface_type = interface_type;
-
-    if let Some(autostart) = autostart {
-        interface.autostart = autostart;
-    }
-    if method.is_some() {
-        interface.method = method;
-    }
-    if method6.is_some() {
-        interface.method6 = method6;
-    }
-    if mtu.is_some() {
-        interface.mtu = mtu;
-    }
-    if comments.is_some() {
-        interface.comments = comments;
-    }
-    if comments6.is_some() {
-        interface.comments6 = comments6;
-    }
-
-    if let Some(cidr) = cidr {
-        let (_, _, is_v6) = network::parse_cidr(&cidr)?;
-        if is_v6 {
-            bail!("invalid address type (expected IPv4, got IPv6)");
-        }
-        interface.cidr = Some(cidr);
-    }
-
-    if let Some(cidr6) = cidr6 {
-        let (_, _, is_v6) = network::parse_cidr(&cidr6)?;
-        if !is_v6 {
-            bail!("invalid address type (expected IPv6, got IPv4)");
-        }
-        interface.cidr6 = Some(cidr6);
-    }
-
-    if let Some(gateway) = gateway {
-        let is_v6 = gateway.contains(':');
-        if is_v6 {
-            bail!("invalid address type (expected IPv4, got IPv6)");
-        }
-        check_duplicate_gateway_v4(&config, &iface)?;
-        interface.gateway = Some(gateway);
-    }
-
-    if let Some(gateway6) = gateway6 {
-        let is_v6 = gateway6.contains(':');
-        if !is_v6 {
-            bail!("invalid address type (expected IPv6, got IPv4)");
-        }
-        check_duplicate_gateway_v6(&config, &iface)?;
-        interface.gateway6 = Some(gateway6);
-    }
-
-    match interface_type {
-        NetworkInterfaceType::Bridge => {
-            if let Some(ports) = bridge_ports {
-                let ports = split_interface_list(&ports)?;
-                set_bridge_ports(&mut interface, ports)?;
-            }
-            if bridge_vlan_aware.is_some() {
-                interface.bridge_vlan_aware = bridge_vlan_aware;
-            }
-        }
-        NetworkInterfaceType::Bond => {
-            if let Some(mode) = bond_mode {
-                interface.bond_mode = bond_mode;
-                if bond_primary.is_some() {
-                    if mode != LinuxBondMode::ActiveBackup {
-                        bail!("bond-primary is only valid with Active/Backup mode");
-                    }
-                    interface.bond_primary = bond_primary;
-                }
-                if bond_xmit_hash_policy.is_some() {
-                    if mode != LinuxBondMode::Ieee802_3ad && mode != LinuxBondMode::BalanceXor {
-                        bail!(
-                            "bond_xmit_hash_policy is only valid with LACP(802.3ad) or balance-xor mode"
-                        );
-                    }
-                    interface.bond_xmit_hash_policy = bond_xmit_hash_policy;
-                }
-            }
-            if let Some(slaves) = slaves {
-                let slaves = split_interface_list(&slaves)?;
-                set_bond_slaves(&mut interface, slaves)?;
-            }
-        }
-        NetworkInterfaceType::Vlan => {
-            if vlan_id.is_none() && parse_vlan_id_from_name(&iface).is_none() {
-                bail!("vlan-id must be set");
-            }
-            interface.vlan_id = vlan_id;
-
-            if let Some(dev) = vlan_raw_device
-                .as_deref()
-                .or_else(|| parse_vlan_raw_device_from_name(&iface))
-            {
-                if !config.interfaces.contains_key(dev) {
-                    bail!("vlan-raw-device {dev} does not exist");
-                }
-            } else {
-                bail!("vlan-raw-device must be set");
-            }
-            interface.vlan_raw_device = vlan_raw_device;
-        }
-        _ => bail!(
-            "creating network interface type '{:?}' is not supported",
-            interface_type
-        ),
-    }
-
-    if interface.cidr.is_some() || interface.gateway.is_some() {
-        interface.method = Some(NetworkConfigMethod::Static);
-    } else if interface.method.is_none() {
-        interface.method = Some(NetworkConfigMethod::Manual);
-    }
-
-    if interface.cidr6.is_some() || interface.gateway6.is_some() {
-        interface.method6 = Some(NetworkConfigMethod::Static);
-    } else if interface.method6.is_none() {
-        interface.method6 = Some(NetworkConfigMethod::Manual);
-    }
-
-    config.interfaces.insert(iface, interface);
-
-    network::save_config(&config)?;
-
-    Ok(())
-}
-
-#[api()]
-#[derive(Serialize, Deserialize)]
-#[serde(rename_all = "kebab-case")]
-/// Deletable property name
-pub enum DeletableProperty {
-    /// Delete the IPv4 address property.
-    Cidr,
-    /// Delete the IPv6 address property.
-    Cidr6,
-    /// Delete the IPv4 gateway property.
-    Gateway,
-    /// Delete the IPv6 gateway property.
-    Gateway6,
-    /// Delete the whole IPv4 configuration entry.
-    Method,
-    /// Delete the whole IPv6 configuration entry.
-    Method6,
-    /// Delete IPv4 comments
-    Comments,
-    /// Delete IPv6 comments
-    Comments6,
-    /// Delete mtu.
-    Mtu,
-    /// Delete autostart flag
-    Autostart,
-    /// Delete bridge ports (set to 'none')
-    #[serde(rename = "bridge_ports")]
-    BridgePorts,
-    /// Delete bridge-vlan-aware flag
-    #[serde(rename = "bridge_vlan_aware")]
-    BridgeVlanAware,
-    /// Delete bond-slaves (set to 'none')
-    Slaves,
-    /// Delete bond-primary
-    BondPrimary,
-    /// Delete bond transmit hash policy
-    #[serde(rename = "bond_xmit_hash_policy")]
-    BondXmitHashPolicy,
+pub fn create_interface(iface: String, config: InterfaceUpdater) -> Result<(), Error> {
+    proxmox_network_api::create_interface(iface, config)
 }
 
 #[api(
@@ -482,101 +127,21 @@ pub enum DeletableProperty {
             iface: {
                 schema: NETWORK_INTERFACE_NAME_SCHEMA,
             },
-            "type": {
-                type: NetworkInterfaceType,
-                optional: true,
-            },
-            autostart: {
-                description: "Autostart interface.",
-                type: bool,
-                optional: true,
-            },
-            method: {
-                type: NetworkConfigMethod,
-                optional: true,
-            },
-            method6: {
-                type: NetworkConfigMethod,
-                optional: true,
-            },
-            comments: {
-                description: "Comments (inet, may span multiple lines)",
-                type: String,
-                optional: true,
-            },
-            comments6: {
-                description: "Comments (inet5, may span multiple lines)",
-                type: String,
-                optional: true,
-            },
-            cidr: {
-                schema: CIDR_V4_SCHEMA,
-                optional: true,
-            },
-            cidr6: {
-                schema: CIDR_V6_SCHEMA,
-                optional: true,
-            },
-            gateway: {
-                schema: IP_V4_SCHEMA,
-                optional: true,
-            },
-            gateway6: {
-                schema: IP_V6_SCHEMA,
-                optional: true,
-            },
-            mtu: {
-                description: "Maximum Transmission Unit.",
-                optional: true,
-                minimum: 46,
-                maximum: 65535,
-                default: 1500,
-            },
-            bridge_ports: {
-                schema: NETWORK_INTERFACE_LIST_SCHEMA,
-                optional: true,
-            },
-            bridge_vlan_aware: {
-                description: "Enable bridge vlan support.",
-                type: bool,
-                optional: true,
-            },
-            "vlan-id": {
-                description: "VLAN ID.",
-                type: u16,
-                optional: true,
-            },
-            "vlan-raw-device": {
-                schema: NETWORK_INTERFACE_NAME_SCHEMA,
-                optional: true,
-            },
-            bond_mode: {
-                type: LinuxBondMode,
-                optional: true,
-            },
-            "bond-primary": {
-                schema: NETWORK_INTERFACE_NAME_SCHEMA,
-                optional: true,
-            },
-            bond_xmit_hash_policy: {
-                type: BondXmitHashPolicy,
-                optional: true,
-            },
-            slaves: {
-                schema: NETWORK_INTERFACE_LIST_SCHEMA,
-                optional: true,
+            update: {
+                type: InterfaceUpdater,
+                flatten: true,
             },
             delete: {
                 description: "List of properties to delete.",
                 type: Array,
                 optional: true,
                 items: {
-                    type: DeletableProperty,
+                    type: DeletableInterfaceProperty,
                 }
             },
             digest: {
+                type: ConfigDigest,
                 optional: true,
-                schema: PROXMOX_CONFIG_DIGEST_SCHEMA,
             },
         },
     },
@@ -585,216 +150,13 @@ pub enum DeletableProperty {
     },
 )]
 /// Update network interface config.
-#[allow(clippy::too_many_arguments)]
 pub fn update_interface(
     iface: String,
-    autostart: Option<bool>,
-    method: Option<NetworkConfigMethod>,
-    method6: Option<NetworkConfigMethod>,
-    comments: Option<String>,
-    comments6: Option<String>,
-    cidr: Option<String>,
-    gateway: Option<String>,
-    cidr6: Option<String>,
-    gateway6: Option<String>,
-    mtu: Option<u64>,
-    bridge_ports: Option<String>,
-    bridge_vlan_aware: Option<bool>,
-    vlan_id: Option<u16>,
-    vlan_raw_device: Option<String>,
-    bond_mode: Option<LinuxBondMode>,
-    bond_primary: Option<String>,
-    bond_xmit_hash_policy: Option<BondXmitHashPolicy>,
-    slaves: Option<String>,
-    delete: Option<Vec<DeletableProperty>>,
-    digest: Option<String>,
-    param: Value,
+    update: InterfaceUpdater,
+    delete: Option<Vec<DeletableInterfaceProperty>>,
+    digest: Option<ConfigDigest>,
 ) -> Result<(), Error> {
-    let _lock = network::lock_config()?;
-
-    let (mut config, expected_digest) = network::config()?;
-
-    pbs_config::detect_modified_configuration_file(digest, &expected_digest)?;
-
-    if gateway.is_some() {
-        check_duplicate_gateway_v4(&config, &iface)?;
-    }
-    if gateway6.is_some() {
-        check_duplicate_gateway_v6(&config, &iface)?;
-    }
-
-    if let Some(dev) = vlan_raw_device
-        .as_deref()
-        .or_else(|| parse_vlan_raw_device_from_name(&iface))
-    {
-        if !config.interfaces.contains_key(dev) {
-            bail!("vlan-raw-device {dev} does not exist");
-        }
-    }
-
-    let interface = config.lookup_mut(&iface)?;
-
-    if let Some(interface_type) = param.get("type") {
-        let interface_type = NetworkInterfaceType::deserialize(interface_type)?;
-        if interface_type != interface.interface_type {
-            bail!(
-                "got unexpected interface type ({:?} != {:?})",
-                interface_type,
-                interface.interface_type
-            );
-        }
-    }
-
-    if let Some(delete) = delete {
-        for delete_prop in delete {
-            match delete_prop {
-                DeletableProperty::Cidr => {
-                    interface.cidr = None;
-                }
-                DeletableProperty::Cidr6 => {
-                    interface.cidr6 = None;
-                }
-                DeletableProperty::Gateway => {
-                    interface.gateway = None;
-                }
-                DeletableProperty::Gateway6 => {
-                    interface.gateway6 = None;
-                }
-                DeletableProperty::Method => {
-                    interface.method = None;
-                }
-                DeletableProperty::Method6 => {
-                    interface.method6 = None;
-                }
-                DeletableProperty::Comments => {
-                    interface.comments = None;
-                }
-                DeletableProperty::Comments6 => {
-                    interface.comments6 = None;
-                }
-                DeletableProperty::Mtu => {
-                    interface.mtu = None;
-                }
-                DeletableProperty::Autostart => {
-                    interface.autostart = false;
-                }
-                DeletableProperty::BridgePorts => {
-                    set_bridge_ports(interface, Vec::new())?;
-                }
-                DeletableProperty::BridgeVlanAware => {
-                    interface.bridge_vlan_aware = None;
-                }
-                DeletableProperty::Slaves => {
-                    set_bond_slaves(interface, Vec::new())?;
-                }
-                DeletableProperty::BondPrimary => {
-                    interface.bond_primary = None;
-                }
-                DeletableProperty::BondXmitHashPolicy => interface.bond_xmit_hash_policy = None,
-            }
-        }
-    }
-
-    if let Some(autostart) = autostart {
-        interface.autostart = autostart;
-    }
-    if method.is_some() {
-        interface.method = method;
-    }
-    if method6.is_some() {
-        interface.method6 = method6;
-    }
-    if mtu.is_some() {
-        interface.mtu = mtu;
-    }
-    if let Some(ports) = bridge_ports {
-        let ports = split_interface_list(&ports)?;
-        set_bridge_ports(interface, ports)?;
-    }
-    if bridge_vlan_aware.is_some() {
-        interface.bridge_vlan_aware = bridge_vlan_aware;
-    }
-    if let Some(slaves) = slaves {
-        let slaves = split_interface_list(&slaves)?;
-        set_bond_slaves(interface, slaves)?;
-    }
-    if let Some(mode) = bond_mode {
-        interface.bond_mode = bond_mode;
-        if bond_primary.is_some() {
-            if mode != LinuxBondMode::ActiveBackup {
-                bail!("bond-primary is only valid with Active/Backup mode");
-            }
-            interface.bond_primary = bond_primary;
-        }
-        if bond_xmit_hash_policy.is_some() {
-            if mode != LinuxBondMode::Ieee802_3ad && mode != LinuxBondMode::BalanceXor {
-                bail!("bond_xmit_hash_policy is only valid with LACP(802.3ad) or balance-xor mode");
-            }
-            interface.bond_xmit_hash_policy = bond_xmit_hash_policy;
-        }
-    }
-
-    if let Some(cidr) = cidr {
-        let (_, _, is_v6) = network::parse_cidr(&cidr)?;
-        if is_v6 {
-            bail!("invalid address type (expected IPv4, got IPv6)");
-        }
-        interface.cidr = Some(cidr);
-    }
-
-    if let Some(cidr6) = cidr6 {
-        let (_, _, is_v6) = network::parse_cidr(&cidr6)?;
-        if !is_v6 {
-            bail!("invalid address type (expected IPv6, got IPv4)");
-        }
-        interface.cidr6 = Some(cidr6);
-    }
-
-    if let Some(gateway) = gateway {
-        let is_v6 = gateway.contains(':');
-        if is_v6 {
-            bail!("invalid address type (expected IPv4, got IPv6)");
-        }
-        interface.gateway = Some(gateway);
-    }
-
-    if let Some(gateway6) = gateway6 {
-        let is_v6 = gateway6.contains(':');
-        if !is_v6 {
-            bail!("invalid address type (expected IPv6, got IPv4)");
-        }
-        interface.gateway6 = Some(gateway6);
-    }
-
-    if comments.is_some() {
-        interface.comments = comments;
-    }
-    if comments6.is_some() {
-        interface.comments6 = comments6;
-    }
-
-    if interface.cidr.is_some() || interface.gateway.is_some() {
-        interface.method = Some(NetworkConfigMethod::Static);
-    } else {
-        interface.method = Some(NetworkConfigMethod::Manual);
-    }
-
-    if interface.cidr6.is_some() || interface.gateway6.is_some() {
-        interface.method6 = Some(NetworkConfigMethod::Static);
-    } else if interface.method6.is_none() {
-        interface.method6 = Some(NetworkConfigMethod::Manual);
-    }
-
-    if vlan_id.is_some() {
-        interface.vlan_id = vlan_id;
-    }
-    if vlan_raw_device.is_some() {
-        interface.vlan_raw_device = vlan_raw_device;
-    }
-
-    network::save_config(&config)?;
-
-    Ok(())
+    proxmox_network_api::update_interface(iface, update, delete, digest)
 }
 
 #[api(
-- 
2.55.0





      parent reply	other threads:[~2026-09-25 12:35 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-25 12:34 [PATCH proxmox{,-backup} 0/3] fix #6121: add 'bond-miimon' option for network interfaces Christoph Heiss
2026-09-25 12:34 ` [PATCH proxmox 1/3] fix #6121: network-api: api: add `bond-miimon` option for interfaces Christoph Heiss
2026-09-25 12:34 ` [PATCH proxmox 2/3] fix #6121: network-api: config: add support for `bond-miimon` option Christoph Heiss
2026-09-25 12:34 ` Christoph Heiss [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260925123459.424903-4-c.heiss@proxmox.com \
    --to=c.heiss@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal