Unverified Commit dc3d3d4e authored by Francesc Guasch's avatar Francesc Guasch Committed by GitHub
Browse files

Fix duplicated mac (#1295)

fix(KVM): unique MAC in all network cards

alwo test(KVM): check for duplicated MACs in 2nd eth

fixes issue #1294
parent 23a1989c
......@@ -2489,6 +2489,7 @@ sub _execute {
die "I can't fork" if !defined $pid;
if ( $pid == 0 ) {
srand();
$self->_do_execute_command($sub, $request);
exit;
}
......
......@@ -1963,7 +1963,7 @@ sub _set_controller_network($self, $number, $data) {
my $pci_slot = $self->_new_pci_slot();
my $device = "<interface type='network'>
<mac address='52:54:00:a7:49:71'/>
<mac address='".$self->_vm->_new_mac()."'/>
<source network='default'/>
<model type='$driver'/>
<address type='pci' domain='0x0000' bus='0x00' slot='$pci_slot' function='0x0'/>
......
......@@ -64,6 +64,7 @@ $DIR_XML = "/var/lib/ravada/xml/" if $0 =~ m{^/usr/sbin};
our $FILE_CONFIG_QEMU = "/etc/libvirt/qemu.conf";
our $XML = XML::LibXML->new();
our %USED_MAC;
#-----------
#
......@@ -2041,52 +2042,55 @@ sub _new_uuid {
}
sub _xml_modify_mac {
my $self = shift;
my $doc = shift or confess "Missing XML doc";
my @old_macs;
sub _read_used_macs($self) {
return if keys %USED_MAC;
for my $dom ($self->vm->list_all_domains) {
my $doc;
eval { $doc = $XML->load_xml(string => $dom->get_xml_description()) } ;
next if !$doc;
for my $nic ( $doc->findnodes('/domain/devices/interface/mac')) {
my $nic_mac = $nic->getAttribute('address');
push @old_macs,($nic_mac);
my $nic_mac = lc($nic->getAttribute('address'));
$USED_MAC{$nic_mac}++;
}
}
}
for my $if_mac ($doc->findnodes('/domain/devices/interface/mac') ) {
my $mac = $if_mac->getAttribute('address');
my @macparts0 = split/:/,$mac;
sub _new_mac($self,$mac='52:54:00:a7:49:71') {
my $new_mac;
$self->_read_used_macs();
my @macparts = split/:/,$mac;
$macparts[5] = sprintf"%02X",($$ % 254);
my @tried;
my $foundit;
for ( 1 .. 1000 ) {
for my $cont ( 1 .. 1000 ) {
my @macparts = @macparts0;
my $pos = int(rand(scalar(@macparts)-3))+3;
my @tried;
my $foundit;
for ( 1 .. 1000 ) {
my $pos = int(rand(scalar(@macparts)-3))+3;
for ( 0 .. 2 ) {
my $num =sprintf "%02X", rand(0xff);
die "Missing num " if !defined $num;
$macparts[$pos] = $num;
$new_mac = lc(join(":",@macparts));
push @tried,($new_mac);
last if !grep /^$new_mac$/i,@old_macs && $self->_unique_mac($new_mac);
push @old_macs,($new_mac);
$pos++;
$pos = 3 if $pos>5;
}
my $new_mac = lc(join(":",@macparts));
push @tried,($new_mac);
if ( $self->_unique_mac($new_mac) ) {
$if_mac->setAttribute(address => $new_mac);
$foundit = 1;
last;
}
}
die "I can't find a new unique mac '$new_mac'\n".Dumper(\@tried) if !$foundit;
return $new_mac if !$USED_MAC{$new_mac}++ && $self->_unique_mac($new_mac);
}
die "I can't find a new unique mac\n".Dumper(\@tried) if !$foundit;
}
sub _xml_modify_mac {
my $self = shift;
my $doc = shift or confess "Missing XML doc";
for my $if_mac ($doc->findnodes('/domain/devices/interface/mac') ) {
my $mac = $if_mac->getAttribute('address');
my $new_mac = $self->_new_mac($mac);;
$if_mac->setAttribute(address => $new_mac);
}
}
......
......@@ -72,16 +72,8 @@ sub test_req_prepare_base{
$domain->is_public(1);
}
sub test_add_nic {
my $vm_name = shift;
# diag("Testing add description $vm_name");
my $vm = rvd_back->search_vm($vm_name);
my $domain = test_create_domain($vm_name);
#Read xml
sub read_mac{
#Read xml
sub read_mac{
my $domain = shift;
my $xml = XML::LibXML->load_xml(string => $domain->get_xml_base());
my @mac;
......@@ -91,7 +83,15 @@ sub test_add_nic {
push @mac, $mac;
}
return(@mac);
}
}
sub test_add_nic {
my $vm_name = shift;
# diag("Testing add description $vm_name");
my $vm = rvd_back->search_vm($vm_name);
my $domain = test_create_domain($vm_name);
my $domain_other = test_create_domain($vm_name);
#Prepare base
test_req_prepare_base($domain->name);
......@@ -112,10 +112,15 @@ sub test_add_nic {
my $domain_clon = $RAVADA->search_domain($name);
my @mac = read_mac($domain);
my @mac_other = read_mac($domain_other);
my @mac2 = read_mac($domain_clon);
isnt($mac[0],$mac2[0], "1st MAC from 1st NIC cloned are the same");
isnt($mac[1],$mac2[1], "2nd MAC from 2nd NIC cloned are the same");
my %dupe_mac = ();
for my $mac (@mac, @mac_other, @mac2) {
ok(!$dupe_mac{$mac}++,"MAC $mac duplicated");
}
}
......
......@@ -98,6 +98,7 @@ sub test_many_clones($base) {
};
test_re_expose($base) if $base->type eq 'Void';
test_different_mac($base, $base->clones) if $base->type ne 'Void';
for my $clone ( $base->clones ) {
my $req = Ravada::Request->remove_domain(
name => $clone->{name}
......@@ -106,6 +107,22 @@ sub test_many_clones($base) {
}
}
sub test_different_mac(@domain) {
my %found;
for my $domain (@domain) {
$domain = Ravada::Front::Domain->open($domain->{id})
if ref($domain) !~/^Ravada/;
my $xml = XML::LibXML->load_xml(string => $domain->_data_extra('xml'));
my (@if_mac) = $xml->findnodes('/domain/devices/interface/mac');
for my $if_mac (@if_mac) {
my $mac = $if_mac->getAttribute('address');
ok(!exists $found{$mac},"Error: MAC $mac from ".$domain->name
." also in domain : ".($found{$mac} or '')) or exit;
$found{$mac} = $domain->name;
}
}
}
sub test_re_expose($base) {
diag("Test re-expose");
for my $clone ( $base->clones ) {
......@@ -196,6 +213,9 @@ for my $vm_name ( vm_names() ) {
ok($base) or next;
push @bases,($base->name);
mojo_request($t, "add_hardware", { id_domain => $base->id, name => 'network' });
wait_request(debug => 1, check_error => 1, background => 1, timeout => 120);
$t->get_ok("/machine/prepare/".$base->id.".json")->status_is(200);
_wait_request(debug => 0, background => 1);
$base = rvd_front->search_domain($name);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment