title: How to build an OpenStack alternative: Step 3, Generating Mac Addresses
---
pub_date: 2020-01-13
---
author: ungleich virtualisation team
---
twitter_handle: ungleich
---
_hidden: no
---
_discoverable: yes
---
abstract:
First step to automation
---
body:

This time we describe how to begin automation in uncloud,
our OpenStack alternative.

The previous time we described
[how to secure the network](../how-to-build-an-openstack-alternative-step-2-secure-the-network/).

## Mac Addresses

Mac addresses are identifiers for network cards. Like a street number
is for a house. A virtual machine can have one or more network
interfaces. Each of these interfaces need a unique number, the mac
address.

## Choosing the prefix

We checked how [OpenNebula](https://opennebula.org/) is doing it.
They basically use the **02:00** prefix and generate mac addresses after
that. The
[QEMU mac address
prefix](https://gist.github.com/ashee/9241ab6281e6f4d1ef9b)
seems to be 52:54:00.
According to [Michael
Stapelberg](https://michael.stapelberg.ch/posts/2012-11-21-kvm_best_practices_2012/)
the **f6** prefix can be used due to the second lowest bit set to 1.

Checking with [Wikipedia](https://en.wikipedia.org/wiki/MAC_address),
this bit indeed specifies whether or not a mac address is locally or
universally administrated.

For that reason we will use **42** as our prefix, which is **1000010**
in binary and thus has the second least significant bit set to 1.

## Generating Mac addresses

Mac addresses are basically just numbers and so we treat them as
such. We need to store the index of which is the current mac address
and for the next time we create a VM, use the next mac address.

The python code to generate a new mac address looks as follows:

```
    @staticmethod
    def int_to_mac(number):
        b = number.to_bytes(6, byteorder="big")
        return ':'.join(format(s, '02x') for s in b)

    def getnext(self):
        if self.last:
            last_number = int(self.last[0], 16)

            if last_number == int('0xffffff', 16):
                raise Error("Exhausted all possible mac addresses - try to free some")

            next_number = last_number + 1
        else:
            next_number = 0

        next_number_string = "{:012x}".format(next_number)

        next_mac_number = self.prefix + next_number
        next_mac = self.int_to_mac(next_mac_number)
```

It basically says:

* If there has been a mac address used add 1 to it and use the next
  one
* Produce an error, if the whole prefix has been used
* If no mac address has been used, use the first one
* Convert the number to the standard format (aa:bb:cc:dd:ee:ff)

There is some additional logic on saving the MAC address to which we
will come back in one of the next posts.

## Using the MAC address generator

From our prototype, we modify the original `vm.sh` script to include a
call to the mac address generator as follows:

```
...
mac=$(./mac-gen.py)
...
$qemu -name "uncloud-${uuid}" \
      -machine pc,accel=${accel} \
      -m ${memory} \
      -smp ${cores} \
      -uuid ${uuid} \
      -drive file=alpine-virt-3.11.2-x86_64.iso,media=cdrom \
      -netdev tap,id=netmain,script=./ifup.sh,downscript=./ifdown.sh \
      -device virtio-net-pci,netdev=netmain,id=net0,mac=${mac}
```

In good UNIX manner, the generator simply outputs the MAC address on
stdout to be used by any software.

## Status

While being a small and very specific tool, the mac address generator
is actually a key element of creating a virtualisation
framework. Without it, it is practically impossible to spawn a dynamic
amount of virtual machines.

With our prototype, a secured network and the mac address generator we
are not far from being able to migrate some test VMs to uncloud.
