#!/usr/bin/env bats load helpers function setup_netns() { local tmp # 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/') # Tell runc to use it. update_config '(.. | select(.type? == "network")) .path |= "'"$ns_path"'"' } function delete_netns() { [ -v ns_name ] || return # Delete the namespace only if the ns_name variable is set. ip netns del "$ns_name" unset ns_name unset ns_path } function setup() { requires root setup_busybox # Create a dummy interface to move to the container. ip link add dummy0 type dummy udevadm settle } function teardown() { # The interface might be on the host or not, depending the test. If it's on the host, let's # delete it. ip link del dev dummy0 2>/dev/null 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" { setup_netns 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" { setup_netns update_config ' .linux.netDevices |= {"dummy0": {} } | .process.args |= ["ip", "address", "show", "dev", "dummy0"]' 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" { setup_netns update_config ' .linux.netDevices |= {"dummy0": {} } | .process.args |= ["ip", "address", "show", "dev", "dummy0"]' 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 -0 ip netns exec "$ns_name" ip address show dev dummy0 [[ "$output" == *"$global_ip "* ]] } @test "move network device to precreated container network namespace and set ip address without global scope" { setup_netns update_config ' .linux.netDevices |= {"dummy0": {} } | .process.args |= ["ip", "address", "show", "dev", "dummy0"]' 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" { setup_netns update_config ' .linux.netDevices |= {"dummy0": {} } | .process.args |= ["ip", "address", "show", "dev", "dummy0"]' mtu_value=1789 # Set 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 -0 ip netns exec "$ns_name" ip address show dev dummy0 [[ "$output" == *"mtu $mtu_value "* ]] } @test "move network device to precreated container network namespace and set mac address" { setup_netns update_config ' .linux.netDevices |= {"dummy0": {} } | .process.args |= ["ip", "address", "show", "dev", "dummy0"]' 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 -0 ip netns exec "$ns_name" ip address show dev dummy0 [[ "$output" == *"ether $mac_address "* ]] } @test "move network device to precreated container network namespace and rename" { setup_netns update_config ' .linux.netDevices |= { "dummy0": { "name" : "ctr_dummy0" } } | .process.args |= ["ip", "address", "show", "dev", "ctr_dummy0"]' 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" { setup_netns update_config ' .linux.netDevices |= { "dummy0": { "name" : "ctr_dummy0" } } | .process.args |= ["ip", "address", "show", "dev", "ctr_dummy0"]' 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 -0 ip netns exec "$ns_name" ip address show dev ctr_dummy0 [[ "$output" == *" $global_ip "* ]] [[ "$output" == *"ether $mac_address "* ]] [[ "$output" == *"mtu $mtu_value "* ]] }