Skip to content

Commit

Permalink
Merge pull request #698 from Luap99/bclim
Browse files Browse the repository at this point in the history
macvlan: add bclim option
  • Loading branch information
flouthoc authored May 25, 2023
2 parents bd41190 + e4e78f0 commit 5ab1d08
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 40 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ zbus = { version = "3.12.0" }
nix = "0.26.2"
rand = "0.8.5"
sha2 = "0.10.6"
netlink-packet-utils = "0.5"
netlink-packet-route = "0.15"
netlink-packet-core = "0.5"
fs2 = "0.4.3"
Expand Down
14 changes: 7 additions & 7 deletions src/network/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,12 @@ impl driver::NetworkDriver for Bridge<'_> {
}
let ipam = get_ipam_addresses(self.info.per_network_opts, self.info.network)?;

let mtu: u32 = parse_option(&self.info.network.options, OPTION_MTU, 0)?;
let isolate: bool = parse_option(&self.info.network.options, OPTION_ISOLATE, false)?;
let metric: u32 = parse_option(&self.info.network.options, OPTION_METRIC, 100)?;
let mtu: u32 = parse_option(&self.info.network.options, OPTION_MTU)?.unwrap_or(0);
let isolate: bool =
parse_option(&self.info.network.options, OPTION_ISOLATE)?.unwrap_or(false);
let metric: u32 = parse_option(&self.info.network.options, OPTION_METRIC)?.unwrap_or(100);
let no_default_route: bool =
parse_option(&self.info.network.options, OPTION_NO_DEFAULT_ROUTE, false)?;
parse_option(&self.info.network.options, OPTION_NO_DEFAULT_ROUTE)?.unwrap_or(false);

let static_mac = match &self.info.per_network_opts.static_mac {
Some(mac) => Some(CoreUtils::decode_address_from_hex(mac)?),
Expand Down Expand Up @@ -389,9 +390,8 @@ impl<'a> Bridge<'a> {
Some(d) => (&d.ipam.container_addresses, &d.ipam.nameservers, d.isolate),
None => {
// options are not yet parsed
let isolate = match parse_option(&self.info.network.options, OPTION_ISOLATE, false)
{
Ok(i) => i,
let isolate: bool = match parse_option(&self.info.network.options, OPTION_ISOLATE) {
Ok(i) => i.unwrap_or(false),
Err(e) => {
// just log we still try to do as much as possible for cleanup
error!("failed to parse {} option: {}", OPTION_ISOLATE, e);
Expand Down
1 change: 1 addition & 0 deletions src/network/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub const OPTION_MTU: &str = "mtu";
pub const OPTION_MODE: &str = "mode";
pub const OPTION_METRIC: &str = "metric";
pub const OPTION_NO_DEFAULT_ROUTE: &str = "no_default_route";
pub const OPTION_BCLIM: &str = "bclim";

/// 100 is the default metric for most Linux networking tools.
pub const DEFAULT_METRIC: u32 = 100;
Expand Down
34 changes: 16 additions & 18 deletions src/network/core_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,10 @@ pub fn get_netavark_dns_port() -> Result<u16, NetavarkError> {
pub fn parse_option<T>(
opts: &Option<HashMap<String, String>>,
name: &str,
default: T,
) -> NetavarkResult<T>
) -> NetavarkResult<Option<T>>
where
T: FromStr,
<T as FromStr>::Err: Display,
T: Default,
{
let val = match opts.as_ref().and_then(|map| map.get(name)) {
Some(val) => match val.parse::<T>() {
Expand All @@ -64,10 +62,10 @@ where
)));
}
},
// if no option is set return the default value
None => default,
// if no option is set return None
None => return Ok(None),
};
Ok(val)
Ok(Some(val))
}

pub fn get_ipam_addresses<'a>(
Expand Down Expand Up @@ -232,29 +230,29 @@ impl CoreUtils {
Ok(result)
}

pub fn get_macvlan_mode_from_string(mode: &str) -> NetavarkResult<u32> {
pub fn get_macvlan_mode_from_string(mode: Option<&str>) -> NetavarkResult<u32> {
match mode {
// default to bridge when unset
"" | "bridge" => Ok(MACVLAN_MODE_BRIDGE),
"private" => Ok(MACVLAN_MODE_PRIVATE),
"vepa" => Ok(MACVLAN_MODE_VEPA),
"passthru" => Ok(MACVLAN_MODE_PASSTHRU),
"source" => Ok(MACVLAN_MODE_SOURCE),
None | Some("") | Some("bridge") => Ok(MACVLAN_MODE_BRIDGE),
Some("private") => Ok(MACVLAN_MODE_PRIVATE),
Some("vepa") => Ok(MACVLAN_MODE_VEPA),
Some("passthru") => Ok(MACVLAN_MODE_PASSTHRU),
Some("source") => Ok(MACVLAN_MODE_SOURCE),
// default to bridge
name => Err(NetavarkError::msg(format!(
Some(name) => Err(NetavarkError::msg(format!(
"invalid macvlan mode \"{}\"",
name
))),
}
}

pub fn get_ipvlan_mode_from_string(mode: &str) -> NetavarkResult<u16> {
pub fn get_ipvlan_mode_from_string(mode: Option<&str>) -> NetavarkResult<u16> {
match mode {
// default to l2 when unset
"" | "l2" => Ok(IPVLAN_MODE_L2),
"l3" => Ok(IPVLAN_MODE_L3),
"l3s" => Ok(IPVLAN_MODE_L3S),
name => Err(NetavarkError::msg(format!(
None | Some("") | Some("l2") => Ok(IPVLAN_MODE_L2),
Some("l3") => Ok(IPVLAN_MODE_L3),
Some("l3s") => Ok(IPVLAN_MODE_L3S),
Some(name) => Err(NetavarkError::msg(format!(
"invalid ipvlan mode \"{}\"",
name
))),
Expand Down
55 changes: 40 additions & 15 deletions src/network/vlan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use log::{debug, error};
use std::{collections::HashMap, net::IpAddr, os::unix::prelude::RawFd};

use netlink_packet_route::nlas::link::{InfoData, InfoIpVlan, InfoKind, InfoMacVlan, Nla};
use netlink_packet_utils::nla::DefaultNla;
use rand::distributions::{Alphanumeric, DistString};

use crate::network::macvlan_dhcp::{get_dhcp_lease, release_dhcp_lease};
Expand All @@ -14,7 +15,7 @@ use crate::{

use super::{
constants::{
NO_CONTAINER_INTERFACE_ERROR, OPTION_METRIC, OPTION_MODE, OPTION_MTU,
NO_CONTAINER_INTERFACE_ERROR, OPTION_BCLIM, OPTION_METRIC, OPTION_MODE, OPTION_MTU,
OPTION_NO_DEFAULT_ROUTE,
},
core_utils::{self, get_ipam_addresses, parse_option, CoreUtils},
Expand All @@ -30,6 +31,9 @@ enum KindData {
mac_address: Option<Vec<u8>>,
/// macvlan mode
mode: u32,

// IFLA_MACVLAN_BC_CUTOFF option if set
bclim: Option<i32>,
},
IpVlan {
/// ipvlan mode
Expand Down Expand Up @@ -88,14 +92,14 @@ impl driver::NetworkDriver for Vlan<'_> {
return Err(NetavarkError::msg(NO_CONTAINER_INTERFACE_ERROR));
}

let mode = parse_option(&self.info.network.options, OPTION_MODE, String::default())?;
let mode: Option<String> = parse_option(&self.info.network.options, OPTION_MODE)?;

let mut ipam = get_ipam_addresses(self.info.per_network_opts, self.info.network)?;

let mtu = parse_option(&self.info.network.options, OPTION_MTU, 0)?;
let metric = parse_option(&self.info.network.options, OPTION_METRIC, 100)?;
let mtu = parse_option(&self.info.network.options, OPTION_MTU)?.unwrap_or(0);
let metric = parse_option(&self.info.network.options, OPTION_METRIC)?.unwrap_or(100);
let no_default_route: bool =
parse_option(&self.info.network.options, OPTION_NO_DEFAULT_ROUTE, false)?;
parse_option(&self.info.network.options, OPTION_NO_DEFAULT_ROUTE)?.unwrap_or(false);

// Remove gateways when marked as internal network
if self.info.network.internal {
Expand All @@ -115,15 +119,19 @@ impl driver::NetworkDriver for Vlan<'_> {
metric: Some(metric),
kind: match self.info.network.driver.as_str() {
super::constants::DRIVER_IPVLAN => KindData::IpVlan {
mode: CoreUtils::get_ipvlan_mode_from_string(&mode)?,
},
super::constants::DRIVER_MACVLAN => KindData::MacVlan {
mode: CoreUtils::get_macvlan_mode_from_string(&mode)?,
mac_address: match &self.info.per_network_opts.static_mac {
Some(mac) => Some(CoreUtils::decode_address_from_hex(mac)?),
None => None,
},
mode: CoreUtils::get_ipvlan_mode_from_string(mode.as_deref())?,
},
super::constants::DRIVER_MACVLAN => {
let bclim = parse_option(&self.info.network.options, OPTION_BCLIM)?;
KindData::MacVlan {
mode: CoreUtils::get_macvlan_mode_from_string(mode.as_deref())?,
mac_address: match &self.info.per_network_opts.static_mac {
Some(mac) => Some(CoreUtils::decode_address_from_hex(mac)?),
None => None,
},
bclim,
}
}
other => {
return Err(NetavarkError::msg(format!(
"unsupported VLAN type {}",
Expand Down Expand Up @@ -268,13 +276,30 @@ fn setup(
opts.info_data = Some(InfoData::IpVlan(vec![InfoIpVlan::Mode(*mode)]));
opts
}
KindData::MacVlan { mode, mac_address } => {
KindData::MacVlan {
mode,
mac_address,
bclim,
} => {
let mut opts = CreateLinkOptions::new(if_name.to_string(), InfoKind::MacVlan);
opts.mac = mac_address.clone().unwrap_or_default();
opts.mtu = data.mtu;
opts.netns = netns_fd;
opts.link = link.header.index;
opts.info_data = Some(InfoData::MacVlan(vec![InfoMacVlan::Mode(*mode)]));

let mut mv_opts = vec![InfoMacVlan::Mode(*mode)];
if let Some(bclim) = bclim {
debug!("setting macvlan bclim to {bclim}");
// TODO: change this to use the upstream const when available
// https://github.com/rust-netlink/netlink-packet-route/pull/32
// IFLA_MACVLAN_BC_CUTOFF const in the kernel is 9
mv_opts.push(InfoMacVlan::Other(DefaultNla::new(
9,
bclim.to_ne_bytes().to_vec(),
)))
}

opts.info_data = Some(InfoData::MacVlan(mv_opts));
opts
}
};
Expand Down

0 comments on commit 5ab1d08

Please sign in to comment.