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.