mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
Add support for Linux Network Devices
Implement support for passing Linux Network Devices to the container network namespace. The network device is passed during the creation of the container, before the process is started. It implements the logic defined in the OCI runtime specification. Signed-off-by: Antonio Ojea <aojea@google.com>
This commit is contained in:
committed by
Antonio Ojea
parent
889c7b272f
commit
8d180e9658
@@ -2,14 +2,34 @@
|
||||
|
||||
load helpers
|
||||
|
||||
function create_netns() {
|
||||
# Create a temporary name for the test network namespace.
|
||||
tmp=$(mktemp -u)
|
||||
ns_name=$(basename "$tmp")
|
||||
|
||||
# Create the network namespace.
|
||||
ip netns add "$ns_name"
|
||||
ns_path=$(ip netns add "$ns_name" 2>&1 | sed -e 's/.*"\(.*\)".*/\1/')
|
||||
}
|
||||
|
||||
function delete_netns() {
|
||||
# Delete the namespace only if the ns_name variable is set.
|
||||
[ -v ns_name ] && ip netns del "$ns_name"
|
||||
}
|
||||
|
||||
function setup() {
|
||||
# XXX: currently criu require root containers.
|
||||
requires criu root
|
||||
|
||||
setup_busybox
|
||||
|
||||
# Create a dummy interface to move to the container.
|
||||
ip link add dummy0 type dummy
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
ip link del dev dummy0
|
||||
delete_netns
|
||||
teardown_bundle
|
||||
}
|
||||
|
||||
@@ -122,6 +142,52 @@ function simple_cr() {
|
||||
done
|
||||
}
|
||||
|
||||
function simple_cr_with_netdevice() {
|
||||
# Set custom parameters to the netdevice to validate those are respected
|
||||
mtu_value=1789
|
||||
mac_address="00:11:22:33:44:55"
|
||||
global_ip="169.254.169.77/32"
|
||||
|
||||
ip link set mtu "$mtu_value" dev dummy0
|
||||
ip link set address "$mac_address" dev dummy0
|
||||
ip address add "$global_ip" dev dummy0
|
||||
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }'
|
||||
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox_netdevice
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
testcontainer test_busybox_netdevice running
|
||||
run runc exec test_busybox_netdevice ip address show dev dummy0
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *" $global_ip "* ]]
|
||||
[[ "$output" == *"ether $mac_address "* ]]
|
||||
[[ "$output" == *"mtu $mtu_value "* ]]
|
||||
|
||||
for _ in $(seq 2); do
|
||||
# checkpoint the running container
|
||||
runc "$@" checkpoint --work-path ./work-dir test_busybox_netdevice
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# after checkpoint busybox is no longer running
|
||||
testcontainer test_busybox_netdevice checkpointed
|
||||
|
||||
# restore from checkpoint
|
||||
runc "$@" restore -d --work-path ./work-dir --console-socket "$CONSOLE_SOCKET" test_busybox_netdevice
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# busybox should be back up and running
|
||||
testcontainer test_busybox_netdevice running
|
||||
run runc exec test_busybox_netdevice ip address show dev dummy0
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *" $global_ip "* ]]
|
||||
[[ "$output" == *"ether $mac_address "* ]]
|
||||
[[ "$output" == *"mtu $mtu_value "* ]]
|
||||
done
|
||||
}
|
||||
|
||||
@test "checkpoint and restore" {
|
||||
simple_cr
|
||||
}
|
||||
@@ -151,6 +217,35 @@ function simple_cr() {
|
||||
simple_cr
|
||||
}
|
||||
|
||||
@test "checkpoint and restore with netdevice" {
|
||||
simple_cr_with_netdevice
|
||||
}
|
||||
|
||||
@test "checkpoint and restore with netdevice (bind mount, destination is symlink)" {
|
||||
mkdir -p rootfs/real/conf
|
||||
ln -s /real/conf rootfs/conf
|
||||
update_config ' .mounts += [{
|
||||
source: ".",
|
||||
destination: "/conf",
|
||||
options: ["bind"]
|
||||
}]'
|
||||
simple_cr_with_netdevice
|
||||
}
|
||||
|
||||
@test "checkpoint and restore with netdevice (with --debug)" {
|
||||
simple_cr_with_netdevice --debug
|
||||
}
|
||||
|
||||
@test "checkpoint and restore with netdevice (cgroupns)" {
|
||||
# cgroupv2 already enables cgroupns so this case was tested above already
|
||||
requires cgroups_v1 cgroupns
|
||||
|
||||
# enable CGROUPNS
|
||||
update_config '.linux.namespaces += [{"type": "cgroup"}]'
|
||||
|
||||
simple_cr_with_netdevice
|
||||
}
|
||||
|
||||
@test "checkpoint --pre-dump (bad --parent-path)" {
|
||||
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
function create_netns() {
|
||||
# Create a temporary name for the test network namespace.
|
||||
tmp=$(mktemp -u)
|
||||
ns_name=$(basename "$tmp")
|
||||
|
||||
# Create the network namespace.
|
||||
ip netns add "$ns_name"
|
||||
ns_path=$(ip netns add "$ns_name" 2>&1 | sed -e 's/.*"\(.*\)".*/\1/')
|
||||
}
|
||||
|
||||
function delete_netns() {
|
||||
# Delete the namespace only if the ns_name variable is set.
|
||||
[ -v ns_name ] && ip netns del "$ns_name"
|
||||
}
|
||||
|
||||
function setup() {
|
||||
requires root
|
||||
setup_busybox
|
||||
|
||||
# Create a dummy interface to move to the container.
|
||||
ip link add dummy0 type dummy
|
||||
}
|
||||
|
||||
function teardown() {
|
||||
ip link del dev dummy0
|
||||
delete_netns
|
||||
teardown_bundle
|
||||
}
|
||||
|
||||
@test "move network device to container network namespace" {
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "dummy0"]'
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "move network device to container network namespace and restore it back" {
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }'
|
||||
|
||||
runc run -d --console-socket "$CONSOLE_SOCKET" test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# The network namespace owner controls the lifecycle of the interface.
|
||||
# The interface should remain on the namespace after the container was killed.
|
||||
runc delete --force test_busybox
|
||||
|
||||
# Move back the interface to the root namespace (pid 1).
|
||||
ip netns exec "$ns_name" ip link set dev dummy0 netns 1
|
||||
|
||||
# Verify the interface is back in the root network namespace.
|
||||
ip address show dev dummy0
|
||||
}
|
||||
|
||||
@test "move network device to precreated container network namespace" {
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "dummy0"]'
|
||||
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Verify the interface is still present in the network namespace.
|
||||
ip netns exec "$ns_name" ip address show dev dummy0
|
||||
}
|
||||
|
||||
@test "move network device to precreated container network namespace and set ip address with global scope" {
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "dummy0"]'
|
||||
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
|
||||
global_ip="169.254.169.77/32"
|
||||
|
||||
# Set the interface down to avoid possible network problems.
|
||||
# Set a custom address to the interface.
|
||||
ip link set down dev dummy0
|
||||
ip address add "$global_ip" dev dummy0
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$global_ip "* ]]
|
||||
|
||||
# Verify the interface is still present in the network namespace.
|
||||
run ip netns exec "$ns_name" ip address show dev dummy0
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$global_ip "* ]]
|
||||
}
|
||||
|
||||
@test "move network device to precreated container network namespace and set ip address without global scope" {
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "dummy0"]'
|
||||
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
|
||||
non_global_ip="127.0.0.33"
|
||||
|
||||
# Set the interface down to avoid possible network problems.
|
||||
# Set a custom address to the interface.
|
||||
ip link set down dev dummy0
|
||||
ip address add "$non_global_ip" dev dummy0
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" != *" $non_global_ip "* ]]
|
||||
|
||||
# Verify the interface is still present in the network namespace.
|
||||
ip netns exec "$ns_name" ip address show dev dummy0
|
||||
}
|
||||
|
||||
@test "move network device to precreated container network namespace and set mtu" {
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "dummy0"]'
|
||||
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
|
||||
mtu_value=1789
|
||||
# Cet a custom mtu to the interface.
|
||||
ip link set mtu "$mtu_value" dev dummy0
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"mtu $mtu_value "* ]]
|
||||
|
||||
# Verify the interface is still present in the network namespace.
|
||||
run ip netns exec "$ns_name" ip address show dev dummy0
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"mtu $mtu_value "* ]]
|
||||
}
|
||||
|
||||
@test "move network device to precreated container network namespace and set mac address" {
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "dummy0"]'
|
||||
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
|
||||
mac_address="00:11:22:33:44:55"
|
||||
# set a custom mac address to the interface
|
||||
ip link set address "$mac_address" dev dummy0
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"ether $mac_address "* ]]
|
||||
|
||||
# Verify the interface is still present in the network namespace.
|
||||
run ip netns exec "$ns_name" ip address show dev dummy0
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"ether $mac_address "* ]]
|
||||
}
|
||||
|
||||
@test "move network device to precreated container network namespace and rename" {
|
||||
update_config ' .linux.netDevices |= { "dummy0": { "name" : "ctr_dummy0" } }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "ctr_dummy0"]'
|
||||
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# Verify the interface is still present in the network namespace.
|
||||
ip netns exec "$ns_name" ip address show dev ctr_dummy0
|
||||
}
|
||||
|
||||
@test "move network device to precreated container network namespace and rename and set mtu and mac and ip address" {
|
||||
update_config ' .linux.netDevices |= { "dummy0": { "name" : "ctr_dummy0" } }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "ctr_dummy0"]'
|
||||
|
||||
# Tell runc which network namespace to use.
|
||||
create_netns
|
||||
update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"'
|
||||
|
||||
mtu_value=1789
|
||||
mac_address="00:11:22:33:44:55"
|
||||
global_ip="169.254.169.77/32"
|
||||
|
||||
# Set a custom mtu to the interface.
|
||||
ip link set mtu "$mtu_value" dev dummy0
|
||||
# Set a custom mac address to the interface.
|
||||
ip link set address "$mac_address" dev dummy0
|
||||
# Set a custom ip address to the interface.
|
||||
ip address add "$global_ip" dev dummy0
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *" $global_ip "* ]]
|
||||
[[ "$output" == *"ether $mac_address "* ]]
|
||||
[[ "$output" == *"mtu $mtu_value "* ]]
|
||||
|
||||
# Verify the interface is still present in the network namespace.
|
||||
run ip netns exec "$ns_name" ip address show dev ctr_dummy0
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *" $global_ip "* ]]
|
||||
[[ "$output" == *"ether $mac_address "* ]]
|
||||
[[ "$output" == *"mtu $mtu_value "* ]]
|
||||
}
|
||||
@@ -246,3 +246,39 @@ function teardown() {
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == "$netns_id" ]]
|
||||
}
|
||||
|
||||
@test "userns with network interface" {
|
||||
requires root
|
||||
|
||||
# Create a dummy interface to move to the container.
|
||||
ip link add dummy0 type dummy
|
||||
|
||||
update_config ' .linux.netDevices |= {"dummy0": {} }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "dummy0"]'
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# The interface is virtual and should not exist because
|
||||
# is deleted during the namespace cleanup.
|
||||
run ip link del dummy0
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "userns with network interface renamed" {
|
||||
requires root
|
||||
|
||||
# Create a dummy interface to move to the container.
|
||||
ip link add dummy0 type dummy
|
||||
|
||||
update_config ' .linux.netDevices |= { "dummy0": { "name" : "ctr_dummy0" } }
|
||||
| .process.args |= ["ip", "address", "show", "dev", "ctr_dummy0"]'
|
||||
|
||||
runc run test_busybox
|
||||
[ "$status" -eq 0 ]
|
||||
|
||||
# The interface is virtual and should not exist because
|
||||
# is deleted during the namespace cleanup.
|
||||
run ip link del dummy0
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user