Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deterministic MAC addresses #137

Closed
nopid opened this issue Sep 6, 2021 · 5 comments
Closed

Deterministic MAC addresses #137

nopid opened this issue Sep 6, 2021 · 5 comments

Comments

@nopid
Copy link
Contributor

nopid commented Sep 6, 2021

Kathará currently has two limitations with respect to Netkit that complicate the deployment of a DHCP server inside a lab.

  1. By default Docker bind-mounts both files /etc/hosts and /etc/resolv.conf limiting the ability of the DHCP client to change the last one when a DNS server is specified ;
  2. Netkit provides deterministic pseudo-random MAC address for the machines interfaces (thanks to this patch), facilitating static DHCP leases.

To circumvent these limitations, we currently invoke the following shell script from shared.startup:

umount /etc/resolv.conf
umount /etc/hosts
echo '127.0.0.1	localhost' > /etc/hosts
for eth in $(ip -br a | grep '^eth' | cut -d@ -f1); do
    ip link set $eth address $(/shared/mojo/macaddr $HOSTNAME $eth)
done

where macaddr is a small Python script:

#!/usr/bin/env python3
from hashlib import sha1
from sys import argv
m = sha1()
m.update(argv[1].encode())
m.update(b"-")
m.update(argv[2].encode())
d = m.digest()
addr = [ (d[i]+d[i+6]) % 256 for i in range(6) ]
addr[0] &= 0xfe
addr[0] |= 0x02
print(':'.join(map(lambda x : ("00"+hex(x)[2:])[-2:],addr)))

It might be possible to directly provide these functionality inside Kathará.

@Skazza94
Copy link
Member

Skazza94 commented Oct 6, 2021

Hi @nopid,
unfortunately we cannot replicate the same function used in Netkit. I'll briefly explain what happens in the Network Plugin.

We create a veth pair with random names (automatically assigned by Linux), then one end of the veth is attached to the Linux bridge corresponding to the requested collision domain, and then we just say to Docker: "the other end will be attached to this endpoint", without specifying the interface name, but only the prefix eth (here).

So, during the process we don't know the name of the container (but only the ID of the "network endpoint") and the final name of the network interface. However, we generate the MAC address from the network ID and the endpoint ID (here). I don't know if you can retrieve such information from docker inspect at runtime, otherwise your solution seems a good workaround.

About /etc/resolv.conf and /etc/hosts, your solution seems good. I workarounded the overwrite of the /etc/resolv.conf file with a nasty trick (here). But using umount is better. I'll patch that in the next release.

@nopid
Copy link
Contributor Author

nopid commented Oct 6, 2021

Hi @Skazza94,

Thank you for the explanation and the pointer to the code where you generate the mac address from the network ID and endpoint ID. Of course, as these IDs vary on lab restart the provided mac addresses cannot be used for static DHCP configuration.

Reading through both the Docker SDK for Python documentation and the network package for Go documentation, it looks like the Network Plugin can receive drivers options during Join Requests (see Options in https://pkg.go.dev/github.com/docker/go-plugins-helpers/network#JoinRequest) that could be send during the connect call on the Python side (see driver_opts in https://docker-py.readthedocs.io/en/stable/networks.html#docker.models.networks.Network.connect). This might provide a channel to transmit a requested MAC address from Kathará to Docker during the network connection?

@Skazza94
Copy link
Member

Skazza94 commented Oct 6, 2021

Hi @nopid,
the solution you suggest seems good. In this way we can pass the machine name and the interface number (without eth).
I'm just concerned about one last thing.

We can pass the dict only with the connect command of Network. However, the first network of the device is attached on container creation (here), otherwise Docker will not create a network stack for the container (setting Network="none") and any other network can't be connected later. I cannot find a way to pass the dict in the Container.create method: https://docker-py.readthedocs.io/en/stable/containers.html#docker.models.containers.ContainerCollection.run.

EDIT: I opened an issue on Dockerpy, let's see what happens!

@nopid
Copy link
Contributor Author

nopid commented Oct 6, 2021

Hi @Skazza94,
The good news is that the low-level api seems to support a network_config parameter that can carry some driver_opt (via create_networking_config and create_endpoint_config) so it might be just a matter of adding support for it inside _create_container_args. Let's see what happen with your docker/docker-py#2896 issue.

@tcaiazzi tcaiazzi added the Pending Fix in progress label Mar 24, 2022
@Skazza94
Copy link
Member

Skazza94 commented May 6, 2023

Hi @nopid,
I know that this is a really old issue.

Some time ago I implemented the driver_opt in container run/create and finally now it is merged in dockerpy 6.1.0!
I will start to implement deterministic MAC addresses with the logic that we discussed (i.e. using device name and interface index).

Best regards.

@Skazza94 Skazza94 added enhancement manager/docker and removed Pending Fix in progress labels May 6, 2023
@Skazza94 Skazza94 added this to the Release 3.7.1 milestone Dec 13, 2023
Skazza94 added a commit that referenced this issue Dec 18, 2023
Co-Authored-By: Tommaso Caiazzi <tommasocaiazzi@gmail.com>
@tcaiazzi tcaiazzi changed the title Running a DHCP server inside Kathará (improving Netkit compatibility) Deterministic MAC addresses Dec 19, 2023
tcaiazzi added a commit that referenced this issue Dec 19, 2023
tcaiazzi added a commit that referenced this issue Dec 19, 2023
tcaiazzi added a commit that referenced this issue Dec 19, 2023
tcaiazzi added a commit that referenced this issue Dec 19, 2023
tcaiazzi added a commit that referenced this issue Dec 19, 2023
tcaiazzi added a commit that referenced this issue Dec 20, 2023
@tcaiazzi tcaiazzi closed this as completed Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

When branches are created from issues, their pull requests are automatically linked.

3 participants