mirror of
https://git.proxmox.com/git/proxmox-backup
synced 2025-04-28 12:50:53 +00:00
api: create and update vlan interfaces
* Implement setting vlan-id and vlan-raw-device in the create and update api. * Checking if the provided vlan-raw-device exists * Moved VLAN_INTERFACE_REGEX to top level network module to use it in the checking functions there. Changed to match with named capture groups. * Unit tests to verify parsing vlan_id and vlan_raw_device from name. Signed-off-by: Stefan Lendl <s.lendl@proxmox.com> Tested-by: Lukas Wagner <l.wagner@proxmox.com> Reviewed-by: Lukas Wagner <l.wagner@proxmox.com> Tested-by: Folke Gleumes <f.gleumes@proxmox.com> Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com>
This commit is contained in:
parent
4794006f81
commit
6f5757d9ff
@ -25,6 +25,8 @@ use crate::{open_backup_lockfile, BackupLockGuard};
|
||||
|
||||
lazy_static! {
|
||||
static ref PHYSICAL_NIC_REGEX: Regex = Regex::new(r"^(?:eth\d+|en[^:.]+|ib\d+)$").unwrap();
|
||||
static ref VLAN_INTERFACE_REGEX: Regex =
|
||||
Regex::new(r"^(?P<vlan_raw_device>\S+)\.(?P<vlan_id>\d+)|vlan(?P<vlan_id2>\d+)$").unwrap();
|
||||
}
|
||||
|
||||
pub fn is_physical_nic(iface: &str) -> bool {
|
||||
@ -41,6 +43,21 @@ pub fn bond_xmit_hash_policy_from_str(s: &str) -> Result<BondXmitHashPolicy, Err
|
||||
.map_err(|_: value::Error| format_err!("invalid bond_xmit_hash_policy '{}'", s))
|
||||
}
|
||||
|
||||
pub fn parse_vlan_id_from_name(iface_name: &str) -> Option<u16> {
|
||||
VLAN_INTERFACE_REGEX.captures(iface_name).and_then(|cap| {
|
||||
cap.name("vlan_id")
|
||||
.or(cap.name("vlan_id2"))
|
||||
.and_then(|id| id.as_str().parse::<u16>().ok())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_vlan_raw_device_from_name(iface_name: &str) -> Option<&str> {
|
||||
VLAN_INTERFACE_REGEX
|
||||
.captures(iface_name)
|
||||
.and_then(|cap| cap.name("vlan_raw_device"))
|
||||
.map(Into::into)
|
||||
}
|
||||
|
||||
// Write attributes not depending on address family
|
||||
fn write_iface_attributes(iface: &Interface, w: &mut dyn Write) -> Result<(), Error> {
|
||||
static EMPTY_LIST: Vec<String> = Vec::new();
|
||||
@ -652,4 +669,22 @@ iface individual_name inet manual
|
||||
.trim()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vlan_parse_vlan_id_from_name() {
|
||||
assert_eq!(parse_vlan_id_from_name("vlan100"), Some(100));
|
||||
assert_eq!(parse_vlan_id_from_name("vlan"), None);
|
||||
assert_eq!(parse_vlan_id_from_name("arbitrary"), None);
|
||||
assert_eq!(parse_vlan_id_from_name("vmbr0.100"), Some(100));
|
||||
assert_eq!(parse_vlan_id_from_name("vmbr0"), None);
|
||||
// assert_eq!(parse_vlan_id_from_name("vmbr0.1.400"), Some(400)); // NOTE ifupdown2 does actually support this
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vlan_parse_vlan_raw_device_from_name() {
|
||||
assert_eq!(parse_vlan_raw_device_from_name("vlan100"), None);
|
||||
assert_eq!(parse_vlan_raw_device_from_name("arbitrary"), None);
|
||||
assert_eq!(parse_vlan_raw_device_from_name("vmbr0"), None);
|
||||
assert_eq!(parse_vlan_raw_device_from_name("vmbr0.200"), Some("vmbr0"));
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::network::VLAN_INTERFACE_REGEX;
|
||||
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::io::BufRead;
|
||||
use std::iter::{Iterator, Peekable};
|
||||
@ -536,7 +538,6 @@ impl<R: BufRead> NetworkParser<R> {
|
||||
|
||||
lazy_static! {
|
||||
static ref INTERFACE_ALIAS_REGEX: Regex = Regex::new(r"^\S+:\d+$").unwrap();
|
||||
static ref VLAN_INTERFACE_REGEX: Regex = Regex::new(r"^\S+\.\d+|vlan\d+$").unwrap();
|
||||
}
|
||||
|
||||
if let Some(existing_interfaces) = existing_interfaces {
|
||||
|
@ -12,7 +12,9 @@ use pbs_api_types::{
|
||||
NETWORK_INTERFACE_ARRAY_SCHEMA, NETWORK_INTERFACE_LIST_SCHEMA, NETWORK_INTERFACE_NAME_SCHEMA,
|
||||
NODE_SCHEMA, PRIV_SYS_AUDIT, PRIV_SYS_MODIFY, PROXMOX_CONFIG_DIGEST_SCHEMA,
|
||||
};
|
||||
use pbs_config::network::{self, NetworkConfig};
|
||||
use pbs_config::network::{
|
||||
self, parse_vlan_id_from_name, parse_vlan_raw_device_from_name, NetworkConfig,
|
||||
};
|
||||
|
||||
use proxmox_rest_server::WorkerTask;
|
||||
|
||||
@ -231,6 +233,15 @@ pub fn read_interface(iface: String) -> Result<Value, Error> {
|
||||
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,
|
||||
@ -269,6 +280,8 @@ pub fn create_interface(
|
||||
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>,
|
||||
@ -373,6 +386,24 @@ pub fn create_interface(
|
||||
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
|
||||
@ -507,6 +538,15 @@ pub enum DeletableProperty {
|
||||
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,
|
||||
@ -557,6 +597,8 @@ pub fn update_interface(
|
||||
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>,
|
||||
@ -581,6 +623,15 @@ pub fn update_interface(
|
||||
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") {
|
||||
@ -734,6 +785,13 @@ pub fn update_interface(
|
||||
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(())
|
||||
|
Loading…
Reference in New Issue
Block a user