| =============================================================================== | 
 |  | 
 | This patch makes MAC addresses of network interfaces predictable. In | 
 | particular, it adds a small routine that computes MAC addresses of based on | 
 | a SHA1 hash of the virtual machine name and interface ID. | 
 |  | 
 | TECHNICAL INFORMATION: | 
 |  | 
 | Applies to vanilla kernel 3.9.4. | 
 |  | 
 | =============================================================================== | 
 | --- a/arch/um/drivers/Kconfig | 
 | +++ b/arch/um/drivers/Kconfig | 
 | @@ -146,6 +146,20 @@ config UML_NET | 
 |  	  enable at least one of the following transport options to actually | 
 |  	  make use of UML networking. | 
 |   | 
 | +config UML_NET_DETERMINISTIC_MAC | 
 | +	bool "Use deterministic MAC addresses for network interfaces" | 
 | +	default y | 
 | +	depends on UML_NET | 
 | +	select CRYPTO_SHA1 | 
 | +	help | 
 | +        Virtual network devices inside a User-Mode Linux instance must be | 
 | +        assigned a MAC (Ethernet) address. If none is specified on the UML | 
 | +        command line, one must be automatically computed. If this option is | 
 | +        enabled, a randomly generated address is used. Otherwise, if this | 
 | +        option is disabled, the address is generated from a SHA1 hash of | 
 | +        the umid of the UML instance and the interface name. The latter choice | 
 | +        is useful to make MAC addresses predictable. | 
 | + | 
 |  config UML_NET_ETHERTAP | 
 |  	bool "Ethertap transport" | 
 |  	depends on UML_NET | 
 | --- a/arch/um/drivers/net_kern.c | 
 | +++ b/arch/um/drivers/net_kern.c | 
 | @@ -25,6 +25,14 @@ | 
 |  #include <net_kern.h> | 
 |  #include <net_user.h> | 
 |   | 
 | +#include <crypto/sha.h> | 
 | +#include <crypto/hash.h> | 
 | +#include <linux/string.h> | 
 | +#include <linux/crypto.h> | 
 | +#include <linux/err.h> | 
 | +#include <linux/scatterlist.h> | 
 | +#include "os.h" | 
 | + | 
 |  #define DRIVER_NAME "uml-netdev" | 
 |   | 
 |  static DEFINE_SPINLOCK(opened_lock); | 
 | @@ -286,9 +294,51 @@ static void uml_net_user_timer_expire(st | 
 |  #endif | 
 |  } | 
 |   | 
 | +#ifdef CONFIG_UML_NET_DETERMINISTIC_MAC | 
 | + | 
 | +/* Compute a SHA1 hash of the UML instance's id and | 
 | + *  * an interface name. */ | 
 | +static int compute_hash(const char *umid, const char *ifname, char *hash) | 
 | +{ | 
 | +	struct ahash_request *desc; | 
 | +	struct crypto_ahash *tfm; | 
 | +	struct scatterlist sg; | 
 | +	char vmif[1024]; | 
 | +	int ret; | 
 | + | 
 | +	strcpy (vmif, umid); | 
 | +	strcat (vmif, ifname); | 
 | + | 
 | +	tfm = crypto_alloc_ahash("sha1", 0, CRYPTO_ALG_ASYNC); | 
 | +	if (IS_ERR(tfm)) | 
 | +		return -ENOMEM; | 
 | + | 
 | +	desc = ahash_request_alloc(tfm, GFP_KERNEL); | 
 | +	if (!desc) { | 
 | +		ret = -ENOMEM; | 
 | +		goto out; | 
 | +	} | 
 | + | 
 | +	crypto_ahash_clear_flags(tfm, ~0); | 
 | + | 
 | +	sg_init_table(&sg, 1); | 
 | +	sg_set_buf(&sg, vmif, strlen(vmif)); | 
 | + | 
 | +	ahash_request_set_crypt(desc, &sg, hash, strlen(vmif)); | 
 | + | 
 | +	ret = crypto_ahash_digest(desc); | 
 | +out: | 
 | +	crypto_free_ahash(tfm); | 
 | + | 
 | +	return ret; | 
 | +} | 
 | + | 
 | +#endif | 
 | + | 
 |  void uml_net_setup_etheraddr(struct net_device *dev, char *str) | 
 |  { | 
 |  	unsigned char *addr = dev->dev_addr; | 
 | +	u8 hash[SHA1_DIGEST_SIZE]; | 
 |  	char *end; | 
 |  	int i; | 
 |   | 
 | @@ -331,9 +381,26 @@ void uml_net_setup_etheraddr(struct net_ | 
 |  	return; | 
 |   | 
 |  random: | 
 | +#ifndef CONFIG_UML_NET_DETERMINISTIC_MAC | 
 |  	printk(KERN_INFO | 
 |  	       "Choosing a random ethernet address for device %s\n", dev->name); | 
 |  	eth_hw_addr_random(dev); | 
 | +#else | 
 | +	printk(KERN_INFO | 
 | +	       "Computing a digest to use as ethernet address for device %s\n", dev->name); | 
 | +	if (compute_hash(get_umid(), dev->name, hash) < 0) { | 
 | +		printk(KERN_WARNING | 
 | +		       "Could not compute digest to use as ethernet address for device %s. " | 
 | +		       "Using random address instead.\n", dev->name); | 
 | +		random_ether_addr(addr); | 
 | +	} | 
 | +	else { | 
 | +		for (i=0; i < 6; i++) | 
 | +			addr[i] = (hash[i] + hash[i+6]) % 0x100; | 
 | +	} | 
 | +	addr [0] &= 0xfe; /* clear multicast bit */ | 
 | +	addr [0] |= 0x02; /* set local assignment bit (IEEE802) */ | 
 | +#endif | 
 |  } | 
 |   | 
 |  static DEFINE_SPINLOCK(devices_lock); |