Skip to content

Commit

Permalink
Merge pull request #470 from Luap99/macvlan-rename
Browse files Browse the repository at this point in the history
macvlan: fix name collision on hostns
  • Loading branch information
openshift-merge-robot authored Oct 27, 2022
2 parents 96630dd + 980d68a commit fba6bf6
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 2 deletions.
44 changes: 43 additions & 1 deletion src/network/macvlan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::{collections::HashMap, net::IpAddr, os::unix::prelude::RawFd};

use log::debug;
use netlink_packet_route::nlas::link::{InfoData, InfoKind, InfoMacVlan, Nla};
use rand::distributions::{Alphanumeric, DistString};

use crate::{
dns::aardvark::AardvarkEntry,
Expand Down Expand Up @@ -165,7 +166,48 @@ fn setup(
opts.info_data = Some(InfoData::MacVlan(vec![InfoMacVlan::Mode(
data.macvlan_mode,
)]));
host.create_link(opts).wrap("create macvlan interface")?;
let mut result = host.create_link(opts.clone());
// Sigh, the kernel creates the interface first in the hostns before moving it into the netns.
// Therefore it can fail with EEXIST if the name is already used on the host. Create the link
// with tmp name, then rename it in the netns.
// If you change the iterations here make sure to match the number in early return case below as well.
for i in 0..3 {
match result {
// no error we can break
Ok(_) => break,

Err(err) => match err {
NetavarkError::Netlink(ref e) if -e.code == libc::EEXIST => {
let random = Alphanumeric.sample_string(&mut rand::thread_rng(), 10);
let tmp_name = "mv-".to_string() + &random;
let mut opts = opts.clone();
opts.name = tmp_name.clone();
result = host.create_link(opts);
if let Err(ref e) = result {
// if last element return directly
if i == 2 {
return Err(NetavarkError::msg(format!(
"create macvlan interface: {}",
e
)));
}
// retry, error could EEXIST again because we pick a random name
continue;
}
let link = netns
.get_link(netlink::LinkID::Name(tmp_name))
.wrap("get tmp macvlan interface")?;
netns
.set_link_name(link.header.index, if_name.to_string())
.wrap("rename tmp macvlan interface")?;

// successful run, break out of loop
break;
}
err => return Err(err).wrap("create macvlan interface")?,
},
}
}

exec_netns!(hostns_fd, netns_fd, res, { disable_ipv6_autoconf(if_name) });
res?; // return autoconf sysctl error
Expand Down
13 changes: 12 additions & 1 deletion src/network/netlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ pub struct Socket {
buffer: [u8; 8192],
}

#[derive(Clone)]
pub struct CreateLinkOptions {
name: String,
pub name: String,
kind: InfoKind,
pub info_data: Option<InfoData>,
pub mtu: u32,
Expand Down Expand Up @@ -130,6 +131,16 @@ impl Socket {
Ok(())
}

pub fn set_link_name(&mut self, id: u32, name: String) -> NetavarkResult<()> {
let mut msg = LinkMessage::default();
msg.header.index = id;
msg.nlas.push(Nla::IfName(name));
let result = self.make_netlink_request(RtnlMessage::SetLink(msg), NLM_F_ACK)?;
expect_netlink_result!(result, 0);

Ok(())
}

pub fn del_link(&mut self, id: LinkID) -> NetavarkResult<()> {
let mut msg = LinkMessage::default();

Expand Down
47 changes: 47 additions & 0 deletions test/300-macvlan.bats
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,50 @@ EOF
assert_json "$link_info" ".[].address" "==" "$mac" "MAC matches container mac"
assert_json "$link_info" '.[].flags[] | select(.=="UP")' "==" "UP" "Container interface is up"
}


@test "macvlan same interface name on host" {

read -r -d '\0' config <<EOF
{
"container_id": "someID",
"container_name": "someName",
"networks": {
"podman": {
"static_ips": [
"10.88.0.2"
],
"interface_name": "eth0"
}
},
"network_info": {
"podman": {
"name": "podman",
"id": "2f259bab93aaaaa2542ba43ef33eb990d0999ee1b9924b557b7be53c0b7a1bb9",
"driver": "macvlan",
"network_interface": "eth0",
"subnets": [
{
"subnet": "10.88.0.0/16",
"gateway": "10.88.0.1"
}
],
"ipv6_enabled": false,
"internal": false,
"dns_enabled": false,
"ipam_options": {
"driver": "host-local"
}
}
}
}\0
EOF

run_in_host_netns ip link add eth0 type dummy

run_netavark setup $(get_container_netns_path) <<<"$config"

run_in_container_netns ip link show eth0

run_netavark teardown $(get_container_netns_path) <<<"$config"
}

0 comments on commit fba6bf6

Please sign in to comment.