This change introduce mac address templating.

By setting lxc.network.hwaddr to something like fe:xx:xx:xx:xx:xx each
"x" will be replaced by a random value.  If less significant bit of
first byte is "templated", it will be set to 0.

This change introduce also a common randinit() function that could be
used to initialize random generator.

Signed-off-by: gza <lxc@zitta.fr>
Acked-by: Serge Hallyn <serge.hallyn@ubuntu.com>
This commit is contained in:
Serge Hallyn 2014-01-13 10:02:29 -06:00
parent bf3e09c00e
commit 508c263ee6
4 changed files with 77 additions and 3 deletions

View File

@ -361,6 +361,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
default to the virtual interface, but in some cases, default to the virtual interface, but in some cases,
this is needed to resolve a mac address conflict or to this is needed to resolve a mac address conflict or to
always have the same link-local ipv6 address always have the same link-local ipv6 address
always have the same link-local ipv6 address.
Any "x" in address will be replaced by random value,
this allows setting hwaddr templates.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -510,6 +510,37 @@ static int macvlan_mode(int *valuep, const char *value)
return -1; return -1;
} }
static int rand_complete_hwaddr(char *hwaddr)
{
const char hex[] = "0123456789abcdef";
char *curs = hwaddr;
#ifndef HAVE_RAND_R
randseed(true);
#else
unsigned int seed=randseed(false);
#endif
while (*curs != '\0')
{
if ( *curs == 'x' || *curs == 'X' ) {
if (curs - hwaddr == 1) {
//ensure address is unicast
#ifdef HAVE_RAND_R
*curs = hex[rand_r(&seed) & 0x0E];
} else {
*curs = hex[rand_r(&seed) & 0x0F];
#else
*curs = hex[rand() & 0x0E];
} else {
*curs = hex[rand() & 0x0F];
#endif
}
}
curs++;
}
return 0;
}
static int config_network_flags(const char *key, const char *value, static int config_network_flags(const char *key, const char *value,
struct lxc_conf *lxc_conf) struct lxc_conf *lxc_conf)
{ {
@ -577,11 +608,27 @@ static int config_network_hwaddr(const char *key, const char *value,
{ {
struct lxc_netdev *netdev; struct lxc_netdev *netdev;
netdev = network_netdev(key, value, &lxc_conf->network); char *new_value = strdup(value);
if (!netdev) if (!new_value) {
SYSERROR("failed to strdup '%s': %m", value);
return -1; return -1;
}
rand_complete_hwaddr(new_value);
return config_string_item(&netdev->hwaddr, value); netdev = network_netdev(key, new_value, &lxc_conf->network);
if (!netdev) {
free(new_value);
return -1;
};
if (!new_value || strlen(new_value) == 0) {
free(new_value);
netdev->hwaddr = NULL;
return 0;
}
netdev->hwaddr = new_value;
return 0;
} }
static int config_network_vlan_id(const char *key, const char *value, static int config_network_vlan_id(const char *key, const char *value,

View File

@ -1084,3 +1084,25 @@ void **lxc_append_null_to_array(void **array, size_t count)
} }
return array; return array;
} }
int randseed(bool srand_it)
{
/*
srand pre-seed function based on /dev/urandom
*/
unsigned int seed=time(NULL)+getpid();
FILE *f;
f = fopen("/dev/urandom", "r");
if (f) {
int ret = fread(&seed, sizeof(seed), 1, f);
if (ret != 1)
DEBUG("unable to fread /dev/urandom, %s, fallback to time+pid rand seed", strerror(errno));
fclose(f);
}
if (srand_it)
srand(seed);
return seed;
}

View File

@ -257,5 +257,7 @@ extern void lxc_free_array(void **array, lxc_free_fn element_free_fn);
extern size_t lxc_array_len(void **array); extern size_t lxc_array_len(void **array);
extern void **lxc_append_null_to_array(void **array, size_t count); extern void **lxc_append_null_to_array(void **array, size_t count);
//initialize rand with urandom
extern int randseed(bool);
#endif #endif