[libvirt] [PATCH] nwfilter: extend schema + add testcase w/ connlimit-above test
by Stefan Berger
I am extending the schema with the recently added connlimit-above
attribute and adding a test case to the test suite.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
docs/schemas/nwfilter.rng | 5 +++++
tests/nwfilterxml2xmlin/conntrack-test.xml | 14 ++++++++++++++
tests/nwfilterxml2xmlout/conntrack-test.xml | 12 ++++++++++++
tests/nwfilterxml2xmltest.c | 2 ++
4 files changed, 33 insertions(+)
Index: libvirt-acl/docs/schemas/nwfilter.rng
===================================================================
--- libvirt-acl.orig/docs/schemas/nwfilter.rng
+++ libvirt-acl/docs/schemas/nwfilter.rng
@@ -387,6 +387,11 @@
<ref name="sixbitrange"/>
</attribute>
</optional>
+ <optional>
+ <attribute name="connlimit-above">
+ <ref name="uint16range"/>
+ </attribute>
+ </optional>
</interleave>
</define>
Index: libvirt-acl/tests/nwfilterxml2xmlin/conntrack-test.xml
===================================================================
--- /dev/null
+++ libvirt-acl/tests/nwfilterxml2xmlin/conntrack-test.xml
@@ -0,0 +1,14 @@
+<filter name='testcase' chain='root'>
+ <uuid>0a5288ea-612c-834a-6bbf-82a03a1a3244</uuid>
+ <rule action='drop' direction='out' priority='500'>
+ <icmp connlimit-above='1'/>
+ </rule>
+ <rule action='drop' direction='out' priority='500'>
+ <tcp connlimit-above='2'/>
+ </rule>
+ <rule action='accept' direction='out' priority='500'>
+ <all/>
+ </rule>
+</filter>
+
+
Index: libvirt-acl/tests/nwfilterxml2xmlout/conntrack-test.xml
===================================================================
--- /dev/null
+++ libvirt-acl/tests/nwfilterxml2xmlout/conntrack-test.xml
@@ -0,0 +1,12 @@
+<filter name='testcase' chain='root'>
+ <uuid>0a5288ea-612c-834a-6bbf-82a03a1a3244</uuid>
+ <rule action='drop' direction='out' priority='500'>
+ <icmp connlimit-above='1'/>
+ </rule>
+ <rule action='drop' direction='out' priority='500'>
+ <tcp connlimit-above='2'/>
+ </rule>
+ <rule action='accept' direction='out' priority='500'>
+ <all/>
+ </rule>
+</filter>
Index: libvirt-acl/tests/nwfilterxml2xmltest.c
===================================================================
--- libvirt-acl.orig/tests/nwfilterxml2xmltest.c
+++ libvirt-acl/tests/nwfilterxml2xmltest.c
@@ -119,6 +119,8 @@ mymain(int argc, char **argv)
DO_TEST("icmp-direction2-test");
DO_TEST("icmp-direction3-test");
+ DO_TEST("conntrack-test");
+
return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
}
14 years, 7 months
[libvirt] [RFC] libvirt-TCK scripts to verify spoofing prevention
by Gerhard Stenzel
The following patch mainly adds a set of test case to verify that
several spoofing attacks are prevented by the nwfilter subsystem.
In order to have a well defined test machine, the patch also includes
test scripts to network install a virtual disk from scratch, to boot the
virtual test machine prior to running the actual test scripts and to
shut it down afterwards.
While I have tried to remove as much dependency on my local setup as
possible there is still some left, so I am currently more interested in
feedback about the general approach, not necessarily actual inclusion
into the libvirt-TCK git.
For example, I am currently trying to find a suitable location for the
kickstart file, and also a suitable place for the common_functions.pl.
Comments are appreciated ... thanks,
Gerhard
Index: libvirt-tck/scripts/network/README
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/README
@@ -0,0 +1,14 @@
+
+Test cases:
+
+000-install-image.t creates and install a 2GB fedora virtual disk via
kickstart file from the network
+001-boot-image.t defines and boots a VM which uses the fedora virtual
disk
+100-ping-still-working.t verifies the VM is pingable
+210-no-mac-spoofing.t verifies mac spoofing is prevented
+220-no-ip-spoofing.t verifies ip spoofing is prevented
+230-no-mac-broadcast.t verifies mac broadcasting is prevented
+240-no-arp-spoofing.t verifies arp spoofing is prevented
+999-shutdown-image.t shuts the VM down
+
+
+
Index: libvirt-tck/scripts/network/000-install-image.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/000-install-image.t
@@ -0,0 +1,181 @@
+# -*- perl -*-
+#
+# Copyright (C) 2010 IBM Corp.
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+network/000-install-image.t - install network test image
+
+=head1 DESCRIPTION
+
+The test case creates and install a 2GB fedora virtual
+disk via kickstart file from the network.
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 1;
+
+use Sys::Virt::TCK;
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END { $tck->cleanup if $tck; }
+
+# variables which may need to be adapted
+my $domain_name ="f12nwtest";
+my $disk_name = "/var/lib/libvirt/images/${domain_name}.img";
+my $disk_size = "2147483648";
+
+my $kickstart_file ="http://192.168.122.1/ks.cfg";
+my $cmdline = "ip=dhcp gateway=192.168.122.1 ks=${kickstart_file}";
+
+# see if the domain already exits
+my $already_defined = 0;
+diag "searching if ${domain_name} is already defined";
+my $nnames = $conn->num_of_defined_domains();
+my @names = $conn->list_defined_domain_names($nnames);
+foreach (@names){
+ if (/${domain_name}/) {
+ print "$_ already exists, no need to redefine\n";
+ $already_defined = 1;
+ }
+}
+diag $already_defined;
+
+# check for installation disk and build it if not exists
+my $already_installed = 0;
+my $pool = $conn->get_storage_pool_by_name("default");
+my $nnames = $pool->num_of_storage_volumes();
+my @volNames = $pool->list_storage_vol_names($nnames);
+foreach (@volNames){
+ if (/${domain_name}/) {
+ print "$_ already exists, no need to install\n";
+ $already_installed = 1;
+ }
+}
+
+my $volumexml = "<volume>".
+" <name>${domain_name}.img</name>".
+" <key>${disk_name}</key>".
+" <source>".
+" </source>".
+" <capacity>${disk_size}</capacity>".
+" <allocation>4096</allocation>".
+" <target>".
+" <path>${disk_name}</path>".
+" <format type='raw'/>".
+" <permissions>".
+" <mode>0644</mode>".
+" <owner>0</owner>".
+" <group>0</group>".
+" </permissions>".
+" </target>".
+"</volume>";
+
+
+# prepare image
+if ($already_installed == 0) {
+ diag "Creating ${disk_name}";
+ diag $volumexml;
+ my $vol = $pool->create_volume($volumexml)
+# system("qemu-img create ${disk_name} ${disk_size}");
+}
+
+my $topxml = " <name>${domain_name}</name>".
+" <memory>524288</memory>".
+" <currentMemory>524288</currentMemory>".
+" <vcpu>1</vcpu>";
+
+my $osxml = " <os>".
+" <type arch='x86_64' machine='fedora-13'>hvm</type>".
+" <kernel>/var/cache/libvirt-tck/os-i686-hvm/vmlinuz</kernel>".
+" <initrd>/var/cache/libvirt-tck/os-i686-hvm/initrd</initrd>".
+" <cmdline>${cmdline}</cmdline>".
+" <boot dev='hd'/>".
+" </os>";
+
+my $bottomxml = " <features>".
+" <acpi/>".
+" <apic/>".
+" </features>".
+" <clock offset='utc'/>".
+" <on_poweroff>destroy</on_poweroff>".
+" <on_reboot>restart</on_reboot>".
+" <on_crash>restart</on_crash>".
+" <devices>".
+" <emulator>/usr/bin/qemu-kvm</emulator>".
+" <disk type='file' device='disk'>".
+" <driver name='qemu' type='raw'/>".
+" <source file='${disk_name}'/>".
+" <target dev='hda' bus='ide'/>".
+" </disk>".
+" <controller type='ide' index='0'>".
+" </controller>".
+" <interface type='network'>".
+" <source network='default'/>".
+" <target dev='vnet0'/>".
+" <model type='virtio'/>".
+" </interface>".
+" <serial type='pty'>".
+" <target port='0'/>".
+" </serial>".
+" <console type='pty'>".
+" <target port='0'/>".
+" </console>".
+" <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'
keymap='de'/>".
+" <video>".
+" <model type='cirrus' vram='9216' heads='1'/>".
+" </video>".
+" </devices>";
+
+my $xml = "<domain type='kvm'>" .
+$topxml.
+$osxml.
+$bottomxml.
+"</domain>";
+
+diag $xml;
+diag "Defining an inactive domain config";
+my $dom;
+
+# no need to start if already installed
+if (($already_installed == 0) && ($already_defined == 0)) {
+ ok_domain(sub { $dom = $conn->define_domain($xml) }, "defined
persistent domain config");
+ $xml = $dom->get_xml_description;
+ diag $xml;
+ diag "Starting inactive domain config";
+ $dom->create;
+
+ # wait for completion of installation
+ diag "wait for installation to finish .. ";
+ while($dom->is_active()) {
+ sleep(10);
+ diag ".. to view progress connect to virtual machine ${domain_name} ..
";
+ }
+ sleep(10);
+ diag " .. done";
+ # cleanup
+ $dom->undefine;
+} else {
+ ok_domain { $dom = $conn->get_domain_by_name($domain_name) } "the
existing domain object";
+}
+
+
+
+
+
Index: libvirt-tck/scripts/network/001-boot-image.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/001-boot-image.t
@@ -0,0 +1,133 @@
+# -*- perl -*-
+#
+# Copyright (C) 2010 IBM Corp.
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+network/001-boot-image.t - boot installed test image
+
+=head1 DESCRIPTION
+
+The test case defines and boots a VM which uses the
+fedora virtual disk create ny 000-install-image
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 2;
+
+use Sys::Virt::TCK;
+use XML::LibXML;
+
+require 'scripts/network/common_functions.pl';
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END { $tck->cleanup if $tck; }
+
+my $already_defined = 0;
+my $domain_name ="f12nwtest";
+
+# see if the domain already exits
+diag "searching if ${domain_name} is already defined";
+my $nnames = $conn->num_of_defined_domains();
+my @names = $conn->list_defined_domain_names($nnames);
+foreach (@names){
+ if (/${domain_name}/) {
+ print "$_ already exists, no need to redefine\n";
+ $already_defined = 1;
+ }
+}
+diag $already_defined;
+
+my $dom;
+my $xml;
+
+if ($already_defined == 1) {
+ ok_domain { $dom = $conn->get_domain_by_name($domain_name) } "the
existing domain object";
+} else {
+ my $topxml = " <name>${domain_name}</name>".
+ " <memory>524288</memory>".
+ " <currentMemory>524288</currentMemory>".
+ " <vcpu>1</vcpu>";
+
+ my $osxml = " <os>".
+ " <type arch='x86_64' machine='fedora-13'>hvm</type>".
+ " <boot dev='hd'/>".
+ " </os>";
+
+ my $bottomxml = " <features>".
+ " <acpi/>".
+ " <apic/>".
+ " </features>".
+ " <clock offset='utc'/>".
+ " <on_poweroff>destroy</on_poweroff>".
+ " <on_reboot>restart</on_reboot>".
+ " <on_crash>restart</on_crash>".
+ " <devices>".
+ " <emulator>/usr/bin/qemu-kvm</emulator>".
+ " <disk type='file' device='disk'>".
+ " <driver name='qemu' type='raw'/>".
+ " <source file='/var/lib/libvirt/images/${domain_name}.img'/>".
+ " <target dev='hda' bus='ide'/>".
+ " </disk>".
+ " <controller type='ide' index='0'>".
+ " </controller>".
+ " <interface type='network'>".
+ " <source network='default'/>".
+ " <filterref filter='no-spoofing'/>".
+ " <target dev='vnet0'/>".
+ " <model type='virtio'/>".
+ " </interface>".
+ " <serial type='pty'>".
+ " <target port='0'/>".
+ " </serial>".
+ " <console type='pty'>".
+ " <target port='0'/>".
+ " </console>".
+ " <graphics type='vnc' port='-1' autoport='yes' listen='127.0.0.1'
keymap='de'/>".
+ " <video>".
+ " <model type='cirrus' vram='9216' heads='1'/>".
+ " </video>".
+ " </devices>";
+
+ $xml = "<domain type='kvm'>" .
+ $topxml.
+ $osxml.
+ $bottomxml.
+ "</domain>";
+
+ diag $xml;
+ diag "Defining an inactive domain config";
+ ok_domain(sub { $dom = $conn->define_domain($xml) }, "defined
persistent domain config");
+}
+
+# already existing or newly defined, start it up
+$dom->create;
+my $uuid = $dom->get_uuid_string();
+diag $uuid;
+$xml = $dom->get_xml_description();
+diag $xml;
+ok($dom->get_id() > 0, "running domain has an ID > 0");
+
+my $mac = get_macaddress($xml);
+diag $mac;
+# wait for guest to boot and request dhcp
+sleep(20);
+my $ip = get_ip_from_leases($mac);
+diag "ip is $ip";
+
Index: libvirt-tck/scripts/network/100-ping-still-working.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/100-ping-still-working.t
@@ -0,0 +1,71 @@
+# -*- perl -*-
+#
+# Copyright (C) 2010 IBM Corp.
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+network/100-ping-still-working.t - verify machines can be pinged from
host
+
+=head1 DESCRIPTION
+
+The test case validates that it is possible to ping a guest machine
from
+the host.
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+
+use Sys::Virt::TCK;
+use Test::Exception;
+use Net::SSH::Perl;
+use XML::LibXML;
+
+require 'scripts/network/common_functions.pl';
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END {
+ $tck->cleanup if $tck;
+}
+
+# create first domain and start it
+diag "Trying domain lookup by name";
+my $dom1;
+my $domain_name ="f12nwtest";
+
+ok_domain { $dom1 = $conn->get_domain_by_name($domain_name) } "the
running domain object";
+my $xml = $dom1->get_xml_description;
+diag $xml;
+ok($dom1->get_id() > 0, "running domain has an ID > 0");
+my $mac1 = get_macaddress($xml);
+diag $mac1;
+my $guestip1 = get_ip_from_leases($mac1);
+diag "ip is $guestip1";
+
+# check ebtables entry
+my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`;
+diag $ebtable1;
+# fixme to include mac adress
+ok($ebtable1 =~ "vnet0", "check ebtables entry");
+
+# ping guest1
+my $ping1 = `ping -c 10 $guestip1`;
+diag $ping1;
+ok($ping1 =~ "10 received", "ping $guestip1 test");
+
+exit 0;
Index: libvirt-tck/scripts/network/210-no-mac-spoofing.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/210-no-mac-spoofing.t
@@ -0,0 +1,113 @@
+# -*- perl -*-
+#
+# Copyright (C) 2010 IBM Corp.
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+network/210-no-mac-spoofing.t - verify MAC spoofing is prevented
+
+=head1 DESCRIPTION
+
+The test case validates that MAC spoofing is prevented
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 5;
+
+use Sys::Virt::TCK;
+use Test::Exception;
+use Net::SSH::Perl;
+use XML::LibXML;
+
+require 'scripts/network/common_functions.pl';
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END {
+ $tck->cleanup if $tck;
+}
+
+# create first domain and start it
+diag "Trying domain lookup by name";
+my $domain_name ="f12nwtest";
+my $dom1;
+ok_domain { $dom1 = $conn->get_domain_by_name($domain_name) } "the
running domain object";
+ok($dom1->get_id() > 0, "running domain has an ID > 0");
+my $xml = $dom1->get_xml_description;
+diag $xml;
+
+# check ebtables entry
+my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`;
+diag $ebtable1;
+# fixme to include mac adress
+ok($ebtable1 =~ "vnet0", "check ebtables entry");
+
+# wait for guest to boot
+diag "waiting for guests to boot";
+#system("sleep 20");
+diag "done";
+
+# ping guest1 first nic
+my $mac1 = get_macaddress($xml);
+diag "$mac1";
+my $guestip1 = get_ip_from_leases($mac1);
+diag "ip is $guestip1";
+my $gateway = "192.168.122.1";
+my $macfalse = "52:54:00:f9:21:22";
+my $ping1 = `ping -c 10 $guestip1`;
+diag $ping1;
+ok($ping1 =~ "10 received", "ping $guestip1 test");
+
+# log into guest
+my $ssh = Net::SSH::Perl->new($guestip1);
+$ssh->login("root", "foobar");
+
+# now bring eth0 down, change MAC and bring it up again
+diag "fiddling with mac";
+my $cmdfile = "echo '" .
+ "/sbin/ifconfig eth0\n".
+ "/sbin/ifconfig eth0 down\n".
+ "/sbin/ifconfig eth0 hw ether ${macfalse}\n".
+ "/sbin/ifconfig eth0 up\n".
+ "/sbin/ifconfig eth0\n".
+ "ping -c 10 ${gateway}\n".
+ "/sbin/ifconfig eth0 down\n".
+ "/sbin/ifconfig eth0 hw ether ${mac1}\n".
+ "/sbin/ifconfig eth0 up\n".
+ "/sbin/ifconfig eth0\n".
+ "' > /test.sh";
+diag $cmdfile;
+my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile);
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("chmod +x /test.sh");
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("/test.sh > /test.log");
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("cat /test.log");
+diag $stdout;
+diag $stderr;
+diag $exit;
+ok($stdout =~ "100% packet loss", "packet loss expected");
+
+exit 0;
Index: libvirt-tck/scripts/network/230-no-mac-broadcast.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/230-no-mac-broadcast.t
@@ -0,0 +1,102 @@
+# -*- perl -*-
+#
+# Copyright (C) 2010 IBM Corp.
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+network/230-no-mac-broadcast.t - verify MAC broadcasts are prevented
+
+=head1 DESCRIPTION
+
+The test case validates that MAC broadcasts are prevented
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+
+use Sys::Virt::TCK;
+use Test::Exception;
+use Net::SSH::Perl;
+use XML::LibXML;
+
+require 'scripts/network/common_functions.pl';
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END {
+ $tck->cleanup if $tck;
+}
+
+# create first domain and start it
+diag "Trying domain lookup by name";
+my $dom1;
+ok_domain { $dom1 = $conn->get_domain_by_name("f12nwtest") } "the
running domain object";
+
+ok($dom1->get_id() > 0, "running domain has an ID > 0");
+my $xml = $dom1->get_xml_description;
+diag $xml;
+my $mac1 = get_macaddress($xml);
+diag "$mac1";
+my $guestip1 = get_ip_from_leases($mac1);
+diag "ip is $guestip1";
+
+# check ebtables entry
+my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`;
+diag $ebtable1;
+# fixme to include mac adress
+ok($ebtable1 =~ "vnet0", "check ebtables entry");
+
+# prepare tcpdump
+diag "prepare tcpdump";
+system("/usr/sbin/tcpdump -v -i virbr0 -n host 255.255.255.255
2> /tmp/tcpdump.log &");
+
+# log into guest
+my $ssh = Net::SSH::Perl->new($guestip1);
+$ssh->login("root", "foobar");
+
+# now generate a mac broadcast paket
+diag "generate mac broadcast";
+my $cmdfile = "echo '" .
+ "/bin/ping -c 1 192.168.122.255 -b\n".
+ "' > /test.sh";
+diag $cmdfile;
+my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile);
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("chmod +x /test.sh");
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("/test.sh > /test.log");
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("cat /test.log");
+diag $stdout;
+diag $stderr;
+diag $exit;
+
+# now stop tcpdump and verify result
+diag "stopping tcpdump";
+system("kill -15 `/sbin/pidof tcpdump`");
+my $tcpdumplog = `cat /tmp/tcpdump.log`;
+diag($tcpdumplog);
+ok($tcpdumplog =~ "0 packets captured", "tcpdump expected to capture no
packets");
+
+exit 0;
Index: libvirt-tck/scripts/network/240-no-arp-spoofing.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/240-no-arp-spoofing.t
@@ -0,0 +1,111 @@
+# -*- perl -*-
+#
+# Copyright (C) 2010 IBM Corp.
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+network/240-no-arp-spoofing.t - verify ARP spoofing is prevented
+
+=head1 DESCRIPTION
+
+The test case validates that ARP spoofing is prevented
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+
+use Sys::Virt::TCK;
+use Test::Exception;
+use Net::SSH::Perl;
+use XML::LibXML;
+
+require 'scripts/network/common_functions.pl';
+
+my $spoofid = "192.168.122.183";
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END {
+ $tck->cleanup if $tck;
+}
+
+# looking up domain
+diag "Trying domain lookup by name";
+my $dom1;
+my $domain_name ="f12nwtest";
+ok_domain { $dom1 = $conn->get_domain_by_name($domain_name) } "the
running domain object";
+ok($dom1->get_id() > 0, "running domain has an ID > 0");
+my $xml = $dom1->get_xml_description;
+diag $xml;
+my $mac1 = get_macaddress($xml);
+diag "$mac1";
+my $guestip1 = get_ip_from_leases($mac1);
+diag "ip is $guestip1";
+
+# check ebtables entry
+my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`;
+diag $ebtable1;
+# check if mac address is listed
+ok($ebtable1 =~ "$guestip1", "check ebtables entry");
+
+# prepare tcpdump
+diag "prepare tcpdump";
+system("/usr/sbin/tcpdump -v -i virbr0 not ip > /tmp/tcpdump.log &");
+
+# log into guest
+my $ssh = Net::SSH::Perl->new($guestip1);
+$ssh->login("root", "foobar");
+
+# now generate a arp spoofing packets
+diag "generate arpspoof";
+my $cmdfile = "echo '" .
+ "/usr/bin/yum -y install dsniff\n".
+ "/usr/sbin/arpspoof ${spoofid} &\n".
+ "/bin/sleep 10\n".
+ "kill -15 `/sbin/pidof arpspoof`\n".
+ "' > /test.sh";
+diag "content of cmdfile:";
+diag $cmdfile;
+diag "creating cmdfile";
+my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile);
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("chmod +x /test.sh");
+diag $stdout;
+diag $stderr;
+diag $exit;
+diag "excuting cmdfile";
+($stdout, $stderr, $exit) = $ssh->cmd("/test.sh > /test.log");
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("echo test.log\ncat /test.log");
+diag $stdout;
+diag $stderr;
+diag $exit;
+
+# now stop tcpdump and verify result
+diag "stopping tcpdump";
+system("kill -15 `/sbin/pidof tcpdump`");
+diag "tcpdump.log:";
+my $tcpdumplog = `cat /tmp/tcpdump.log`;
+diag($tcpdumplog);
+ok($tcpdumplog !~ "${spoofid} is-at", "tcpdump expected to capture no
arp reply packets");
+
+exit 0;
Index: libvirt-tck/scripts/network/220-no-ip-spoofing.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/220-no-ip-spoofing.t
@@ -0,0 +1,101 @@
+# -*- perl -*-
+#
+# Copyright (C) 2010 IBM Corp.
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+network/220-no-ip-spoofing.t - verify IP spoofing is prevented
+
+=head1 DESCRIPTION
+
+The test case validates that IP spoofing is prevented
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 4;
+
+use Sys::Virt::TCK;
+use Test::Exception;
+use Net::SSH::Perl;
+use XML::LibXML;
+
+require 'scripts/network/common_functions.pl';
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END {
+ $tck->cleanup if $tck;
+}
+
+# looking up domain
+diag "Trying domain lookup by name";
+my $dom1;
+my $domain_name ="f12nwtest";
+
+ok_domain { $dom1 = $conn->get_domain_by_name($domain_name) } "the
running domain object";
+ok($dom1->get_id() > 0, "running domain has an ID > 0");
+my $xml = $dom1->get_xml_description;
+diag $xml;
+my $mac1 = get_macaddress($xml);
+diag "$mac1";
+my $guestip1 = get_ip_from_leases($mac1);
+diag "ip is $guestip1";
+
+# check ebtables entry
+my $ebtable1 = `/sbin/ebtables -L;/sbin/ebtables -t nat -L`;
+diag $ebtable1;
+# check if IP address is listed
+ok($ebtable1 =~ "$guestip1", "check ebtables entry");
+
+# log into guest
+my $ssh = Net::SSH::Perl->new($guestip1);
+$ssh->login("root", "foobar");
+
+# now bring eth0 down, change IP and bring it up again
+diag "preparing ip spoof";
+my $cmdfile = "echo '" .
+ "/bin/sleep 1\n".
+ "/sbin/ifconfig eth0\n".
+ "/sbin/ifconfig eth0 down\n".
+ "/sbin/ifconfig eth0 192.168.122.183 netmask 255.255.255.0 up\n".
+ "/sbin/ifconfig eth0\n".
+ "/bin/sleep 1\n".
+ "/bin/ping -c 1 192.168.122.1\n".
+ "/sbin/ifconfig eth0 down\n".
+ "/sbin/ifconfig eth0 ${guestip1} netmask 255.255.255.0 up\n".
+ "/sbin/ifconfig eth0 \n".
+ "/bin/sleep 1\n".
+ "' > /test.sh";
+diag $cmdfile;
+my ($stdout, $stderr, $exit) = $ssh->cmd($cmdfile);
+diag $stdout;
+diag $stderr;
+diag $exit;
+($stdout, $stderr, $exit) = $ssh->cmd("chmod +x /test.sh");
+diag $stdout;
+diag $stderr;
+diag $exit;
+diag "running ip spoof";
+($stdout, $stderr, $exit) = $ssh->cmd("/test.sh");
+diag $stdout;
+diag $stderr;
+diag $exit;
+diag "checking result";
+ok($stdout =~ "100% packet loss", "packet loss expected");
+
+exit 0;
Index: libvirt-tck/scripts/network/999-shutdown-image.t
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/999-shutdown-image.t
@@ -0,0 +1,59 @@
+# -*- perl -*-
+#
+# Copyright (C) 2010 IBM Corp.
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+network/240-no-arp-spoofing.t - verify ARP spoofing is prevented
+
+=head1 DESCRIPTION
+
+The test case validates that ARP spoofing is prevented
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 2;
+
+use Sys::Virt::TCK;
+use Test::Exception;
+use Net::SSH::Perl;
+
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END {
+ $tck->cleanup if $tck;
+}
+
+# find domain
+my $domain_name = "f12nwtest";
+diag "Trying domain lookup by name";
+my $dom;
+ok_domain { $dom = $conn->get_domain_by_name($domain_name) } "the
running domain object";
+ok($dom->get_id() > 0, "running domain has an ID > 0");
+
+# cleanup guest
+diag "cleaning up";
+$dom->shutdown();
+ while($dom->is_active()) {
+ sleep(1);
+ diag ".. waiting for virtual machine ${domain_name} to shutdown.. ";
+ }
+#$dom->undefine();
+
+exit 0;
Index: libvirt-tck/scripts/network/common_functions.pl
===================================================================
--- /dev/null
+++ libvirt-tck/scripts/network/common_functions.pl
@@ -0,0 +1,35 @@
+use utf8;
+#no utf8;
+
+sub get_macaddress {
+ my $xmldesc = shift;
+
+ my $mac;
+ my $parser = XML::LibXML->new();
+
+ my $doc = $parser->parse_string($xmldesc);
+
+ my $rootel = $doc -> getDocumentElement();
+
+ my @devices = $rootel->getChildrenByTagName("devices");
+ foreach my $device(@devices) {
+ my @interfaces = $device->getChildrenByTagName("interface");
+ foreach my $interface(@interfaces) {
+ my @targets = $interface->getChildrenByTagName("mac");
+ foreach my $target(@targets) {
+ $mac = $target->getAttribute("address");
+ }
+ }
+ }
+ utf8::decode($mac);
+ return $mac;
+}
+
+sub get_ip_from_leases{
+ my $mac = shift;
+ my $tmp = `grep $mac /var/lib/dnsmasq/dnsmasq.leases`;
+ my @fields = split(/ /, $tmp);
+ my $ip = $fields[2];
+ return $ip;
+}
+1;
--
Best regards,
Gerhard Stenzel,
-----------------------------------------------------------------------------------------------------------------------------------
IBM Deutschland Research & Development GmbH
Vorsitzender des Aufsichtsrats: Martin Jetter
Geschäftsführung: Dirk Wittkopp
Sitz der Gesellschaft: Böblingen
Registergericht: Amtsgericht Stuttgart, HRB 243294
14 years, 7 months
[libvirt] [PATCH] Fix security context references in DAC code
by spencer@beyondabstraction.net
* The error messages coming from qemu's DAC support contain strings from the original SELinux security driver code. This just removes references to "security context" and other SELinux-isms from the DAC code.
Signed-off-by: Spencer Shimko <sshimko(a)tresys.com>
---
src/qemu/qemu_security_dac.c | 18 ++++++------------
1 files changed, 6 insertions(+), 12 deletions(-)
diff --git a/src/qemu/qemu_security_dac.c b/src/qemu/qemu_security_dac.c
index 1883fbe..e408dbf 100644
--- a/src/qemu/qemu_security_dac.c
+++ b/src/qemu/qemu_security_dac.c
@@ -37,7 +37,7 @@ void qemuSecurityDACSetDriver(struct qemud_driver *newdriver)
static int
qemuSecurityDACSetOwnership(const char *path, int uid, int gid)
{
- VIR_INFO("Setting DAC context on '%s' to '%d:%d'", path, uid, gid);
+ VIR_INFO("Setting DAC user and group on '%s' to '%d:%d'", path, uid, gid);
if (chown(path, uid, gid) < 0) {
struct stat sb;
@@ -51,24 +51,18 @@ qemuSecurityDACSetOwnership(const char *path, int uid, int gid)
}
}
- /* if the error complaint is related to an image hosted on
- * an nfs mount, or a usbfs/sysfs filesystem not supporting
- * labelling, then just ignore it & hope for the best.
- * The user hopefully set one of the necessary qemuSecurityDAC
- * virt_use_{nfs,usb,pci} boolean tunables to allow it...
- */
if (chown_errno == EOPNOTSUPP) {
- VIR_INFO("Setting security context '%d:%d' on '%s' not supported by filesystem",
+ VIR_INFO("Setting user and group to '%d:%d' on '%s' not supported by filesystem",
uid, gid, path);
} else if (chown_errno == EPERM) {
- VIR_INFO("Setting security context '%d:%d' on '%s' not permitted",
+ VIR_INFO("Setting user and group to '%d:%d' on '%s' not permitted",
uid, gid, path);
} else if (chown_errno == EROFS) {
- VIR_INFO("Setting security context '%d:%d' on '%s' not possible on readonly filesystem",
+ VIR_INFO("Setting user and group to '%d:%d' on '%s' not possible on readonly filesystem",
uid, gid, path);
} else {
virReportSystemError(chown_errno,
- _("unable to set security context '%d:%d' on '%s'"),
+ _("unable to set user and group to '%d:%d' on '%s'"),
uid, gid, path);
return -1;
}
@@ -84,7 +78,7 @@ qemuSecurityDACRestoreSecurityFileLabel(const char *path)
int err;
char *newpath = NULL;
- VIR_INFO("Restoring DAC context on '%s'", path);
+ VIR_INFO("Restoring DAC user and group on '%s'", path);
if ((err = virFileResolveLink(path, &newpath)) < 0) {
virReportSystemError(err,
--
1.6.6.1
14 years, 7 months
[libvirt] [PATCH] addrToString: give better error message
by Eric Blake
The user probably doesn't care what the gai error numbers are, as
much as what the failed conversion IP address was.
* src/remote/remote_driver.c (addrToString): Mention which address
could not be converted.
* daemon/remote.c (addrToString): Likewise.
---
In response to
https://www.redhat.com/archives/libvir-list/2010-April/msg00219.html
daemon/remote.c | 24 +++++++++++++++++-------
src/remote/remote_driver.c | 22 ++++++++++++++++------
2 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/daemon/remote.c b/daemon/remote.c
index 149176f..093e9c6 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -1,7 +1,7 @@
/*
* remote.c: handlers for RPC method calls
*
- * Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
+ * Copyright (C) 2007-2010 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -41,6 +41,7 @@
#include <string.h>
#include <errno.h>
#include <fnmatch.h>
+#include <arpa/inet.h>
#include "virterror_internal.h"
#if HAVE_POLKIT0
@@ -3169,21 +3170,30 @@ remoteDispatchAuthList (struct qemud_server *server,
#if HAVE_SASL
/*
- * NB, keep in sync with similar method in src/remote_internal.c
+ * NB, keep in sync with similar method in src/remote/remote_driver.c
*/
static char *addrToString(remote_error *rerr,
- struct sockaddr_storage *sa, socklen_t salen) {
+ struct sockaddr_storage *ss, socklen_t salen) {
char host[1024], port[20];
char *addr;
int err;
+ struct sockaddr *sa = (struct sockaddr *)ss;
- if ((err = getnameinfo((struct sockaddr *)sa, salen,
+ if ((err = getnameinfo(sa, salen,
host, sizeof(host),
port, sizeof(port),
NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
- remoteDispatchFormatError(rerr,
- _("Cannot resolve address %d: %s"),
- err, gai_strerror(err));
+ char ip[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(sa->sa_family, sa->sa_data, ip, sizeof ip)) {
+ remoteDispatchFormatError(rerr,
+ _("Cannot resolve address %s: %s"),
+ ip, gai_strerror(err));
+ } else {
+ remoteDispatchFormatError(rerr,
+ _("Cannot resolve address: %s"),
+ gai_strerror(err));
+ }
return NULL;
}
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index 44d8c26..752964f 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <arpa/inet.h>
/* Windows socket compatibility functions. */
#include <errno.h>
@@ -6570,21 +6571,30 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv,
#if HAVE_SASL
/*
- * NB, keep in sync with similar method in remote/remote.c
+ * NB, keep in sync with similar method in daemon/remote.c
*/
-static char *addrToString(struct sockaddr_storage *sa, socklen_t salen)
+static char *addrToString(struct sockaddr_storage *ss, socklen_t salen)
{
char host[NI_MAXHOST], port[NI_MAXSERV];
char *addr;
int err;
+ struct sockaddr *sa = (struct sockaddr *)ss;
- if ((err = getnameinfo((struct sockaddr *)sa, salen,
+ if ((err = getnameinfo(sa, salen,
host, sizeof(host),
port, sizeof(port),
NI_NUMERICHOST | NI_NUMERICSERV)) != 0) {
- remoteError(VIR_ERR_UNKNOWN_HOST,
- _("Cannot resolve address %d: %s"),
- err, gai_strerror(err));
+ char ip[INET6_ADDRSTRLEN];
+
+ if (inet_ntop(sa->sa_family, sa->sa_data, ip, sizeof ip)) {
+ remoteError(VIR_ERR_UNKNOWN_HOST,
+ _("Cannot resolve address %s: %s"),
+ ip, gai_strerror(err));
+ } else {
+ remoteError(VIR_ERR_UNKNOWN_HOST,
+ _("Cannot resolve address: %s"),
+ gai_strerror(err));
+ }
return NULL;
}
--
1.6.6.1
14 years, 7 months
[libvirt] [PATCH V2] nwfilter: lock interface by its index
by Stefan Berger
Changes from V1 to V2:
- using INT_BUFSIZE_BOUND() to determine the length of the buffersize
for printing and integer into
- not explicitly initializing static var threadsTerminate to false
anymore, since that's done automatically
- there are 2 calls in the virNWFilterLockIface function that can fail
due to OOM error; in case that happens, loop until the memory is
available to avoid a failing lock. The call initializing the mutex
should never fail with pthreads, otherwise we'd have a compile-time
problem (wrong parameters for recursive lock) and may fail due to OOM
error on win-32, so I am also looping there. The interface name may
cause a failure, but callers should be certain at this point that the
string is suitable. I am adding ATTRIBUTE_RETURN_CHECK to force the
caller to check for failure and adapting the code where the function is
called.
Since the name of an interface can be the same between stops and starts
of different VMs I have to switch the IP address learning thread to use
the index of the interface to determine whether an interface is still
available or not - in the case of macvtap the thread needs to listen for
traffic on the physical interface, thus having to time out periodically
to check whether the VM's macvtap device is still there as an indication
that the VM is still alive. Previously the following sequence of 2 VMs
with macvtap device
virsh start testvm1; virsh destroy testvm1 ; virsh start testvm2
would not terminate the thread upon testvm1's destroy since the name of
the interface on the host could be the same (i.e, macvtap0) on testvm1
and testvm2, thus it was easily race-able. The thread would then
determine the IP address parameter for testvm2 but apply the rule set
for testvm1. :-(
I am also introducing a lock for the interface (by name) that the thread
must hold while it listens for the traffic and releases when it
terminates upon VM termination or 0.5 second thereafter. Thus, the new
thread for a newly started VM with the same interface name will not
start while the old one still holds the lock. The only other code that I
see that also needs to grab the lock to serialize operation is the one
that tears down the firewall that were established on behalf of an
interface.
I am moving the code applying the 'basic' firewall rules during the IP
address learning phase inside the thread but won't start the thread
unless it is ensured that the firewall driver has the ability to apply
the 'basic' firewall rules.
Signed-off-by: Stefan Berger <stefanb(a)us.ibm.com>
---
src/nwfilter/nwfilter_gentech_driver.c | 24 +++
src/nwfilter/nwfilter_gentech_driver.h | 2
src/nwfilter/nwfilter_learnipaddr.c | 239 +++++++++++++++++++++++++++------
src/nwfilter/nwfilter_learnipaddr.h | 7
4 files changed, 229 insertions(+), 43 deletions(-)
Index: libvirt-acl/src/nwfilter/nwfilter_learnipaddr.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_learnipaddr.c
+++ libvirt-acl/src/nwfilter/nwfilter_learnipaddr.c
@@ -36,6 +36,7 @@
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <net/if_arp.h>
+#include <intprops.h>
#include "internal.h"
@@ -54,6 +55,11 @@
#define VIR_FROM_THIS VIR_FROM_NWFILTER
+#define IFINDEX2STR(VARNAME, ifindex) \
+ char VARNAME[INT_BUFSIZE_BOUND(ifindex)]; \
+ snprintf(VARNAME, sizeof(VARNAME), "%d", ifindex);
+
+#define PKT_TIMEOUT_MS 500 /* ms */
/* structure of an ARP request/reply message */
struct f_arphdr {
@@ -109,6 +115,96 @@ static virHashTablePtr pendingLearnReq;
static virMutex ipAddressMapLock;
static virNWFilterHashTablePtr ipAddressMap;
+static virMutex ifaceMapLock;
+static virHashTablePtr ifaceLockMap;
+
+typedef struct _virNWFilterIfaceLock virNWFilterIfaceLock;
+typedef virNWFilterIfaceLock *virNWFilterIfaceLockPtr;
+struct _virNWFilterIfaceLock {
+ char ifname[IF_NAMESIZE];
+ virMutex lock;
+ int refctr;
+};
+
+
+static bool threadsTerminate = false;
+
+
+int
+virNWFilterLockIface(const char *ifname) {
+ virNWFilterIfaceLockPtr ifaceLock;
+
+ virMutexLock(&ifaceMapLock);
+
+ ifaceLock = virHashLookup(ifaceLockMap, ifname);
+ if (!ifaceLock) {
+ while (VIR_ALLOC(ifaceLock) < 0) {
+ /* wait for memory */
+ usleep(50);
+ }
+
+ if (virMutexInitRecursive(&ifaceLock->lock)) {
+ /* win32 - wait for memory */
+ usleep(50);
+ }
+
+ if (virStrcpyStatic(ifaceLock->ifname, ifname) == NULL) {
+ VIR_FREE(ifaceLock);
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
+ _("%s: interface name %s does not fit into "
+ "buffer "),
+ __FUNCTION__, ifaceLock->ifname);
+ goto err_exit;
+ }
+
+ while (virHashAddEntry(ifaceLockMap, ifname, ifaceLock)) {
+ /* wait for memory */
+ usleep(50);
+ }
+
+ ifaceLock->refctr = 0;
+ }
+
+ ifaceLock->refctr++;
+
+ virMutexUnlock(&ifaceMapLock);
+
+ virMutexLock(&ifaceLock->lock);
+
+ return 0;
+
+ err_exit:
+ virMutexUnlock(&ifaceMapLock);
+
+ return 1;
+}
+
+
+static void
+freeIfaceLock(void *payload, const char *name ATTRIBUTE_UNUSED) {
+ VIR_FREE(payload);
+}
+
+
+void
+virNWFilterUnlockIface(const char *ifname) {
+ virNWFilterIfaceLockPtr ifaceLock;
+
+ virMutexLock(&ifaceMapLock);
+
+ ifaceLock = virHashLookup(ifaceLockMap, ifname);
+
+ if (ifaceLock) {
+ virMutexUnlock(&ifaceLock->lock);
+
+ ifaceLock->refctr--;
+ if (ifaceLock->refctr == 0)
+ virHashRemoveEntry(ifaceLockMap, ifname, freeIfaceLock);
+ }
+
+ virMutexUnlock(&ifaceMapLock);
+}
+
static void
virNWFilterIPAddrLearnReqFree(virNWFilterIPAddrLearnReqPtr req) {
@@ -127,10 +223,12 @@ virNWFilterIPAddrLearnReqFree(virNWFilte
static int
virNWFilterRegisterLearnReq(virNWFilterIPAddrLearnReqPtr req) {
int res = -1;
+ IFINDEX2STR(ifindex_str, req->ifindex);
+
virMutexLock(&pendingLearnReqLock);
- if (!virHashLookup(pendingLearnReq, req->ifname))
- res = virHashAddEntry(pendingLearnReq, req->ifname, req);
+ if (!virHashLookup(pendingLearnReq, ifindex_str))
+ res = virHashAddEntry(pendingLearnReq, ifindex_str, req);
virMutexUnlock(&pendingLearnReqLock);
@@ -141,12 +239,13 @@ virNWFilterRegisterLearnReq(virNWFilterI
virNWFilterIPAddrLearnReqPtr
-virNWFilterLookupLearnReq(const char *ifname) {
+virNWFilterLookupLearnReq(int ifindex) {
void *res;
+ IFINDEX2STR(ifindex_str, ifindex);
virMutexLock(&pendingLearnReqLock);
- res = virHashLookup(pendingLearnReq, ifname);
+ res = virHashLookup(pendingLearnReq, ifindex_str);
virMutexUnlock(&pendingLearnReqLock);
@@ -163,15 +262,16 @@ freeLearnReqEntry(void *payload, const c
#ifdef HAVE_LIBPCAP
static virNWFilterIPAddrLearnReqPtr
-virNWFilterDeregisterLearnReq(const char *ifname) {
+virNWFilterDeregisterLearnReq(int ifindex) {
virNWFilterIPAddrLearnReqPtr res;
+ IFINDEX2STR(ifindex_str, ifindex);
virMutexLock(&pendingLearnReqLock);
- res = virHashLookup(pendingLearnReq, ifname);
+ res = virHashLookup(pendingLearnReq, ifindex_str);
if (res)
- virHashRemoveEntry(pendingLearnReq, ifname, NULL);
+ virHashRemoveEntry(pendingLearnReq, ifindex_str, NULL);
virMutexUnlock(&pendingLearnReqLock);
@@ -274,7 +374,7 @@ static void *
learnIPAddressThread(void *arg)
{
char errbuf[PCAP_ERRBUF_SIZE] = {0};
- pcap_t *handle;
+ pcap_t *handle = NULL;
struct bpf_program fp;
struct pcap_pkthdr header;
const u_char *packet;
@@ -285,19 +385,27 @@ learnIPAddressThread(void *arg)
unsigned int ethHdrSize;
char *listen_if = (strlen(req->linkdev) != 0) ? req->linkdev
: req->ifname;
- int to_ms = (strlen(req->linkdev) != 0) ? 1000
- : 0;
int dhcp_opts_len;
char macaddr[VIR_MAC_STRING_BUFLEN];
virBuffer buf = VIR_BUFFER_INITIALIZER;
- char *filter= NULL;
+ char *filter = NULL;
uint16_t etherType;
+ bool showError = true;
enum howDetect howDetected = 0;
virNWFilterTechDriverPtr techdriver = req->techdriver;
+ if (virNWFilterLockIface(req->ifname))
+ goto err_no_lock;
+
req->status = 0;
- handle = pcap_open_live(listen_if, BUFSIZ, 0, to_ms, errbuf);
+ /* anything change to the VM's interface -- check at least once */
+ if (ifaceCheck(false, req->ifname, NULL, req->ifindex)) {
+ req->status = ENODEV;
+ goto done;
+ }
+
+ handle = pcap_open_live(listen_if, BUFSIZ, 0, PKT_TIMEOUT_MS, errbuf);
if (handle == NULL) {
VIR_DEBUG("Couldn't open device %s: %s\n", listen_if, errbuf);
@@ -309,11 +417,22 @@ learnIPAddressThread(void *arg)
switch (req->howDetect) {
case DETECT_DHCP:
+ if (techdriver->applyDHCPOnlyRules(req->ifname,
+ req->macaddr,
+ NULL)) {
+ req->status = EINVAL;
+ goto done;
+ }
virBufferVSprintf(&buf, " ether dst %s"
" and src port 67 and dst port 68",
macaddr);
break;
default:
+ if (techdriver->applyBasicRules(req->ifname,
+ req->macaddr)) {
+ req->status = EINVAL;
+ goto done;
+ }
virBufferVSprintf(&buf, "ether host %s", macaddr);
}
@@ -324,25 +443,36 @@ learnIPAddressThread(void *arg)
filter = virBufferContentAndReset(&buf);
- if (pcap_compile(handle, &fp, filter, 1, 0) != 0 ||
- pcap_setfilter(handle, &fp) != 0) {
- VIR_DEBUG("Couldn't compile or set filter '%s'.\n", filter);
+ if (pcap_compile(handle, &fp, filter, 1, 0) != 0) {
+ VIR_DEBUG("Couldn't compile filter '%s'.\n", filter);
req->status = EINVAL;
goto done;
}
+ if (pcap_setfilter(handle, &fp) != 0) {
+ VIR_DEBUG("Couldn't set filter '%s'.\n", filter);
+ req->status = EINVAL;
+ pcap_freecode(&fp);
+ goto done;
+ }
+
+ pcap_freecode(&fp);
+
while (req->status == 0 && vmaddr == 0) {
packet = pcap_next(handle, &header);
if (!packet) {
- if (to_ms == 0) {
- /* assuming IF disappeared */
- req->status = ENODEV;
+
+ if (threadsTerminate) {
+ req->status = ECANCELED;
+ showError = false;
break;
}
- /* listening on linkdev, check whether VM's dev is still there */
- if (ifaceCheck(false, req->ifname, req->macaddr, -1)) {
+
+ /* check whether VM's dev is still there */
+ if (ifaceCheck(false, req->ifname, NULL, req->ifindex)) {
req->status = ENODEV;
+ showError = false;
break;
}
continue;
@@ -470,6 +600,7 @@ learnIPAddressThread(void *arg)
ret = virNWFilterInstantiateFilterLate(NULL,
req->ifname,
+ req->ifindex,
req->linkdev,
req->nettype,
req->macaddr,
@@ -478,13 +609,23 @@ learnIPAddressThread(void *arg)
req->driver);
VIR_DEBUG("Result from applying firewall rules on "
"%s with IP addr %s : %d\n", req->ifname, inetaddr, ret);
+ } else {
+ if (showError)
+ virReportSystemError(req->status,
+ "%s encountered an error. Shutting down "
+ "interface %s",
+ __FUNCTION__, req->ifname);
+ ifaceDown(req->ifname);
}
memset(&req->thread, 0x0, sizeof(req->thread));
VIR_DEBUG("pcap thread terminating for interface %s\n",req->ifname);
- virNWFilterDeregisterLearnReq(req->ifname);
+ virNWFilterUnlockIface(req->ifname);
+
+ err_no_lock:
+ virNWFilterDeregisterLearnReq(req->ifindex);
virNWFilterIPAddrLearnReqFree(req);
@@ -496,6 +637,7 @@ learnIPAddressThread(void *arg)
* virNWFilterLearnIPAddress
* @techdriver : driver to build firewalls
* @ifname: the name of the interface
+ * @ifindex: the index of the interface
* @linkdev : the name of the link device; currently only used in case of a
* macvtap device
* @nettype : the type of interface
@@ -516,6 +658,7 @@ learnIPAddressThread(void *arg)
int
virNWFilterLearnIPAddress(virNWFilterTechDriverPtr techdriver,
const char *ifname,
+ int ifindex,
const char *linkdev,
enum virDomainNetType nettype,
const unsigned char *macaddr,
@@ -530,6 +673,14 @@ virNWFilterLearnIPAddress(virNWFilterTec
if (howDetect == 0)
return 1;
+ if ( !techdriver->canApplyBasicRules()) {
+ virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("IP parameter must be provided since "
+ "snooping the IP address does not work "
+ "possibly due to missing tools"));
+ return 1;
+ }
+
if (VIR_ALLOC(req) < 0) {
virReportOOMError();
goto err_no_req;
@@ -538,7 +689,7 @@ virNWFilterLearnIPAddress(virNWFilterTec
ht = virNWFilterHashTableCreate(0);
if (ht == NULL) {
virReportOOMError();
- goto err_no_ht;
+ goto err_free_req;
}
if (virNWFilterHashTablePutAll(filterparams, ht))
@@ -565,6 +716,8 @@ virNWFilterLearnIPAddress(virNWFilterTec
goto err_free_ht;
}
}
+
+ req->ifindex = ifindex;
req->nettype = nettype;
memcpy(req->macaddr, macaddr, sizeof(req->macaddr));
req->driver = driver;
@@ -576,35 +729,21 @@ virNWFilterLearnIPAddress(virNWFilterTec
rc = virNWFilterRegisterLearnReq(req);
if (rc)
- goto err_free_ht;
-
- switch (howDetect) {
- case DETECT_DHCP:
- if (techdriver->applyDHCPOnlyRules(ifname,
- macaddr,
- NULL))
- goto err_free_ht;
- break;
- default:
- if (techdriver->applyBasicRules(ifname,
- macaddr))
- goto err_free_ht;
- }
-
+ goto err_free_req;
if (pthread_create(&req->thread,
NULL,
learnIPAddressThread,
req) != 0)
- goto err_remove_rules;
+ goto err_dereg_req;
return 0;
-err_remove_rules:
- techdriver->removeBasicRules(ifname);
+err_dereg_req:
+ virNWFilterDeregisterLearnReq(ifindex);
err_free_ht:
virNWFilterHashTableFree(ht);
-err_no_ht:
+err_free_req:
virNWFilterIPAddrLearnReqFree(req);
err_no_req:
return 1;
@@ -615,6 +754,7 @@ err_no_req:
int
virNWFilterLearnIPAddress(virNWFilterTechDriverPtr techdriver ATTRIBUTE_UNUSED,
const char *ifname ATTRIBUTE_UNUSED,
+ int ifindex ATTRIBUTE_UNUSED,
const char *linkdev ATTRIBUTE_UNUSED,
enum virDomainNetType nettype ATTRIBUTE_UNUSED,
const unsigned char *macaddr ATTRIBUTE_UNUSED,
@@ -637,6 +777,12 @@ virNWFilterLearnIPAddress(virNWFilterTec
*/
int
virNWFilterLearnInit(void) {
+
+ if (pendingLearnReq)
+ return 0;
+
+ threadsTerminate = false;
+
pendingLearnReq = virHashCreate(0);
if (!pendingLearnReq) {
virReportOOMError();
@@ -660,6 +806,18 @@ virNWFilterLearnInit(void) {
return 1;
}
+ ifaceLockMap = virHashCreate(0);
+ if (!ifaceLockMap) {
+ virReportOOMError();
+ virNWFilterLearnShutdown();
+ return 1;
+ }
+
+ if (virMutexInit(&ifaceMapLock)) {
+ virNWFilterLearnShutdown();
+ return 1;
+ }
+
return 0;
}
@@ -670,9 +828,18 @@ virNWFilterLearnInit(void) {
*/
void
virNWFilterLearnShutdown(void) {
+
+ threadsTerminate = true;
+
+ while (virHashSize(pendingLearnReq) != 0)
+ usleep((PKT_TIMEOUT_MS * 1000) / 3);
+
virHashFree(pendingLearnReq, freeLearnReqEntry);
pendingLearnReq = NULL;
virNWFilterHashTableFree(ipAddressMap);
ipAddressMap = NULL;
+
+ virHashFree(ifaceLockMap, freeIfaceLock);
+ ifaceLockMap = NULL;
}
Index: libvirt-acl/src/nwfilter/nwfilter_learnipaddr.h
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_learnipaddr.h
+++ libvirt-acl/src/nwfilter/nwfilter_learnipaddr.h
@@ -35,6 +35,7 @@ typedef virNWFilterIPAddrLearnReq *virNW
struct _virNWFilterIPAddrLearnReq {
virNWFilterTechDriverPtr techdriver;
char ifname[IF_NAMESIZE];
+ int ifindex;
char linkdev[IF_NAMESIZE];
enum virDomainNetType nettype;
unsigned char macaddr[VIR_MAC_BUFLEN];
@@ -49,6 +50,7 @@ struct _virNWFilterIPAddrLearnReq {
int virNWFilterLearnIPAddress(virNWFilterTechDriverPtr techdriver,
const char *ifname,
+ int ifindex,
const char *linkdev,
enum virDomainNetType nettype,
const unsigned char *macaddr,
@@ -57,12 +59,15 @@ int virNWFilterLearnIPAddress(virNWFilte
virNWFilterDriverStatePtr driver,
enum howDetect howDetect);
-virNWFilterIPAddrLearnReqPtr virNWFilterLookupLearnReq(const char *ifname);
+virNWFilterIPAddrLearnReqPtr virNWFilterLookupLearnReq(int ifindex);
void virNWFilterDelIpAddrForIfname(const char *ifname);
const char *virNWFilterGetIpAddrForIfname(const char *ifname);
+int virNWFilterLockIface(const char *ifname) ATTRIBUTE_RETURN_CHECK;
+void virNWFilterUnlockIface(const char *ifname);
+
int virNWFilterLearnInit(void);
void virNWFilterLearnShutdown(void);
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_gentech_driver.c
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.c
@@ -557,6 +557,7 @@ virNWFilterInstantiate(virConnectPtr con
enum virDomainNetType nettype,
virNWFilterDefPtr filter,
const char *ifname,
+ int ifindex,
const char *linkdev,
virNWFilterHashTablePtr vars,
enum instCase useNewFilter, int *foundNewFilter,
@@ -592,9 +593,10 @@ virNWFilterInstantiate(virConnectPtr con
if (virHashSize(missing_vars->hashTable) == 1) {
if (virHashLookup(missing_vars->hashTable,
NWFILTER_STD_VAR_IP) != NULL) {
- if (virNWFilterLookupLearnReq(ifname) == NULL) {
+ if (virNWFilterLookupLearnReq(ifindex) == NULL) {
rc = virNWFilterLearnIPAddress(techdriver,
ifname,
+ ifindex,
linkdev,
nettype, macaddr,
filter->name,
@@ -639,11 +641,22 @@ virNWFilterInstantiate(virConnectPtr con
if (rc)
goto err_exit;
+ if (virNWFilterLockIface(ifname))
+ goto err_exit;
+
rc = techdriver->applyNewRules(conn, ifname, nptrs, ptrs);
if (teardownOld && rc == 0)
techdriver->tearOldRules(conn, ifname);
+ if (rc == 0 && ifaceCheck(false, ifname, NULL, ifindex)) {
+ /* interface changed/disppeared */
+ techdriver->allTeardown(ifname);
+ rc = 1;
+ }
+
+ virNWFilterUnlockIface(ifname);
+
VIR_FREE(ptrs);
}
@@ -666,6 +679,7 @@ static int
__virNWFilterInstantiateFilter(virConnectPtr conn,
bool teardownOld,
const char *ifname,
+ int ifindex,
const char *linkdev,
enum virDomainNetType nettype,
const unsigned char *macaddr,
@@ -767,6 +781,7 @@ __virNWFilterInstantiateFilter(virConnec
nettype,
filter,
ifname,
+ ifindex,
linkdev,
vars,
useNewFilter, &foundNewFilter,
@@ -798,9 +813,15 @@ _virNWFilterInstantiateFilter(virConnect
const char *linkdev = (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
? net->data.direct.linkdev
: NULL;
+ int ifindex;
+
+ if (ifaceGetIndex(true, net->ifname, &ifindex))
+ return 1;
+
return __virNWFilterInstantiateFilter(conn,
teardownOld,
net->ifname,
+ ifindex,
linkdev,
net->type,
net->mac,
@@ -814,6 +835,7 @@ _virNWFilterInstantiateFilter(virConnect
int
virNWFilterInstantiateFilterLate(virConnectPtr conn,
const char *ifname,
+ int ifindex,
const char *linkdev,
enum virDomainNetType nettype,
const unsigned char *macaddr,
@@ -825,6 +847,7 @@ virNWFilterInstantiateFilterLate(virConn
rc = __virNWFilterInstantiateFilter(conn,
1,
ifname,
+ ifindex,
linkdev,
nettype,
macaddr,
Index: libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
===================================================================
--- libvirt-acl.orig/src/nwfilter/nwfilter_gentech_driver.h
+++ libvirt-acl/src/nwfilter/nwfilter_gentech_driver.h
@@ -49,6 +49,7 @@ int virNWFilterTearOldFilter(virConnectP
int virNWFilterInstantiateFilterLate(virConnectPtr conn,
const char *ifname,
+ int ifindex,
const char *linkdev,
enum virDomainNetType nettype,
const unsigned char *macaddr,
@@ -77,6 +78,7 @@ virNWFilterTearNWFilter(virDomainNetDefP
static inline void
virNWFilterTearVMNWFilters(virDomainObjPtr vm) {
int i;
+
for (i = 0; i < vm->def->nnets; i++)
virNWFilterTearNWFilter(vm->def->nets[i]);
}
14 years, 7 months
[libvirt] [PATCH] Fix locking in qemudDomainCoreDump
by y@orkuz.home
From: Jiri Denemark <jdenemar(a)redhat.com>
The hang fix in d376b7d63ec1ef24ba4c812d58b9a414ddb561f8 was incomplete
since it left quite a few {Enter,Exit}Monitor calls which require driver
to be unlocked. Since the driver is locked throughout the whole
function, {Enter,Exit}MonitorWithDriver need to be used instead to
ensure driver is not locked when issuing monitor commands.
---
src/qemu/qemu_driver.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 4afed2f..0a0d9bc 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5165,18 +5165,18 @@ static int qemudDomainCoreDump(virDomainPtr dom,
/* Pause domain for non-live dump */
if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
- qemuDomainObjEnterMonitor(vm);
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorStopCPUs(priv->mon) < 0) {
- qemuDomainObjExitMonitor(vm);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
goto endjob;
}
- qemuDomainObjExitMonitor(vm);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
paused = 1;
}
- qemuDomainObjEnterMonitor(vm);
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorMigrateToCommand(priv->mon, 1, args, path);
- qemuDomainObjExitMonitor(vm);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
if (ret < 0)
goto endjob;
@@ -5205,13 +5205,13 @@ endjob:
will support synchronous operations so we always get here after
the migration is complete. */
else if (resume && paused) {
- qemuDomainObjEnterMonitor(vm);
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
if (virGetLastError() == NULL)
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("resuming after dump failed"));
}
- qemuDomainObjExitMonitor(vm);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
}
if (qemuDomainObjEndJob(vm) == 0)
--
1.7.0.4
14 years, 7 months
[libvirt] [PATCH] Poll for migration end every 50ms instead of 50us
by Jiri Denemark
The comment in qemuDomainWaitForMigrationComplete says we are polling
every 50ms but the code sleeps only for 50us. This was already discussed
during review but apparently forgotten when the series was pushed.
---
src/qemu/qemu_driver.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 89cd291..4afed2f 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -4524,7 +4524,7 @@ qemuDomainWaitForMigrationComplete(struct qemud_driver *driver, virDomainObjPtr
while (priv->jobInfo.type == VIR_DOMAIN_JOB_UNBOUNDED) {
/* Poll every 50ms for progress & to allow cancellation */
- struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000ull };
+ struct timespec ts = { .tv_sec = 0, .tv_nsec = 50 * 1000 * 1000ull };
struct timeval now;
int rc;
--
1.7.0.4
14 years, 7 months
[libvirt] [PATCH v2 0/7] CPU selection fixes and tests
by Jiri Denemark
In this second version of the patchset, patches were reordered and a
comment for format expected by qemudParseX86Models() was modified as
suggested by Eric. In addition to these changes, qemu tests were fixed
to pass on RHEL.
Jirka
Jiri Denemark (7):
Deal with CPU models in []
Move MIN macro to util.h so that others can use it
Support removing features when converting data to CPU
Use configured CPU model if possible
Fake host CPU for qemu tests
Support for faking emulator in qemuxml2argv tests
Tests for CPU selection in qemu driver
src/cpu/cpu.c | 8 +-
src/cpu/cpu.h | 6 +-
src/cpu/cpu_x86.c | 82 +++++++++++++++-----
src/qemu/qemu_conf.c | 39 ++++++++--
src/util/util.c | 4 -
src/util/util.h | 4 +
tests/qemuxml2argvdata/qemu.sh | 64 +++++++++++++++
.../qemuxml2argvdata/qemuxml2argv-cpu-exact1.args | 1 +
tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml | 28 +++++++
.../qemuxml2argvdata/qemuxml2argv-cpu-exact2.args | 1 +
tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml | 35 ++++++++
.../qemuxml2argv-cpu-minimum1.args | 1 +
.../qemuxml2argvdata/qemuxml2argv-cpu-minimum1.xml | 21 +++++
.../qemuxml2argv-cpu-minimum2.args | 1 +
.../qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml | 25 ++++++
.../qemuxml2argvdata/qemuxml2argv-cpu-strict1.args | 1 +
.../qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml | 38 +++++++++
.../qemuxml2argv-cpu-topology1.args | 1 +
.../qemuxml2argv-cpu-topology1.xml | 21 +++++
.../qemuxml2argv-cpu-topology2.args | 1 +
.../qemuxml2argv-cpu-topology2.xml | 22 +++++
.../qemuxml2argv-cpu-topology3.args | 1 +
.../qemuxml2argv-cpu-topology3.xml | 21 +++++
tests/qemuxml2argvtest.c | 27 +++++++
tests/testutilsqemu.c | 30 +++++++-
25 files changed, 444 insertions(+), 39 deletions(-)
create mode 100755 tests/qemuxml2argvdata/qemu.sh
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-exact1.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-exact2.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum1.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum1.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-minimum2.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-strict1.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-topology1.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-topology1.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-topology2.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-topology2.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-topology3.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-cpu-topology3.xml
14 years, 7 months
[libvirt] [PATCH] Fix locking in qemudDomainCoreDump
by Jiri Denemark
The hang fix in d376b7d63ec1ef24ba4c812d58b9a414ddb561f8 was incomplete
since it left quite a few {Enter,Exit}Monitor calls which require driver
to be unlocked. Since the driver is locked throughout the whole
function, {Enter,Exit}MonitorWithDriver need to be used instead to
ensure driver is not locked when issuing monitor commands.
---
src/qemu/qemu_driver.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 4afed2f..0a0d9bc 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -5165,18 +5165,18 @@ static int qemudDomainCoreDump(virDomainPtr dom,
/* Pause domain for non-live dump */
if (!(flags & VIR_DUMP_LIVE) && vm->state == VIR_DOMAIN_RUNNING) {
- qemuDomainObjEnterMonitor(vm);
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorStopCPUs(priv->mon) < 0) {
- qemuDomainObjExitMonitor(vm);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
goto endjob;
}
- qemuDomainObjExitMonitor(vm);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
paused = 1;
}
- qemuDomainObjEnterMonitor(vm);
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
ret = qemuMonitorMigrateToCommand(priv->mon, 1, args, path);
- qemuDomainObjExitMonitor(vm);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
if (ret < 0)
goto endjob;
@@ -5205,13 +5205,13 @@ endjob:
will support synchronous operations so we always get here after
the migration is complete. */
else if (resume && paused) {
- qemuDomainObjEnterMonitor(vm);
+ qemuDomainObjEnterMonitorWithDriver(driver, vm);
if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
if (virGetLastError() == NULL)
qemuReportError(VIR_ERR_OPERATION_FAILED,
"%s", _("resuming after dump failed"));
}
- qemuDomainObjExitMonitor(vm);
+ qemuDomainObjExitMonitorWithDriver(driver, vm);
}
if (qemuDomainObjEndJob(vm) == 0)
--
1.7.0.4
14 years, 7 months
[libvirt] [PATCH TCK] Add a minimal test case for CPU hotplug
by Daniel P. Berrange
Adds a minimal test case which verifies that it is possible to
set the CPU count to max, and then back to the min. This really
needs libguestfs integration to validate that the guest sees the
change
---
scripts/domain/130-cpu-hotplug.t | 78 ++++++++++++++++++++++++++++++++++++++
1 files changed, 78 insertions(+), 0 deletions(-)
create mode 100644 scripts/domain/130-cpu-hotplug.t
diff --git a/scripts/domain/130-cpu-hotplug.t b/scripts/domain/130-cpu-hotplug.t
new file mode 100644
index 0000000..2976f2d
--- /dev/null
+++ b/scripts/domain/130-cpu-hotplug.t
@@ -0,0 +1,78 @@
+# -*- perl -*-
+#
+# Copyright (C) 2009-2010 Red Hat, Inc.
+# Copyright (C) 2009-2010 Daniel P. Berrange
+#
+# This program is free software; You can redistribute it and/or modify
+# it under the GNU General Public License as published by the Free
+# Software Foundation; either version 2, or (at your option) any
+# later version
+#
+# The file "LICENSE" distributed along with this file provides full
+# details of the terms and conditions
+#
+
+=pod
+
+=head1 NAME
+
+domain/130-cpu-hotplug.t - whether CPU count can be changed
+
+=head1 DESCRIPTION
+
+The test case validates the it is possible to change the CPU
+on a running guest.
+
+XXX: Need libguestfs integration to check that it has truely
+worked.
+
+=cut
+
+use strict;
+use warnings;
+
+use Test::More tests => 7;
+use Test::Exception;
+
+use Sys::Virt::TCK;
+
+my $tck = Sys::Virt::TCK->new();
+my $conn = eval { $tck->setup(); };
+BAIL_OUT "failed to setup test harness: $@" if $@;
+END { $tck->cleanup if $tck; }
+
+
+my $xml = $tck->generic_domain("tck")->as_xml;
+
+
+diag "Creating a new transient domain";
+my $dom;
+ok_domain(sub { $dom = $conn->create_domain($xml) }, "created transient domain object");
+
+my $max;
+lives_ok(sub { $max = $dom->get_max_vcpus() }, "queried max vcpus");
+
+SKIP: {
+ skip "SMP guests not supported", 4 unless $max > 1;
+
+ diag "Increasing CPU count to max";
+ lives_ok(sub { $dom->set_vcpus($max); }, "set vcpus to $max");
+
+ my $info = $dom->get_info();
+
+ is($info->{nrVirtCpu}, $max, "cpu count $info->{nrVirtCpu} is $max");
+
+ diag "Decreasing CPU count to min";
+ lives_ok(sub { $dom->set_vcpus(1); }, "set vcpus to 1");
+
+ $info = $dom->get_info();
+ is($info->{nrVirtCpu}, 1, "cpu count $info->{nrVirtCpu} is 1");
+}
+
+diag "Destroying the transient domain";
+$dom->destroy;
+
+diag "Checking that transient domain has gone away";
+ok_error(sub { $conn->get_domain_by_name("tck") }, "NO_DOMAIN error raised from missing domain", 42);
+
+# end
--
1.6.5.2
14 years, 7 months