mirror of
https://github.com/containers/netavark.git
synced 2026-02-05 06:45:56 +01:00
Add vrf support for bridges
Signed-off-by: André Cirne <dumahk21@gmail.com>
This commit is contained in:
@@ -19,7 +19,7 @@ use super::{
|
||||
constants::{
|
||||
ISOLATE_OPTION_FALSE, ISOLATE_OPTION_STRICT, ISOLATE_OPTION_TRUE,
|
||||
NO_CONTAINER_INTERFACE_ERROR, OPTION_ISOLATE, OPTION_METRIC, OPTION_MTU,
|
||||
OPTION_NO_DEFAULT_ROUTE,
|
||||
OPTION_NO_DEFAULT_ROUTE, OPTION_VRF,
|
||||
},
|
||||
core_utils::{self, get_ipam_addresses, join_netns, parse_option, CoreUtils},
|
||||
driver::{self, DriverInfo},
|
||||
@@ -50,6 +50,8 @@ struct InternalData {
|
||||
metric: Option<u32>,
|
||||
/// if set, no default gateway will be added
|
||||
no_default_route: bool,
|
||||
/// sef vrf for bridge
|
||||
vrf: Option<String>,
|
||||
// TODO: add vlan
|
||||
}
|
||||
|
||||
@@ -81,6 +83,7 @@ impl driver::NetworkDriver for Bridge<'_> {
|
||||
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)?.unwrap_or(false);
|
||||
let vrf: Option<String> = parse_option(&self.info.network.options, OPTION_VRF)?;
|
||||
|
||||
let static_mac = match &self.info.per_network_opts.static_mac {
|
||||
Some(mac) => Some(CoreUtils::decode_address_from_hex(mac)?),
|
||||
@@ -96,6 +99,7 @@ impl driver::NetworkDriver for Bridge<'_> {
|
||||
isolate,
|
||||
metric: Some(metric),
|
||||
no_default_route,
|
||||
vrf,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -494,6 +498,15 @@ fn create_interfaces(
|
||||
InfoKind::Bridge,
|
||||
);
|
||||
create_link_opts.mtu = data.mtu;
|
||||
|
||||
if let Some(vrf_name) = &data.vrf {
|
||||
let vrf = match host.get_link(netlink::LinkID::Name(vrf_name.to_string())) {
|
||||
Ok(vrf) => check_link_is_vrf(vrf, vrf_name)?,
|
||||
Err(err) => return Err(err).wrap("get vrf to set up bridge interface"),
|
||||
};
|
||||
create_link_opts.primary_index = vrf.header.index;
|
||||
}
|
||||
|
||||
host.create_link(create_link_opts).wrap("create bridge")?;
|
||||
|
||||
if data.ipam.ipv6_enabled {
|
||||
@@ -672,6 +685,30 @@ fn check_link_is_bridge(msg: LinkMessage, br_name: &str) -> NetavarkResult<LinkM
|
||||
)))
|
||||
}
|
||||
|
||||
/// make sure the LinkMessage is the kind VRF
|
||||
fn check_link_is_vrf(msg: LinkMessage, vrf_name: &str) -> NetavarkResult<LinkMessage> {
|
||||
for nla in msg.nlas.iter() {
|
||||
if let Nla::Info(info) = nla {
|
||||
for inf in info.iter() {
|
||||
if let Info::Kind(kind) = inf {
|
||||
if *kind == InfoKind::Vrf {
|
||||
return Ok(msg);
|
||||
} else {
|
||||
return Err(NetavarkError::Message(format!(
|
||||
"vrf {} already exists but is a {:?} interface",
|
||||
vrf_name, kind
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(NetavarkError::Message(format!(
|
||||
"could not determine namespace link kind for vrf {}",
|
||||
vrf_name
|
||||
)))
|
||||
}
|
||||
|
||||
fn remove_link(
|
||||
host: &mut netlink::Socket,
|
||||
netns: &mut netlink::Socket,
|
||||
|
||||
@@ -21,6 +21,7 @@ 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";
|
||||
pub const OPTION_VRF: &str = "vrf";
|
||||
|
||||
/// 100 is the default metric for most Linux networking tools.
|
||||
pub const DEFAULT_METRIC: u32 = 100;
|
||||
|
||||
33
test/600-bridge-vrf.bats
Normal file
33
test/600-bridge-vrf.bats
Normal file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bats -*- bats -*-
|
||||
#
|
||||
# bridge driver tests with vrf
|
||||
#
|
||||
|
||||
load helpers
|
||||
|
||||
@test vrf - bridge with vrf {
|
||||
run_in_host_netns ip link add test-vrf type vrf table 10
|
||||
run_in_host_netns ip link set dev test-vrf up
|
||||
|
||||
run_netavark --file ${TESTSDIR}/testfiles/simplebridge-vrf.json setup $(get_container_netns_path)
|
||||
|
||||
# check if vrf exists
|
||||
run_in_host_netns ip -j --details link show podman0
|
||||
result="$output"
|
||||
assert_json "$result" ".[].linkinfo.info_slave_kind" "==" "vrf" "Bridge has a vrf set"
|
||||
assert_json "$result" ".[].master" "==" "test-vrf" "Bridge has the correct vrf set"
|
||||
}
|
||||
|
||||
@test vrf - simple bridge {
|
||||
run_netavark --file ${TESTSDIR}/testfiles/simplebridge.json setup $(get_container_netns_path)
|
||||
run_in_host_netns ip -j --details link show podman0
|
||||
result="$output"
|
||||
assert_json "$result" ".[].linkinfo.info_slave_kind" "==" "null" "VRF is not set"
|
||||
}
|
||||
|
||||
@test vrf - non existent vrf {
|
||||
expected_rc=1 run_netavark --file ${TESTSDIR}/testfiles/simplebridge-vrf.json setup $(get_container_netns_path)
|
||||
result="$output"
|
||||
assert_json "$result" ".error" "==" "get vrf to set up bridge interface: Netlink error: No such device (os error 19)" "Attempt to set a non existent vrf"
|
||||
}
|
||||
|
||||
32
test/testfiles/simplebridge-vrf.json
Normal file
32
test/testfiles/simplebridge-vrf.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"container_id": "6ce776ea58b5",
|
||||
"container_name": "testcontainer",
|
||||
"networks": {
|
||||
"podman": {
|
||||
"interface_name": "eth0",
|
||||
"static_ips": [
|
||||
"10.88.0.2"
|
||||
]
|
||||
}
|
||||
},
|
||||
"network_info": {
|
||||
"podman": {
|
||||
"dns_enabled": false,
|
||||
"driver": "bridge",
|
||||
"id": "53ce4390f2adb1681eb1a90ec8b48c49c015e0a8d336c197637e7f65e365fa9e",
|
||||
"internal": false,
|
||||
"ipv6_enabled": false,
|
||||
"name": "podman",
|
||||
"network_interface": "podman0",
|
||||
"subnets": [
|
||||
{
|
||||
"gateway": "10.88.0.1",
|
||||
"subnet": "10.88.0.0/16"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"vrf": "test-vrf"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user