[libvirt] [ocaml] event registration APis v3
by David Scott
Hi,
Here are my latest patches which add OCaml bindings for the libvirt event
API. I'm pretty happy with them now: my test programs have been running
for long periods of time without incident.
Changes from the previous submission (sent 2013-04-17)
* added a patch which removes the backwards compatability logic from
the bindings. The aim is to make the bindings simpler to read and
develop.
Changes from the initial submission (sent 2013-03-27)
* add support for 'deregister_any'
* fix the ordering of '{enter,leave}_blocking_section' and GC registration
* add timer callbacks
Cheers,
Dave
11 years, 6 months
[libvirt] Bug in DOMINFO command when balloon driver is used on a vm with more then 8 GB of MaxMemory ?
by fc lists
Hi ,
I have been banging my head on this for the last 8 hours ... and i really
need to know if is really a bug or i am doing something wrong.
Description of the problem:
When the virsh setmem command is used to inflate the balloon on a VM to
which 8GB of MaxMemory or more are allocated then the information reported
with virsh dominfo , virsh dumpxml after the balloon change has been
performed are wrong.
The actual balloon is inflated correctly though and that is verifiable both
in the vm itself and through the "virsh dommemstat" commands.
I *think* that is because the dommestat command will perform a proper query
to find out the amount of ram currently used (and i can see that in the
logs when issuing a dommestat command)
2013-03-22 21:22:41.820+0000: 23181: debug : virJSONValueToString:1133 :
result={"execute":"query-balloon","id":"libvirt-9"}
2013-03-22 21:22:41.820+0000: 23181: debug :
qemuMonitorJSONCommandWithFd:265 : Send command
'{"execute":"query-balloon","id":"libvirt-9"}' for write with FD -1
2013-03-22 21:22:41.820+0000: 23181: debug : qemuMonitorSend:903 :
QEMU_MONITOR_SEND_MSG: mon=0x7f3d643eb5a0
msg={"execute":"query-balloon","id":"libvirt-9"}
2013-03-22 21:22:41.820+0000: 23179: debug : qemuMonitorIOWrite:461 :
QEMU_MONITOR_IO_WRITE: mon=0x7f3d643eb5a0
buf={"execute":"query-balloon","id":"libvirt-9"}
but no entries are shown in the log for qemu-monitor when virsh dominfo is
run, how does dominfo gather those informations?
I am going to raise a ticket on RED HAT bugzilla for this but was hoping to
get some feedback here first to avoid raising a ticket for something that
maybe i just misunderstood.
Platform is Centos 6.4 (problem was present in 6.3 as well starting
with libvirt-0.9.10-21.el6.3.7 )
The patch that actually is causing the problem is patch number 398 in the
src rpm for libvirt-0.9.10-21.el6.3.7 :
libvirt-Wire-up-handling-for-QMP-s-BALLOON_EVENT.patch (
https://bugzilla.redhat.com/show_bug.cgi?id=884713)
And i verified it by removing the patch and recompiling the rpm , that
indeed worked perfectly after that.
The problem exists in every version up to the latest (that is what i am
running now) but now the patch is part of the libvirt source code in itself
and not a patch in the rpm anymore.
Software used:
# yum list installed | egrep -i "qemu|libvirt"
gpxe-roms-qemu.noarch 0.9.7-6.9.el6 @base
libvirt.x86_64 0.10.2-18.el6_4.2 @updates
libvirt-client.x86_64 0.10.2-18.el6_4.2 @updates
libvirt-python.x86_64 0.10.2-18.el6_4.2 @updates
qemu-img.x86_64 2:0.12.1.2-2.355.0.1.el6.centos.2 @updates
qemu-kvm.x86_64 2:0.12.1.2-2.355.0.1.el6.centos.2 @updates
qemu-kvm-tools.x86_64 2:0.12.1.2-2.355.0.1.el6.centos.2 @updates
Full example ( long and include debug logs ) :
1) Start VM with 12GB of MAX and CURRENT (12582912)
(tail -f libvirtd.log | grep -i balloon)
2013-03-22 21:06:34.438+0000: 23180: debug : qemuMonitorSetBalloon:1690 :
mon=0x7f3d6c1789e0 newmem=12582912
2013-03-22 21:06:34.438+0000: 23180: debug : virJSONValueToString:1133 :
result={"execute":"balloon","arguments":{"value":12884901888},"id":"libvirt-6"}
2013-03-22 21:06:34.438+0000: 23180: debug :
qemuMonitorJSONCommandWithFd:265 : Send command
'{"execute":"balloon","arguments":{"value":12884901888},"id":"libvirt-6"}'
for write with FD -1
2013-03-22 21:06:34.438+0000: 23180: debug : qemuMonitorSend:903 :
QEMU_MONITOR_SEND_MSG: mon=0x7f3d6c1789e0
msg={"execute":"balloon","arguments":{"value":12884901888},"id":"libvirt-6"}
2013-03-22 21:06:34.439+0000: 23179: debug : qemuMonitorIOWrite:461 :
QEMU_MONITOR_IO_WRITE: mon=0x7f3d6c1789e0
buf={"execute":"balloon","arguments":{"value":12884901888},"id":"libvirt-6"}
# dominfo 2
Id: 2
Name: centos_jt
UUID: bc25a6c4-ba34-a593-47c7-6372999946d6
OS Type: hvm
State: running
CPU(s): 1
CPU time: 26.6s
Max memory: 12582912 KiB
Used memory: 12582912 KiB
Persistent: yes
Autostart: disable
Managed save: no
Security model: none
Security DOI: 0
2) set mem to 8GB
# setmem 2 --live --config --size 8388608
2013-03-22 21:13:45.522+0000: 23183: debug : qemuMonitorSetBalloon:1690 :
mon=0x7f3d6c1789e0 newmem=8388608
2013-03-22 21:13:45.522+0000: 23183: debug : virJSONValueToString:1133 :
result={"execute":"balloon","arguments":{"value":8589934592},"id":"libvirt-9"}
2013-03-22 21:13:45.522+0000: 23183: debug :
qemuMonitorJSONCommandWithFd:265 : Send command
'{"execute":"balloon","arguments":{"value":8589934592},"id":"libvirt-9"}'
for write with FD -1
2013-03-22 21:13:45.522+0000: 23183: debug : qemuMonitorSend:903 :
QEMU_MONITOR_SEND_MSG: mon=0x7f3d6c1789e0
msg={"execute":"balloon","arguments":{"value":8589934592},"id":"libvirt-9"}
2013-03-22 21:13:45.523+0000: 23179: debug : qemuMonitorIOWrite:461 :
QEMU_MONITOR_IO_WRITE: mon=0x7f3d6c1789e0
buf={"execute":"balloon","arguments":{"value":8589934592},"id":"libvirt-9"}
2013-03-22 21:13:45.528+0000: 23179: debug : qemuMonitorIOProcess:353 :
QEMU_MONITOR_IO_PROCESS: mon=0x7f3d6c1789e0 buf={"timestamp": {"seconds":
1363986825, "microseconds": 528314}, "event": "BALLOON_CHANGE", "data":
{"actual": 12883853312}}
2013-03-22 21:13:45.528+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:152 : Line [{"timestamp": {"seconds":
1363986825, "microseconds": 528314}, "event": "BALLOON_CHANGE", "data":
{"actual": 12883853312}}]
2013-03-22 21:13:45.528+0000: 23179: debug : virJSONValueFromString:975 :
string={"timestamp": {"seconds": 1363986825, "microseconds": 528314},
"event": "BALLOON_CHANGE", "data": {"actual": 12883853312}}
2013-03-22 21:13:45.528+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:167 : QEMU_MONITOR_RECV_EVENT:
mon=0x7f3d6c1789e0 event={"timestamp": {"seconds": 1363986825,
"microseconds": 528314}, "event": "BALLOON_CHANGE", "data": {"actual":
12883853312}}
2013-03-22 21:13:45.528+0000: 23179: debug :
qemuMonitorJSONIOProcessEvent:138 : handle BALLOON_CHANGE handler=0x4b4de0
data=0x1685ce0
2013-03-22 21:13:45.528+0000: 23179: debug :
qemuMonitorEmitBalloonChange:1151 : mon=0x7f3d6c1789e0
2013-03-22 21:13:45.528+0000: 23179: debug :
qemuProcessHandleBalloonChange:1248 : Updating balloon from 12582912 to
12581888 kb
2013-03-22 21:13:46.528+0000: 23179: debug : qemuMonitorIOProcess:353 :
QEMU_MONITOR_IO_PROCESS: mon=0x7f3d6c1789e0 buf={"timestamp": {"seconds":
1363986826, "microseconds": 352941}, "event": "BALLOON_CHANGE", "data":
{"actual": 12884901888}}
2013-03-22 21:13:46.528+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:152 : Line [{"timestamp": {"seconds":
1363986826, "microseconds": 352941}, "event": "BALLOON_CHANGE", "data":
{"actual": 12884901888}}]
2013-03-22 21:13:46.528+0000: 23179: debug : virJSONValueFromString:975 :
string={"timestamp": {"seconds": 1363986826, "microseconds": 352941},
"event": "BALLOON_CHANGE", "data": {"actual": 12884901888}}
2013-03-22 21:13:46.528+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:167 : QEMU_MONITOR_RECV_EVENT:
mon=0x7f3d6c1789e0 event={"timestamp": {"seconds": 1363986826,
"microseconds": 352941}, "event": "BALLOON_CHANGE", "data": {"actual":
12884901888}}
2013-03-22 21:13:46.528+0000: 23179: debug :
qemuMonitorJSONIOProcessEvent:138 : handle BALLOON_CHANGE handler=0x4b4de0
data=0x1686770
2013-03-22 21:13:46.528+0000: 23179: debug :
qemuMonitorEmitBalloonChange:1151 : mon=0x7f3d6c1789e0
2013-03-22 21:13:46.528+0000: 23179: debug :
qemuProcessHandleBalloonChange:1248 : Updating balloon from 12581888 to
12582912 kb
virsh # dominfo 2
Id: 2
Name: centos_jt
UUID: bc25a6c4-ba34-a593-47c7-6372999946d6
OS Type: hvm
State: running
CPU(s): 1
CPU time: 41.6s
Max memory: 12582912 KiB
Used memory: 12582912 KiB
Persistent: yes
Autostart: disable
Managed save: no
Security model: none
Security DOI: 0
virsh # dommemstat 2
actual 8388608
rss 599916
The Balloon was actually inflated , and in the VM i can see 8GB of Ram
available with free
3) setmem to to 3000000
2013-03-22 21:18:19.182+0000: 23181: debug : qemuMonitorSetBalloon:1690 :
mon=0x7f3d6c1789e0 newmem=3000000
2013-03-22 21:18:19.182+0000: 23181: debug : virJSONValueToString:1133 :
result={"execute":"balloon","arguments":{"value":3072000000},"id":"libvirt-63"}
2013-03-22 21:18:19.182+0000: 23181: debug :
qemuMonitorJSONCommandWithFd:265 : Send command
'{"execute":"balloon","arguments":{"value":3072000000},"id":"libvirt-63"}'
for write with FD -1
2013-03-22 21:18:19.182+0000: 23181: debug : qemuMonitorSend:903 :
QEMU_MONITOR_SEND_MSG: mon=0x7f3d6c1789e0
msg={"execute":"balloon","arguments":{"value":3072000000},"id":"libvirt-63"}
2013-03-22 21:18:19.183+0000: 23179: debug : qemuMonitorIOWrite:461 :
QEMU_MONITOR_IO_WRITE: mon=0x7f3d6c1789e0
buf={"execute":"balloon","arguments":{"value":3072000000},"id":"libvirt-63"}
2013-03-22 21:18:19.184+0000: 23179: debug : qemuMonitorIOProcess:353 :
QEMU_MONITOR_IO_PROCESS: mon=0x7f3d6c1789e0 buf={"timestamp": {"seconds":
1363987099, "microseconds": 184245}, "event": "BALLOON_CHANGE", "data":
{"actual": 12883853312}}
2013-03-22 21:18:19.184+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:152 : Line [{"timestamp": {"seconds":
1363987099, "microseconds": 184245}, "event": "BALLOON_CHANGE", "data":
{"actual": 12883853312}}]
2013-03-22 21:18:19.184+0000: 23179: debug : virJSONValueFromString:975 :
string={"timestamp": {"seconds": 1363987099, "microseconds": 184245},
"event": "BALLOON_CHANGE", "data": {"actual": 12883853312}}
2013-03-22 21:18:19.184+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:167 : QEMU_MONITOR_RECV_EVENT:
mon=0x7f3d6c1789e0 event={"timestamp": {"seconds": 1363987099,
"microseconds": 184245}, "event": "BALLOON_CHANGE", "data": {"actual":
12883853312}}
2013-03-22 21:18:19.184+0000: 23179: debug :
qemuMonitorJSONIOProcessEvent:138 : handle BALLOON_CHANGE handler=0x4b4de0
data=0x1688320
2013-03-22 21:18:19.184+0000: 23179: debug :
qemuMonitorEmitBalloonChange:1151 : mon=0x7f3d6c1789e0
2013-03-22 21:18:19.191+0000: 23179: debug :
qemuProcessHandleBalloonChange:1248 : Updating balloon from 12582912 to
12581888 kb
2013-03-22 21:18:20.184+0000: 23179: debug : qemuMonitorIOProcess:353 :
QEMU_MONITOR_IO_PROCESS: mon=0x7f3d6c1789e0 buf={"timestamp": {"seconds":
1363987100, "microseconds": 184128}, "event": "BALLOON_CHANGE", "data":
{"actual": 11874074624}}
2013-03-22 21:18:20.184+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:152 : Line [{"timestamp": {"seconds":
1363987100, "microseconds": 184128}, "event": "BALLOON_CHANGE", "data":
{"actual": 11874074624}}]
2013-03-22 21:18:20.184+0000: 23179: debug : virJSONValueFromString:975 :
string={"timestamp": {"seconds": 1363987100, "microseconds": 184128},
"event": "BALLOON_CHANGE", "data": {"actual": 11874074624}}
2013-03-22 21:18:20.184+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:167 : QEMU_MONITOR_RECV_EVENT:
mon=0x7f3d6c1789e0 event={"timestamp": {"seconds": 1363987100,
"microseconds": 184128}, "event": "BALLOON_CHANGE", "data": {"actual":
11874074624}}
2013-03-22 21:18:20.184+0000: 23179: debug :
qemuMonitorJSONIOProcessEvent:138 : handle BALLOON_CHANGE handler=0x4b4de0
data=0x1685ce0
2013-03-22 21:18:20.184+0000: 23179: debug :
qemuMonitorEmitBalloonChange:1151 : mon=0x7f3d6c1789e0
2013-03-22 21:18:20.184+0000: 23179: debug :
qemuProcessHandleBalloonChange:1248 : Updating balloon from 12581888 to
11595776 kb
2013-03-22 21:18:21.184+0000: 23179: debug : qemuMonitorIOProcess:353 :
QEMU_MONITOR_IO_PROCESS: mon=0x7f3d6c1789e0 buf={"timestamp": {"seconds":
1363987100, "microseconds": 224930}, "event": "BALLOON_CHANGE", "data":
{"actual": 11661934592}}
2013-03-22 21:18:21.184+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:152 : Line [{"timestamp": {"seconds":
1363987100, "microseconds": 224930}, "event": "BALLOON_CHANGE", "data":
{"actual": 11661934592}}]
2013-03-22 21:18:21.184+0000: 23179: debug : virJSONValueFromString:975 :
string={"timestamp": {"seconds": 1363987100, "microseconds": 224930},
"event": "BALLOON_CHANGE", "data": {"actual": 11661934592}}
2013-03-22 21:18:21.184+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:167 : QEMU_MONITOR_RECV_EVENT:
mon=0x7f3d6c1789e0 event={"timestamp": {"seconds": 1363987100,
"microseconds": 224930}, "event": "BALLOON_CHANGE", "data": {"actual":
11661934592}}
2013-03-22 21:18:21.184+0000: 23179: debug :
qemuMonitorJSONIOProcessEvent:138 : handle BALLOON_CHANGE handler=0x4b4de0
data=0x1686770
2013-03-22 21:18:21.184+0000: 23179: debug :
qemuMonitorEmitBalloonChange:1151 : mon=0x7f3d6c1789e0
2013-03-22 21:18:21.184+0000: 23179: debug :
qemuProcessHandleBalloonChange:1248 : Updating balloon from 11595776 to
11388608
virsh # dominfo 2
Id: 2
Name: centos_jt
UUID: bc25a6c4-ba34-a593-47c7-6372999946d6
OS Type: hvm
State: running
CPU(s): 1
CPU time: 53.0s
Max memory: 12582912 KiB
Used memory: 11388608 KiB
Persistent: yes
Autostart: disable
Managed save: no
Security model: none
Security DOI: 0
virsh # dommemstat 2
actual 3000000
rss 599036
4) Restart vm with 4GB of Current and Max (4194304)
2013-03-22 21:20:58.894+0000: 23182: debug : qemuMonitorSetBalloon:1690 :
mon=0x7f3d643eb5a0 newmem=4194304
2013-03-22 21:20:58.894+0000: 23182: debug : virJSONValueToString:1133 :
result={"execute":"balloon","arguments":{"value":4294967296},"id":"libvirt-6"}
2013-03-22 21:20:58.894+0000: 23182: debug :
qemuMonitorJSONCommandWithFd:265 : Send command
'{"execute":"balloon","arguments":{"value":4294967296},"id":"libvirt-6"}'
for write with FD -1
2013-03-22 21:20:58.894+0000: 23182: debug : qemuMonitorSend:903 :
QEMU_MONITOR_SEND_MSG: mon=0x7f3d643eb5a0
msg={"execute":"balloon","arguments":{"value":4294967296},"id":"libvirt-6"}
2013-03-22 21:20:58.894+0000: 23179: debug : qemuMonitorIOWrite:461 :
QEMU_MONITOR_IO_WRITE: mon=0x7f3d643eb5a0
buf={"execute":"balloon","arguments":{"value":4294967296},"id":"libvirt-6"}
virsh # dominfo 3
Id: 3
Name: centos_jt
UUID: bc25a6c4-ba34-a593-47c7-6372999946d6
OS Type: hvm
State: running
CPU(s): 1
CPU time: 15.4s
Max memory: 4194304 KiB
Used memory: 4194304 KiB
Persistent: yes
Autostart: disable
Managed save: no
Security model: none
Security DOI: 0
virsh # dommemstat 3
actual 4194304
rss 431384
5) reduce ram to 1GB
virsh # setmem 3 --live --config --size 1048576
2013-03-22 21:26:08.783+0000: 23183: debug : qemuMonitorSetBalloon:1690 :
mon=0x7f3d643eb5a0 newmem=1048576
2013-03-22 21:26:08.783+0000: 23183: debug : virJSONValueToString:1133 :
result={"execute":"balloon","arguments":{"value":1073741824},"id":"libvirt-11"}
2013-03-22 21:26:08.783+0000: 23183: debug :
qemuMonitorJSONCommandWithFd:265 : Send command
'{"execute":"balloon","arguments":{"value":1073741824},"id":"libvirt-11"}'
for write with FD -1
2013-03-22 21:26:08.783+0000: 23183: debug : qemuMonitorSend:903 :
QEMU_MONITOR_SEND_MSG: mon=0x7f3d643eb5a0
msg={"execute":"balloon","arguments":{"value":1073741824},"id":"libvirt-11"}
2013-03-22 21:26:08.784+0000: 23179: debug : qemuMonitorIOWrite:461 :
QEMU_MONITOR_IO_WRITE: mon=0x7f3d643eb5a0
buf={"execute":"balloon","arguments":{"value":1073741824},"id":"libvirt-11"}
2013-03-22 21:26:08.789+0000: 23179: debug : qemuMonitorIOProcess:353 :
QEMU_MONITOR_IO_PROCESS: mon=0x7f3d643eb5a0 buf={"timestamp": {"seconds":
1363987568, "microseconds": 789570}, "event": "BALLOON_CHANGE", "data":
{"actual": 4293918720}}
2013-03-22 21:26:08.789+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:152 : Line [{"timestamp": {"seconds":
1363987568, "microseconds": 789570}, "event": "BALLOON_CHANGE", "data":
{"actual": 4293918720}}]
2013-03-22 21:26:08.789+0000: 23179: debug : virJSONValueFromString:975 :
string={"timestamp": {"seconds": 1363987568, "microseconds": 789570},
"event": "BALLOON_CHANGE", "data": {"actual": 4293918720}}
2013-03-22 21:26:08.789+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:167 : QEMU_MONITOR_RECV_EVENT:
mon=0x7f3d643eb5a0 event={"timestamp": {"seconds": 1363987568,
"microseconds": 789570}, "event": "BALLOON_CHANGE", "data": {"actual":
4293918720}}
2013-03-22 21:26:08.789+0000: 23179: debug :
qemuMonitorJSONIOProcessEvent:138 : handle BALLOON_CHANGE handler=0x4b4de0
data=0x1686360
2013-03-22 21:26:08.789+0000: 23179: debug :
qemuMonitorEmitBalloonChange:1151 : mon=0x7f3d643eb5a0
2013-03-22 21:26:08.789+0000: 23179: debug :
qemuProcessHandleBalloonChange:1248 : Updating balloon from 4194304 to
4193280 kb
2013-03-22 21:26:09.789+0000: 23179: debug : qemuMonitorIOProcess:353 :
QEMU_MONITOR_IO_PROCESS: mon=0x7f3d643eb5a0 buf={"timestamp": {"seconds":
1363987569, "microseconds": 408889}, "event": "BALLOON_CHANGE", "data":
{"actual": 1073741824}}
2013-03-22 21:26:09.789+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:152 : Line [{"timestamp": {"seconds":
1363987569, "microseconds": 408889}, "event": "BALLOON_CHANGE", "data":
{"actual": 1073741824}}]
2013-03-22 21:26:09.789+0000: 23179: debug : virJSONValueFromString:975 :
string={"timestamp": {"seconds": 1363987569, "microseconds": 408889},
"event": "BALLOON_CHANGE", "data": {"actual": 1073741824}}
2013-03-22 21:26:09.789+0000: 23179: debug :
qemuMonitorJSONIOProcessLine:167 : QEMU_MONITOR_RECV_EVENT:
mon=0x7f3d643eb5a0 event={"timestamp": {"seconds": 1363987569,
"microseconds": 408889}, "event": "BALLOON_CHANGE", "data": {"actual":
1073741824}}
2013-03-22 21:26:09.789+0000: 23179: debug :
qemuMonitorJSONIOProcessEvent:138 : handle BALLOON_CHANGE handler=0x4b4de0
data=0x16826e0
2013-03-22 21:26:09.789+0000: 23179: debug :
qemuMonitorEmitBalloonChange:1151 : mon=0x7f3d643eb5a0
2013-03-22 21:26:09.789+0000: 23179: debug :
qemuProcessHandleBalloonChange:1248 : Updating balloon from 4193280 to
1048576 kb
virsh # dominfo 3
Id: 3
Name: centos_jt
UUID: bc25a6c4-ba34-a593-47c7-6372999946d6
OS Type: hvm
State: running
CPU(s): 1
CPU time: 28.6s
Max memory: 4194304 KiB
Used memory: 1048576 KiB
Persistent: yes
Autostart: disable
Managed save: no
Security model: none
Security DOI: 0
virsh # dommemstat 3
actual 1048576
rss 411740
11 years, 6 months
[libvirt] [RFC] New CPU hotplug APIs
by Peter Krempa
Hi upstream,
I'd like to discuss the design of CPU modification related APIs before I
start working on them.
Qemu recently added support for modification of the state of the cpu
using the guest agent and is also doing work on hot plug of cpus and
possibly even hot unplug.
This stuff will require us to introduce new APIs to take full advantage
of the new code for qemu.
I'm imagining adding 3 new API functions: 1 universal getter function
and 2 specific setters: one for agent based modifications and one for
classic (ACPI) cpu hotplug.
1) The getter function:
int
virDomainGetVCPUMap(virDomainPtr dom,
const char **cpumap,
unsigned int flags);
With no flags, this function would return the map of online CPUs in the
guest.
The flags will allow us then to do:
VIR_DOMAIN_VCPU_MAP_AGENT_ONLINE - map of online cpus as the guest agent
sees it
VIR_DOMAIN_VCPU_MAP_AGENT_OFFLINABLE - map of online cpus that can be
turned off
VIR_DOMAIN_VCPU_MAP_AGENT_ONLINABLE - map of offline cpus that can be
turned on
VIR_DOMAIN_VCPU_MAP_AGENT_POSSIBLE - all vcpus as the guest agent sees them
(_AGENT_OFFLINE probably isn't useful
And similarly for offline processors:
VIR_DOMAIN_VCPU_MAP_ONLINE
VIR_DOMAIN_VCPU_MAP_ONLINABLE
VIR_DOMAIN_VCPU_MAP_POSSIBLE
(no idea if offlinable makes sense here)
The universal nature of this function would be documented right away and
would save us having separate getters for agent based hotplug and
classic one.
The returned map would be automatically allocated and the length of it
returned as the return value.
This getter will allow us representing (possibly) sparse allocation of
the cpu IDs.
2) Setters
int
virDomainSetVCPUState(virDomainPtr dom,
int id,
bool state,
unsigned int flags);
for classic CPU hotplug and:
virDomainSetGuestVCPUState(virDomainPtr dom,
int id,
bool state,
unsigned int flags);
for agent based cpu offlining.
This will represent the setter functions with similar semantics. I've
gone for two to absolutely differentiate the agent based stuff from the
classic one, but they could be merged into a single one with appropriate
flags).
These will allow modification of state of single CPUs so that errors can
be handled gracefully. The id corresponds to position of the bit in the
cpumap requested by the getter func described above.
Thanks in advance for your input on this design stuff.
Peter
11 years, 6 months
[libvirt] [PATCH qom-cpu 0/9] x86: feature words array (v11) + "feature-words" property
by Eduardo Habkost
This series includes the previous "replace cpuid_*features fields with a feature
word array" series.
The first 4 patches already have a Reviewed-by from Igor, they correspond to v10
plus a small indent fix requested by him.
As the cpuid_*features series was holding my "feature-words"/"filtered-features"
series (previously sent as RFC), I am now sending both as a single series, to
try to get "feature-words"/"filtered-features" some attention and try to get it
included in 1.5.
The "feature-words"/"filtered-features" mechanism is very important for libvirt,
to allow it to ensure the guest is getting the required set of CPU features, as
configured by the user.
Eduardo Habkost (9):
target-i386: cleanup: Group together level, xlevel, xlevel2 fields
target-i386/kvm.c: Code formatting changes
target-i386/cpu.c: Break lines so they don't get too long
target-i386: Replace cpuid_*features fields with a feature word array
target-i386: Add ECX information to FeatureWordInfo
target-i386: Add "feature-words" property
target-i386: Use FeatureWord loop on filter_features_for_kvm()
target-i386: Introduce X86CPU.filtered_features field
target-i386: Add "filtered-features" property to X86CPU
.gitignore | 2 +
Makefile.objs | 7 +-
bsd-user/elfload.c | 2 +-
bsd-user/main.c | 4 +-
hw/i386/kvm/clock.c | 2 +-
linux-user/elfload.c | 2 +-
linux-user/main.c | 4 +-
qapi-schema.json | 31 +++
target-i386/cpu-qom.h | 3 +
target-i386/cpu.c | 501 +++++++++++++++++++++++++++++-----------------
target-i386/cpu.h | 15 +-
target-i386/helper.c | 4 +-
target-i386/kvm.c | 5 +-
target-i386/misc_helper.c | 14 +-
target-i386/translate.c | 10 +-
15 files changed, 385 insertions(+), 221 deletions(-)
--
1.8.1.4
11 years, 6 months
[libvirt] [PATCH-v4.2] Support for static routes on a virtual bridge
by Gene Czarcinski
network: static route support for <network>
This patch adds the <route> subelement of <network> to define a static
route. the address and prefix (or netmask) attribute identify the
destination network, and the gateway attribute specifies the next hop
address (which must be directly reachable from the containing
<network>) which is to receive the packets destined for
"address/(prefix|netmask)".
Tests are done to validate that the input definitions are
correct. For example, for a static route ip definition,
the address must be a network address and not a host address.
Additional checks are added to ensure that the specified gateway
is directly reachable via a network defined on this bridge.
Whan a static route is added to a bridge, there is a slight
possibility that the gateway address will be incorrect. If
this is handled as an error, that bridge becomes unusable and
can only be recovered by rebooting. If the error is
ignored, then that network can be destroyed and the network
definition file edited to correct the problem. Unfortunately,
the error message only appears in syslog. However, with
the checks performed when the network definition file is parsed,
it is unlikely that this condition will ever occur.
Handling of errors in this manner is consistent with other uses
of the CommandRun interface.
The command used is of the following form:
ip route add <address>/<prefix> via <gateway> dev <virbr-bridge> \
proto static metric 1
While family='ipv4' address='0.0.0.0' netmask='0.0.0.0' or prefix='0' is
supported and does work, the same cannot be said for ipv6. Therefore,
if address='::' prefix='0' is specified for family='ipv6' an error
message is issued stating that this is not currently supported.
.
Signed-off-by: Gene Czarcinski <gene(a)czarc.net>
---
docs/formatnetwork.html.in | 71 +++++
docs/schemas/network.rng | 19 ++
src/conf/network_conf.c | 318 ++++++++++++++++++++-
src/conf/network_conf.h | 22 ++
src/libvirt_private.syms | 1 +
src/network/bridge_driver.c | 78 +++++
src/util/virnetdev.c | 44 +++
src/util/virnetdev.h | 5 +
.../networkxml2xmlin/dhcp6host-routed-network.xml | 2 +
.../networkxml2xmlout/dhcp6host-routed-network.xml | 2 +
10 files changed, 561 insertions(+), 1 deletion(-)
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 4dd0415..15dce3a 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -529,6 +529,50 @@
starting.
</p>
+ <h5><a name="elementsStaticroute">Static Routes</a></h5>
+ <p>
+ Static route definitions are used to provide routing
+ information to the virtualization host for networks which are not
+ defined as a network on one of the virtual bridges so that such
+ networks can be reachable from the virtualization
+ host <span class="since">Since 1.0.5</span>.
+ </p>
+
+ <p>
+ As shown in <a href="formatnetwork.html#examplesNoGateway">this example</a>,
+ it is possible to define a virtual bridge interface with no
+ IPv4 or IPv6 networks. Such interfaces are useful in supporting
+ networks which have no visibility or direct connectivity with the
+ virtualization host, but can be used to support
+ virtual networks which only have guest connectivity. A guest
+ with connectivity to the guest-only network and another network
+ that is directly reachable from the host can act as a gateway between the
+ networks. A static route added to the "visible" network definition
+ provides the routing information so that IP packets can be sent
+ from the virtualization host to guests on the hidden network.
+ </p>
+
+ <p>
+ Here is a fragment of a definition which shows the static
+ route specification as well as the IPv4 and IPv6 definitions
+ for network addresses which are referred to in the
+ <code>gateway</code> gateway address specifications.
+ </p>
+
+ <pre>
+ ...
+ <ip address="192.168.122.1" netmask="255.255.255.0">
+ <dhcp>
+ <range start="192.168.122.128" end="192.168.122.254" />
+ </dhcp>
+ </ip>
+ <route address="192.168.222.0" prefix="24" gateway="192.168.122.2" />
+ <ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" />
+ <route family="ipv6" address="2001:db8:ca2:3::" prefix="64" gateway="2001:db8:ca2:2::2">
+ </route>
+ ...
+ </pre>
+
<h3><a name="elementsAddress">Addressing</a></h3>
<p>
@@ -560,6 +604,7 @@
</dhcp>
</ip>
<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" />
+ <route family="ipv6" address="2001:db9:ca1:1::" prefix="64" gateway="2001:db8:ca2:2::2" />
</network></pre>
<dl>
@@ -809,6 +854,32 @@
</ip>
</network></pre>
+ <p>
+ Below is yet another IPv6 variation. This variation has only IPv6
+ defined with DHCPv6 on the primary IPv6 network. A static link
+ if defined for a second IPv6 network which will not be visable on
+ the bridge interface but will have a static route defined for this
+ network via the specified gateway. Note that the gateway address
+ must be directly reachable via (on the same subnet as) one of the
+ <ip> addresses defined for this <network>.
+ <span class="since">Since 1.0.5</span>
+ </p>
+
+ <pre>
+ <network>
+ <name>net7</name>
+ <bridge name="virbr7" />
+ <forward mode="route"/>
+ <ip family="ipv6" address="2001:db8:ca2:7::1" prefix="64" >
+ <dhcp>
+ <range start="2001:db8:ca2:7::100" end="2001:db8:ca2::1ff" />
+ <host id="0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63" name="lucas" ip="2001:db8:ca2:2:3::4" />
+ </dhcp>
+ </ip>
+ <route family="ipv6" address="2001:db8:ca2:8::" prefix="64" gateway="2001:db8:ca2:7::4" >
+ </route>
+ </network></pre>
+
<h3><a name="examplesPrivate">Isolated network config</a></h3>
<p>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 6c3fae2..1106b76 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -305,6 +305,25 @@
</optional>
</element>
</zeroOrMore>
+ <!-- <route> element -->
+ <zeroOrMore>
+ <!-- The (static) route element specifies a network address and gateway
+ address to access that network. Bother the network address and
+ the gateway address must be specified. -->
+ <element name="route">
+ <optional>
+ <attribute name="family"><ref name="addr-family"/></attribute>
+ </optional>
+ <attribute name="address"><ref name="ipAddr"/></attribute>
+ <optional>
+ <choice>
+ <attribute name="netmask"><ref name="ipv4Addr"/></attribute>
+ <attribute name="prefix"><ref name="ipPrefix"/></attribute>
+ </choice>
+ </optional>
+ <attribute name="gateway"><ref name="ipAddr"/></attribute>
+ </element>
+ </zeroOrMore>
</interleave>
</element>
</define>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index 1c88547..93ac535 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -137,6 +137,12 @@ virNetworkIpDefClear(virNetworkIpDefPtr def)
}
static void
+virNetworkRouteDefClear(virNetworkRouteDefPtr def)
+{
+ VIR_FREE(def->family);
+}
+
+static void
virNetworkDNSTxtDefClear(virNetworkDNSTxtDefPtr def)
{
VIR_FREE(def->name);
@@ -215,6 +221,11 @@ virNetworkDefFree(virNetworkDefPtr def)
}
VIR_FREE(def->ips);
+ for (ii = 0 ; ii < def->nroutes && def->routes ; ii++) {
+ virNetworkRouteDefClear(&def->routes[ii]);
+ }
+ VIR_FREE(def->routes);
+
for (ii = 0; ii < def->nPortGroups && def->portGroups; ii++) {
virPortGroupDefClear(&def->portGroups[ii]);
}
@@ -1264,6 +1275,198 @@ cleanup:
}
static int
+virNetworkRouteDefParseXML(const char *networkName,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ virNetworkRouteDefPtr def)
+{
+ /*
+ * virNetworkRouteDef object is already allocated as part
+ * of an array. On failure clear: it out, but don't free it.
+ */
+
+ xmlNodePtr save;
+ char *address = NULL, *netmask = NULL;
+ char *gateway = NULL;
+ unsigned long prefix = 0;
+ int result = -1;
+ int prefixRc;
+ virSocketAddr testAddr;
+
+ save = ctxt->node;
+ ctxt->node = node;
+
+ /* grab raw data from XML */
+ def->family = virXPathString("string(./@family)", ctxt);
+
+ address = virXPathString("string(./@address)", ctxt);
+
+ netmask = virXPathString("string(./@netmask)", ctxt);
+
+ gateway = virXPathString("string(./@gateway)", ctxt);
+
+ prefixRc = virXPathULong("string(./@prefix)", ctxt, &prefix);
+ if (prefixRc == -2) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid prefix specified in route definition '%s'"),
+ networkName);
+ goto cleanup;
+ }
+ if (!(prefixRc < 0))
+ def->has_prefix = true;
+ else
+ def->has_prefix = false;
+
+ /* Note: both network and gateway addresses must be specified */
+
+ if (!address) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("A network address must be specified in route definition '%s'"),
+ networkName);
+ goto cleanup;
+ }
+
+ if (!gateway) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("A gateway address must be specified in route definition '%s'"),
+ networkName);
+ goto cleanup;
+ }
+
+ if (virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Bad network address '%s' in route definition '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+
+ if (virSocketAddrParse(&def->gateway, gateway, AF_UNSPEC) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Bad gateway address '%s' in route definition '%s'"),
+ gateway, networkName);
+ goto cleanup;
+ }
+
+ /* validate network address, etc. for each family */
+ if ((def->family == NULL) || (STREQ(def->family, "ipv4"))) {
+ if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) ||
+ VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_UNSPEC))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("%s family specified for non-IPv4 address '%s' in route definition '%s'"),
+ def->family == NULL? "no" : "ipv4", address, networkName);
+ goto cleanup;
+ }
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("%s family specified for non-IPv4 gateway address '%s' in route definition '%s'"),
+ def->family == NULL? "no" : "ipv4", address, networkName);
+ goto cleanup;
+ }
+ if (netmask) {
+ if (virSocketAddrParse(&def->netmask, netmask, AF_UNSPEC) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Bad netmask address '%s' in route definition '%s'"),
+ netmask, networkName);
+ goto cleanup;
+ }
+
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("network '%s' has invalid netmask '%s' for address '%s' (both must be IPv4)"),
+ networkName, netmask, address);
+ goto cleanup;
+ }
+ if (def->has_prefix) {
+ /* can't have both netmask and prefix at the same time */
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("route definition '%s' cannot have both a prefix and a netmask"),
+ networkName);
+ goto cleanup;
+ }
+ }
+ else {
+ if (def->has_prefix)
+ def->prefix = prefix;
+ }
+ if (def->prefix > 32) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Invalid IPv4 prefix '%lu' for '%s' specified in route definition '%s'"),
+ def->prefix, def->family == NULL? "no" : "ipv4", networkName);
+ goto cleanup;
+ }
+ } else if (STREQ(def->family, "ipv6")) {
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("ipv6 family specified for non-IPv6 address '%s' in route definition '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+ if (netmask) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("specifying netmask invalid for IPv6 address '%s' in route definition '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET6)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("ipv6 specified for non-IPv6 gateway address '%s' in route definition '%s'"),
+ gateway, networkName);
+ goto cleanup;
+ }
+ if (def->has_prefix)
+ def->prefix = prefix;
+
+ if (def->prefix > 128) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("Invalid IPv6 prefix '%lu' for '%s' specified in route definition '%s'"),
+ def->prefix, def->family, networkName);
+ goto cleanup;
+ }
+ } else {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Unrecognized family '%s' in definition of route definition '%s'"),
+ def->family, networkName);
+ goto cleanup;
+ }
+
+ /* make sure the address is a network address */
+ if (netmask) {
+ if (virSocketAddrMask(&def->address, &def->netmask, &testAddr) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("error converting address '%s' with netmask '%s' to network-address in route definition '%s'"),
+ address, netmask, networkName);
+ goto cleanup;
+ }
+ } else {
+ if (virSocketAddrMaskByPrefix(&def->address, def->prefix, &testAddr) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("error converting address '%s' with prefix=%u to network-address in route definition '%s'"),
+ address, def->prefix, networkName);
+ goto cleanup;
+ }
+ }
+ if (!virSocketAddrEqual(&def->address, &testAddr)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("address '%s' in <route> definition of network '%s' is not a network address"),
+ address, networkName);
+ goto cleanup;
+ }
+
+ result = 0;
+
+cleanup:
+ if (result < 0) {
+ virNetworkRouteDefClear(def);
+ }
+ VIR_FREE(address);
+ VIR_FREE(netmask);
+ VIR_FREE(gateway);
+
+ ctxt->node = save;
+ return result;
+}
+
+static int
virNetworkPortGroupParseXML(virPortGroupDefPtr def,
xmlNodePtr node,
xmlXPathContextPtr ctxt)
@@ -1661,8 +1864,9 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
char *tmp;
char *stp = NULL;
xmlNodePtr *ipNodes = NULL;
+ xmlNodePtr *routeNodes = NULL;
xmlNodePtr *portGroupNodes = NULL;
- int nIps, nPortGroups;
+ int nIps, nPortGroups, nRoutes;
xmlNodePtr dnsNode = NULL;
xmlNodePtr virtPortNode = NULL;
xmlNodePtr forwardNode = NULL;
@@ -1816,6 +2020,70 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
}
VIR_FREE(ipNodes);
+ nRoutes = virXPathNodeSet("./route", ctxt, &routeNodes);
+ if (nRoutes < 0)
+ goto error;
+
+ if (nRoutes > 0) {
+ int ii;
+
+ /* allocate array to hold all the route definitions */
+ if (VIR_ALLOC_N(def->routes, nRoutes) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ /* parse each definition */
+ for (ii = 0; ii < nRoutes; ii++) {
+ int ret = virNetworkRouteDefParseXML(def->name, routeNodes[ii],
+ ctxt, &def->routes[ii]);
+ if (ret < 0)
+ goto error;
+ def->nroutes++;
+ }
+
+ /* now validate the correctness of any static route gateways specified
+ *
+ * note: the parameters within each definition are varified/assumed valid;
+ * the question being asked and answered here is if the specified gateway
+ * is directly reachable from this bridge.
+ */
+ nRoutes = def->nroutes;
+ nIps = def->nips;
+ for (ii = 0; ii < nRoutes; ii++) {
+ int jj;
+ virSocketAddr testAddr, testGw;
+ bool addrMatch;
+ virNetworkRouteDefPtr gwdef = &def->routes[ii];
+ if (VIR_SOCKET_ADDR_VALID(&gwdef->gateway)) {
+ addrMatch = false;
+ for (jj = 0; jj < nIps; jj++) {
+ virNetworkIpDefPtr def2 = &def->ips[jj];
+ if (VIR_SOCKET_ADDR_FAMILY(&gwdef->gateway)
+ != VIR_SOCKET_ADDR_FAMILY(&def2->address)) {
+ continue;
+ }
+ int prefix = virNetworkIpDefPrefix(def2);
+ virSocketAddrMaskByPrefix(&def2->address, prefix, &testAddr);
+ virSocketAddrMaskByPrefix(&gwdef->gateway, prefix, &testGw);
+ if (VIR_SOCKET_ADDR_VALID(&testAddr) &&
+ VIR_SOCKET_ADDR_VALID(&testGw) &&
+ virSocketAddrEqual(&testAddr, &testGw)) {
+ addrMatch = true;
+ break;
+ }
+ }
+ if (!addrMatch) {
+ char *gw = virSocketAddrFormat(&gwdef->gateway);
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unreachable static route gateway '%s' specified for network '%s'"),
+ gw, def->name);
+ VIR_FREE(gw);
+ goto error;
+ }
+ }
+ }
+ }
+
forwardNode = virXPathNode("./forward", ctxt);
if (forwardNode &&
virNetworkForwardDefParseXML(def->name, forwardNode, ctxt, &def->forward) < 0) {
@@ -1888,6 +2156,7 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
return def;
error:
+ VIR_FREE(routeNodes);
VIR_FREE(stp);
virNetworkDefFree(def);
VIR_FREE(ipNodes);
@@ -2113,6 +2382,48 @@ error:
}
static int
+virNetworkRouteDefFormat(virBufferPtr buf,
+ const virNetworkRouteDefPtr def)
+{
+ int result = -1;
+
+ virBufferAddLit(buf, "<route");
+
+ if (def->family) {
+ virBufferAsprintf(buf, " family='%s'", def->family);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&def->address)) {
+ char *addr = virSocketAddrFormat(&def->address);
+ if (!addr)
+ goto error;
+ virBufferAsprintf(buf, " address='%s'", addr);
+ VIR_FREE(addr);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
+ char *addr = virSocketAddrFormat(&def->netmask);
+ if (!addr)
+ goto error;
+ virBufferAsprintf(buf, " netmask='%s'", addr);
+ VIR_FREE(addr);
+ }
+ if (def->has_prefix) {
+ virBufferAsprintf(buf," prefix='%u'", def->prefix);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&def->gateway)) {
+ char *addr = virSocketAddrFormat(&def->gateway);
+ if (!addr)
+ goto error;
+ virBufferAsprintf(buf, " gateway='%s'", addr);
+ VIR_FREE(addr);
+ }
+ virBufferAddLit(buf, "/>\n");
+
+ result = 0;
+error:
+ return result;
+}
+
+static int
virPortGroupDefFormat(virBufferPtr buf,
const virPortGroupDefPtr def)
{
@@ -2310,6 +2621,11 @@ virNetworkDefFormatInternal(virBufferPtr buf,
goto error;
}
+ for (ii = 0; ii < def->nroutes; ii++) {
+ if (virNetworkRouteDefFormat(buf, &def->routes[ii]) < 0)
+ goto error;
+ }
+
if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
goto error;
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 163478c..7be9bd6 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -135,6 +135,25 @@ struct _virNetworkIpDef {
virSocketAddr bootserver;
};
+typedef struct _virNetworkRouteDef virNetworkRouteDef;
+typedef virNetworkRouteDef *virNetworkRouteDefPtr;
+struct _virNetworkRouteDef {
+ char *family; /* ipv4 or ipv6 - default is ipv4 */
+ virSocketAddr address; /* Routed Network IP address */
+
+ /* One or the other of the following two will be used for a given
+ * Network address, but never both. The parser guarantees this.
+ * The virSocketAddrGetIpPrefix() can be used to get a
+ * valid prefix.
+ */
+ unsigned int prefix; /* ipv6 - only prefix allowed */
+ virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
+
+ virSocketAddr gateway; /* gateway IP address for ip-route */
+
+ bool has_prefix; /* prefix= was specified */
+ };
+
typedef struct _virNetworkForwardIfDef virNetworkForwardIfDef;
typedef virNetworkForwardIfDef *virNetworkForwardIfDefPtr;
struct _virNetworkForwardIfDef {
@@ -209,6 +228,9 @@ struct _virNetworkDef {
size_t nips;
virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */
+ size_t nroutes;
+ virNetworkRouteDefPtr routes; /* ptr to array of static routes on this interface */
+
virNetworkDNSDef dns; /* dns related configuration */
virNetDevVPortProfilePtr virtPortProfile;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 882b77d..09ad053 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1478,6 +1478,7 @@ virNetDevReplaceMacAddress;
virNetDevReplaceNetConfig;
virNetDevRestoreMacAddress;
virNetDevRestoreNetConfig;
+virNetDevSetGateway;
virNetDevSetIPv4Address;
virNetDevSetMAC;
virNetDevSetMTU;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 53db5d5..37ab386 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2370,6 +2370,7 @@ out:
return ret;
}
+/* add an IP address to a bridge */
static int
networkAddAddrToBridge(virNetworkObjPtr network,
virNetworkIpDefPtr ipdef)
@@ -2390,6 +2391,69 @@ networkAddAddrToBridge(virNetworkObjPtr network,
return 0;
}
+/* add an IP (static) route to a bridge */
+static int
+networkAddRouteToBridge(virNetworkObjPtr network,
+ virNetworkRouteDefPtr routedef)
+{
+ bool done = false;
+ int prefix = 0;
+ virSocketAddrPtr addr = &routedef->address;
+ virSocketAddrPtr mask = &routedef->netmask;
+
+ if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET)) {
+ long val4 = ntohl(addr->data.inet4.sin_addr.s_addr);
+ long msk4 = -1;
+ if (VIR_SOCKET_ADDR_IS_FAMILY(mask, AF_INET)) {
+ msk4 = ntohl(mask->data.inet4.sin_addr.s_addr);
+ }
+ if (msk4 == -1) {
+ if (val4 == 0 && routedef->prefix == 0)
+ done = true;
+ } else {
+ if (val4 == 0 && msk4 == 0)
+ done = true;
+ }
+ }
+ else if (VIR_SOCKET_ADDR_IS_FAMILY(addr, AF_INET6)) {
+ int i, val6 = 0;
+ for (i = 0;i < 4;i++) {
+ val6 += ((addr->data.inet6.sin6_addr.s6_addr[2 * i] << 8) |
+ addr->data.inet6.sin6_addr.s6_addr[2 * i + 1]);
+ }
+ if (val6 == 0 && routedef->prefix == 0) {
+ char *addr = virSocketAddrFormat(&routedef->address);
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("bridge '%s' has prefix=0 for address='%s' which is not supported"),
+ network->def->bridge, addr);
+ VIR_FREE(addr);
+ return -1;
+ }
+ }
+
+ if (done) {
+ prefix = 0;
+ } else {
+ prefix = virSocketAddrGetIpPrefix(&routedef->address,
+ &routedef->netmask,
+ routedef->prefix);
+
+ if (prefix < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("bridge '%s' has an invalid netmask or IP address for route definition"),
+ network->def->bridge);
+ return -1;
+ }
+ }
+
+ if (virNetDevSetGateway(network->def->bridge,
+ &routedef->address,
+ prefix,
+ &routedef->gateway) < 0)
+ return -1;
+ return 0;
+}
+
static int
networkStartNetworkVirtual(struct network_driver *driver,
virNetworkObjPtr network)
@@ -2398,6 +2462,7 @@ networkStartNetworkVirtual(struct network_driver *driver,
bool v4present = false, v6present = false;
virErrorPtr save_err = NULL;
virNetworkIpDefPtr ipdef;
+ virNetworkRouteDefPtr routedef;
char *macTapIfName = NULL;
int tapfd = -1;
@@ -2474,6 +2539,19 @@ networkStartNetworkVirtual(struct network_driver *driver,
if (virNetDevSetOnline(network->def->bridge, 1) < 0)
goto err2;
+ for (ii = 0; ii < network->def->nroutes; ii++) {
+ routedef = &network->def->routes[ii];
+ /* Add the IP route to the bridge */
+ /* ignore errors, error msg will be generated */
+ /* but libvirt will not know and net-destroy will work. */
+ if (VIR_SOCKET_ADDR_VALID(&routedef->gateway)) {
+ if (networkAddRouteToBridge(network, routedef) < 0) {
+ /* an error occurred adding the static route */
+ continue; /* for now, do nothing */
+ }
+ }
+ }
+
/* If forward.type != NONE, turn on global IP forwarding */
if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE &&
networkEnableIpForwarding(v4present, v6present) < 0) {
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index 7ffaac1..69a8830 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -769,6 +769,50 @@ cleanup:
}
/**
+ * virNetDevSetGateway:
+ * @ifname: the interface name
+ * @addr: the IP network address (IPv4 or IPv6)
+ * @prefix: number of 1 bits in the netmask
+ * @gateway: via address for route (same as @addr)
+ *
+ * Add a route for a network IP address to an interface. This function
+ * *does not* remove any previously added IP static routes.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
+
+int virNetDevSetGateway(const char *ifname,
+ virSocketAddrPtr addr,
+ unsigned int prefix,
+ virSocketAddrPtr gateway)
+{
+ virCommandPtr cmd = NULL;
+ char *addrstr = NULL, *gatewaystr = NULL;
+ int ret = -1;
+
+ if (!(addrstr = virSocketAddrFormat(addr)))
+ goto cleanup;
+ if (!(gatewaystr = virSocketAddrFormat(gateway)))
+ goto cleanup;
+ cmd = virCommandNew(IP_PATH);
+ virCommandAddArgList(cmd, "route", "add", NULL);
+ virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
+ virCommandAddArgList(cmd, "via", gatewaystr, "dev", ifname,
+ "proto", "static", "metric", NULL);
+ virCommandAddArgFormat(cmd, "%u", 1);
+
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ ret = 0;
+cleanup:
+ VIR_FREE(addrstr);
+ VIR_FREE(gatewaystr);
+ virCommandFree(cmd);
+ return ret;
+}
+
+/**
* virNetDevClearIPv4Address:
* @ifname: the interface name
* @addr: the IP address (IPv4 or IPv6)
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index 551ea22..c8f20b1 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -42,6 +42,11 @@ int virNetDevSetIPv4Address(const char *ifname,
virSocketAddr *addr,
unsigned int prefix)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevSetGateway(const char *ifname,
+ virSocketAddrPtr addr,
+ unsigned int prefix,
+ virSocketAddrPtr gateway)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4) ATTRIBUTE_RETURN_CHECK;
int virNetDevClearIPv4Address(const char *ifname,
virSocketAddr *addr,
unsigned int prefix)
diff --git a/tests/networkxml2xmlin/dhcp6host-routed-network.xml b/tests/networkxml2xmlin/dhcp6host-routed-network.xml
index 2693d87..40f6dfe 100644
--- a/tests/networkxml2xmlin/dhcp6host-routed-network.xml
+++ b/tests/networkxml2xmlin/dhcp6host-routed-network.xml
@@ -19,4 +19,6 @@
<host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
</dhcp>
</ip>
+ <route address="192.168.222.0" netmask="255.255.255.0" gateway="192.168.122.10"/>
+ <route family="ipv6" address="2001:db8:ac10:fc00::" prefix="64" gateway="2001:db8:ac10:fd01::1:24"/>
</network>
diff --git a/tests/networkxml2xmlout/dhcp6host-routed-network.xml b/tests/networkxml2xmlout/dhcp6host-routed-network.xml
index 1d3035b..fc8666b 100644
--- a/tests/networkxml2xmlout/dhcp6host-routed-network.xml
+++ b/tests/networkxml2xmlout/dhcp6host-routed-network.xml
@@ -21,4 +21,6 @@
<host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
</dhcp>
</ip>
+ <route address='192.168.222.0' netmask='255.255.255.0' gateway='192.168.122.10'/>
+ <route family='ipv6' address='2001:db8:ac10:fc00::' prefix='64' gateway='2001:db8:ac10:fd01::1:24'/>
</network>
--
1.8.1.4
11 years, 6 months
[libvirt] [PATCH] ESX: Fix DISPATCH_FREE generation code to free all extended objects
by Ata E Husain Bohra
Python code generator "generate_source" section that handles
code generation to "free" inherited objects needs to generate
DISPATCH_FREE calls for all extended_by objects.
---
src/esx/esx_vi_generator.py | 21 ++++++++++++++++++---
1 file changed, 18 insertions(+), 3 deletions(-)
diff --git a/src/esx/esx_vi_generator.py b/src/esx/esx_vi_generator.py
index af4e7e8..7a7cf76 100755
--- a/src/esx/esx_vi_generator.py
+++ b/src/esx/esx_vi_generator.py
@@ -4,6 +4,7 @@
# esx_vi_generator.py: generates most of the SOAP type mapping code
#
# Copyright (C) 2010-2012 Matthias Bolte <matthias.bolte(a)googlemail.com>
+# Copyright (C) 2013 Ata E Husain Bohra <ata.husain(a)hotmail.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -785,9 +786,7 @@ class Object(Type):
source += "ESX_VI__TEMPLATE__DYNAMIC_FREE(%s,\n" % self.name
source += "{\n"
- for extended_by in self.extended_by:
- source += " ESX_VI__TEMPLATE__DISPATCH__FREE(%s)\n" \
- % extended_by
+ source += recurse_dispatch(self, "ESX_VI__TEMPLATE__DISPATCH__FREE")
source += "},\n"
source += "{\n"
@@ -1285,6 +1284,22 @@ class ManagedObject(Type):
+def recurse_dispatch(object, text):
+
+ source = ""
+
+ if object.extended_by is None:
+ return source
+
+ for extended_by in object.extended_by:
+ source += " %s(%s)\n" % (text, extended_by)
+ child = objects_by_name[extended_by]
+ source += recurse_dispatch(child, text)
+
+ return source
+
+
+
class Enum(Type):
FEATURE__ANY_TYPE = (1 << 1)
FEATURE__SERIALIZE = (1 << 2)
--
1.7.9.5
11 years, 6 months
[libvirt] [PATCH] util: Prevent libvirtd crash from virPCIDeviceAddressIsEqual()
by Alex Jia
GDB backtrace:
Breakpoint 1, virPCIGetVirtualFunctionIndex (pf_sysfs_device_link=0x7fc04400f470 "/sys/bus/pci/devices/0000:03:00.1", vf_sysfs_device_link=<optimized out>, vf_index=vf_index@entry=0x7fc06897b8f4)
at util/virpci.c:2107
2107 if (virPCIDeviceAddressIsEqual(vf_bdf, virt_fns[i])) {
(gdb) p *vf_bdf
$1 = {domain = 0, bus = 3, slot = 16, function = 1}
(gdb) l
2102 "virtual_functions"), pf_sysfs_device_link);
2103 goto out;
2104 }
2105
2106 for (i = 0; i < num_virt_fns; i++) {
2107 if (virPCIDeviceAddressIsEqual(vf_bdf, virt_fns[i])) {
2108 *vf_index = i;
2109 ret = 0;
2110 break;
2111 }
(gdb) p num_virt_fns
$46 = 2
(gdb) p virt_fns[0]
$48 = (virPCIDeviceAddressPtr) 0x0
(gdb) s
virPCIDeviceAddressIsEqual (bdf2=0x0, bdf1=0x7fc04400f330) at util/virpci.c:1844
1844 (bdf1->slot == bdf2->slot) &&
(gdb) s
Program received signal SIGSEGV, Segmentation fault.
RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=957416
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
src/util/virpci.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/src/util/virpci.c b/src/util/virpci.c
index 97bba74..dda044c 100644
--- a/src/util/virpci.c
+++ b/src/util/virpci.c
@@ -1897,7 +1897,8 @@ static bool
virPCIDeviceAddressIsEqual(virPCIDeviceAddressPtr bdf1,
virPCIDeviceAddressPtr bdf2)
{
- return ((bdf1->domain == bdf2->domain) &&
+ return (bdf1 && bdf2 &&
+ (bdf1->domain == bdf2->domain) &&
(bdf1->bus == bdf2->bus) &&
(bdf1->slot == bdf2->slot) &&
(bdf1->function == bdf2->function));
--
1.7.1
11 years, 6 months
[libvirt] [PATCH 0/2] Fix forgetting of transient networks on daemon restart
by Peter Krempa
Peter Krempa (2):
network: remove autostart flag from network when undefining it
network: bridge_driver: don't lose transient networks on daemon
restart
src/conf/network_conf.c | 220 +++++++++++++++++++++++++++++---------------
src/conf/network_conf.h | 10 +-
src/libvirt_private.syms | 2 +-
src/network/bridge_driver.c | 52 +++++++----
4 files changed, 185 insertions(+), 99 deletions(-)
--
1.8.1.5
11 years, 6 months
[libvirt] [libvirt-glib] object: Add "transfer none" annotation to argv parameter
by Christophe Fergeau
This makes the parameter to be passed "unowned" in Vala. This was
previously done using a vala metadata file, but it's better to do
it directly through a gtk-doc annotation, as this means the gir
file will know about this, and thus any gir-based binding can
make use of this info.
This also makes libvirt-gobject consistent with what was done
for gconfig and glib in commit 431720.
---
libvirt-gobject/libvirt-gobject-main.c | 4 ++--
vapi/LibvirtGObject-1.0.metadata | 2 --
vapi/Makefile.am | 2 +-
3 files changed, 3 insertions(+), 5 deletions(-)
delete mode 100644 vapi/LibvirtGObject-1.0.metadata
diff --git a/libvirt-gobject/libvirt-gobject-main.c b/libvirt-gobject/libvirt-gobject-main.c
index 31d2514..11ea24a 100644
--- a/libvirt-gobject/libvirt-gobject-main.c
+++ b/libvirt-gobject/libvirt-gobject-main.c
@@ -33,7 +33,7 @@
/**
* gvir_init_object:
* @argc: (inout): pointer to application's argc
- * @argv: (inout) (array length=argc) (allow-none): pointer to application's argv
+ * @argv: (inout) (array length=argc) (allow-none) (transfer none): pointer to application's argv
*/
void gvir_init_object(int *argc,
char ***argv)
@@ -58,7 +58,7 @@ static void gvir_log_handler(const gchar *log_domain G_GNUC_UNUSED,
/**
* gvir_init_object_check:
* @argc: (inout): pointer to application's argc
- * @argv: (inout) (array length=argc) (allow-none): pointer to application's argv
+ * @argv: (inout) (array length=argc) (allow-none) (transfer none): pointer to application's argv
* @err: pointer to a #GError to which a message will be posted on error
*/
gboolean gvir_init_object_check(int *argc,
diff --git a/vapi/LibvirtGObject-1.0.metadata b/vapi/LibvirtGObject-1.0.metadata
deleted file mode 100644
index 90e5197..0000000
--- a/vapi/LibvirtGObject-1.0.metadata
+++ /dev/null
@@ -1,2 +0,0 @@
-init_object.argv unowned
-init_object_check.argv unowned
diff --git a/vapi/Makefile.am b/vapi/Makefile.am
index 2ecc3e3..0154104 100644
--- a/vapi/Makefile.am
+++ b/vapi/Makefile.am
@@ -44,4 +44,4 @@ CLEANFILES = \
libvirt-gobject-1.0.vapi \
$(NULL)
-EXTRA_DIST = LibvirtGObject-1.0.metadata libvirt-gobject-1.0.deps
+EXTRA_DIST = libvirt-gobject-1.0.deps
--
1.8.1.4
11 years, 6 months