Macvlan Docker interface with explicit endpoint MAC address

Macvlan Docker interface with explicit endpoint MAC address

Probably one of thos “unicorn” problems, but I was in need of running a Juniper vMX Docker Container attached to a network interface using a statically assigned IP and MAC address. The use case is to run vMX on a baremetal server in a public cloud.

Macvlan is ideal to share a single network interface with a compute host and containers on it. But it currently doesn’t allow to specify the MAC address, except when used as the single container interface: See [#1009](https://github.com/docker/libnetwork/issues/1009).

I need to define the MAC address, which is provided by the public cloud provider. But how? docker network connect doesn’t have ‘–mac-address’ option (docker run has it, but only for the default/first network interface).

So, time to play with macvlan interfaces and network namespaces myself ..

For documentation purpose, lets say the baremetal server got the following IP addresses assigned to interface enp2s0 (using IPv4 example addresses from RFC 5737:

203.0.113.10/24
203.0.113.22/24 with MAC address 00:50:56:00:1A:E2

After launching the vMX container with the default network eth0 attached to docker0, it will wait for additional interfaces to be attached to the running container. This is where I execute following script, specifing the container name (vmx1), physical network interface to attach to (enp2s0) and the MAC address to assign to the macvlan based interface in the container. The script requires sudo privileges.

$ ./add-macvlan-link.sh vmx1 enp2s0 00:50:56:00:1A:E2
CONTAINER=vmx1 INTERFACE=enp2s0 MACADDR=00:50:56:00:1A:E2
vmx1 has pid 1815
creating namespace for container vmx1
vmx1 has 1 eth interfaces
eth1 attached to container vmx1 using 00:50:56:00:1A:E2

And the script itself:

#!/bin/bash
CONTAINER=$1
INTERFACE=$2
MACADDR=$3
if [ -z "$MACADDR" ]; then
    echo "$0 <container> <physical interface> <mac-address>"
    exit 1
fi

echo "CONTAINER=$CONTAINER INTERFACE=$INTERFACE MACADDR=$MACADDR"

sudo mkdir -p /var/run/netns

pid=$(docker inspect -f "{{.State.Pid}}" $CONTAINER)
if [ -z "$pid" ]; then
    echo "Can't find pid for container $CONTAINER"
    exit 1
fi

echo "$CONTAINER has pid $pid"
echo "creating namespace for container $CONTAINER"
sudo ln -sf /proc/$pid/ns/net /var/run/netns/$CONTAINER

ifcount=$(sudo ip netns exec $CONTAINER ifconfig -a | grep ^eth | wc -l)

echo "$CONTAINER has $ifcount eth interfaces"

sudo ip link add v${CONTAINER}-${ifcount} link $INTERFACE type macvlan mode bridge
sudo ip link set v${CONTAINER}-${ifcount} address $MACADDR
sudo ip link set v${CONTAINER}-${ifcount} name eth${ifcount} netns $CONTAINER
sudo ip netns exec $CONTAINER ifconfig eth${ifcount} up

echo "eth${ifcount} attached to container $CONTAINER using $MACADDR"

The script first finds out the process Id of the running container, then creates a symlink under /var/run/netns in order for ip netns commands to work, then creates a an IP link of type macvlan in bridge mode using a unique name (combining container name and unused ethX number) and places it into the network namespace of the container. Finally, the interface is brought up.
Typically one would also set the MTU, but because this is a public cloud, I have to leave it at its default of 1500.

Once the vMX is running, I configured interface ge–0/0/0 with the IPv4 address and add a static route and voila. Success!

I can log into the vMX over the Internet:

$ ssh 203.0.113.111
Last login: Mon Oct  1 14:51:35 2018 from 212.51.142.77
--- JUNOS 18.3R1.9 Kernel 64-bit  JNPR-11.0-20180816.8630ec5_buil
mwiget@vmx1>
mwiget@vmx1> show interfaces terse ge-0/0/0
Interface               Admin Link Proto    Local                 Remote
ge-0/0/0                up    up
ge-0/0/0.0              up    up   inet     203.0.113.111/24
                                   multiservice

FYI, it is not possible to reach the vMX container via IP from the compute node itself. You can find out more about macvlan here: Use macvlan networks.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Blog at WordPress.com.

Up ↑

%d bloggers like this: