Revision 748e4b5a lib/hypervisor/hv_kvm.py
b/lib/hypervisor/hv_kvm.py | ||
---|---|---|
44 | 44 |
from ganeti import netutils |
45 | 45 |
|
46 | 46 |
|
47 |
_KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge" |
|
48 |
|
|
49 |
|
|
50 |
def _WriteNetScript(instance, nic, index): |
|
51 |
"""Write a script to connect a net interface to the proper bridge. |
|
52 |
|
|
53 |
This can be used by any qemu-type hypervisor. |
|
54 |
|
|
55 |
@type instance: L{objects.Instance} |
|
56 |
@param instance: Instance object |
|
57 |
@type nic: L{objects.NIC} |
|
58 |
@param nic: NIC object |
|
59 |
@type index: int |
|
60 |
@param index: NIC index |
|
61 |
@return: Script |
|
62 |
@rtype: string |
|
63 |
|
|
64 |
""" |
|
65 |
if instance.tags: |
|
66 |
tags = " ".join(instance.tags) |
|
67 |
else: |
|
68 |
tags = "" |
|
69 |
|
|
70 |
buf = StringIO() |
|
71 |
sw = utils.ShellWriter(buf) |
|
72 |
sw.Write("#!/bin/sh") |
|
73 |
sw.Write("# this is autogenerated by Ganeti, please do not edit") |
|
74 |
sw.Write("export PATH=$PATH:/sbin:/usr/sbin") |
|
75 |
sw.Write("export INSTANCE=%s", utils.ShellQuote(instance.name)) |
|
76 |
sw.Write("export MAC=%s", utils.ShellQuote(nic.mac)) |
|
77 |
sw.Write("export MODE=%s", |
|
78 |
utils.ShellQuote(nic.nicparams[constants.NIC_MODE])) |
|
79 |
sw.Write("export INTERFACE=\"$1\"") |
|
80 |
sw.Write("export TAGS=%s", utils.ShellQuote(tags)) |
|
81 |
|
|
82 |
if nic.ip: |
|
83 |
sw.Write("export IP=%s", utils.ShellQuote(nic.ip)) |
|
84 |
|
|
85 |
if nic.nicparams[constants.NIC_LINK]: |
|
86 |
sw.Write("export LINK=%s", |
|
87 |
utils.ShellQuote(nic.nicparams[constants.NIC_LINK])) |
|
88 |
|
|
89 |
if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED: |
|
90 |
sw.Write("export BRIDGE=%s", |
|
91 |
utils.ShellQuote(nic.nicparams[constants.NIC_LINK])) |
|
92 |
|
|
93 |
# TODO: make this configurable at ./configure time |
|
94 |
sw.Write("if [ -x %s ]; then", utils.ShellQuote(_KVM_NETWORK_SCRIPT)) |
|
95 |
sw.IncIndent() |
|
96 |
try: |
|
97 |
sw.Write("# Execute the user-specific vif file") |
|
98 |
sw.Write(_KVM_NETWORK_SCRIPT) |
|
99 |
finally: |
|
100 |
sw.DecIndent() |
|
101 |
sw.Write("else") |
|
102 |
sw.IncIndent() |
|
103 |
try: |
|
104 |
sw.Write("ifconfig $INTERFACE 0.0.0.0 up") |
|
105 |
|
|
106 |
if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED: |
|
107 |
sw.Write("# Connect the interface to the bridge") |
|
108 |
sw.Write("brctl addif $BRIDGE $INTERFACE") |
|
109 |
|
|
110 |
elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED: |
|
111 |
if not nic.ip: |
|
112 |
raise errors.HypervisorError("nic/%d is routed, but has no IP" |
|
113 |
" address" % index) |
|
114 |
|
|
115 |
sw.Write("# Route traffic targeted at the IP to the interface") |
|
116 |
if nic.nicparams[constants.NIC_LINK]: |
|
117 |
sw.Write("while ip rule del dev $INTERFACE; do :; done") |
|
118 |
sw.Write("ip rule add dev $INTERFACE table $LINK") |
|
119 |
sw.Write("ip route replace $IP table $LINK proto static" |
|
120 |
" dev $INTERFACE") |
|
121 |
else: |
|
122 |
sw.Write("ip route replace $IP proto static dev $INTERFACE") |
|
123 |
|
|
124 |
interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE" |
|
125 |
sw.Write(" if [ -d %s ]; then", interface_v4_conf) |
|
126 |
sw.IncIndent() |
|
127 |
try: |
|
128 |
sw.Write("echo 1 > %s/proxy_arp", interface_v4_conf) |
|
129 |
sw.Write("echo 1 > %s/forwarding", interface_v4_conf) |
|
130 |
finally: |
|
131 |
sw.DecIndent() |
|
132 |
sw.Write("fi") |
|
133 |
|
|
134 |
interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE" |
|
135 |
sw.Write("if [ -d %s ]; then", interface_v6_conf) |
|
136 |
sw.IncIndent() |
|
137 |
try: |
|
138 |
sw.Write("echo 1 > %s/proxy_ndp", interface_v6_conf) |
|
139 |
sw.Write("echo 1 > %s/forwarding", interface_v6_conf) |
|
140 |
finally: |
|
141 |
sw.DecIndent() |
|
142 |
sw.Write("fi") |
|
143 |
finally: |
|
144 |
sw.DecIndent() |
|
145 |
sw.Write("fi") |
|
146 |
|
|
147 |
return buf.getvalue() |
|
148 |
|
|
149 |
|
|
47 | 150 |
class KVMHypervisor(hv_base.BaseHypervisor): |
48 | 151 |
"""KVM hypervisor interface""" |
49 | 152 |
CAN_MIGRATE = True |
... | ... | |
108 | 211 |
_MIGRATION_INFO_MAX_BAD_ANSWERS = 5 |
109 | 212 |
_MIGRATION_INFO_RETRY_DELAY = 2 |
110 | 213 |
|
111 |
_KVM_NETWORK_SCRIPT = constants.SYSCONFDIR + "/ganeti/kvm-vif-bridge" |
|
112 |
|
|
113 | 214 |
ANCILLARY_FILES = [ |
114 | 215 |
_KVM_NETWORK_SCRIPT, |
115 | 216 |
] |
... | ... | |
298 | 399 |
else: |
299 | 400 |
raise |
300 | 401 |
|
301 |
def _WriteNetScript(self, instance, seq, nic): |
|
402 |
@staticmethod |
|
403 |
def _WriteNetScriptFile(instance, seq, nic): |
|
302 | 404 |
"""Write a script to connect a net interface to the proper bridge. |
303 | 405 |
|
304 | 406 |
This can be used by any qemu-type hypervisor. |
... | ... | |
313 | 415 |
@rtype: string |
314 | 416 |
|
315 | 417 |
""" |
316 |
script = StringIO() |
|
317 |
script.write("#!/bin/sh\n") |
|
318 |
script.write("# this is autogenerated by Ganeti, please do not edit\n#\n") |
|
319 |
script.write("PATH=$PATH:/sbin:/usr/sbin\n") |
|
320 |
script.write("export INSTANCE=%s\n" % instance.name) |
|
321 |
script.write("export MAC=%s\n" % nic.mac) |
|
322 |
if nic.ip: |
|
323 |
script.write("export IP=%s\n" % nic.ip) |
|
324 |
script.write("export MODE=%s\n" % nic.nicparams[constants.NIC_MODE]) |
|
325 |
if nic.nicparams[constants.NIC_LINK]: |
|
326 |
script.write("export LINK=%s\n" % nic.nicparams[constants.NIC_LINK]) |
|
327 |
if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED: |
|
328 |
script.write("export BRIDGE=%s\n" % nic.nicparams[constants.NIC_LINK]) |
|
329 |
script.write("export INTERFACE=$1\n") |
|
330 |
if instance.tags: |
|
331 |
script.write("export TAGS=\"%s\"\n" % " ".join(instance.tags)) |
|
332 |
# TODO: make this configurable at ./configure time |
|
333 |
script.write("if [ -x '%s' ]; then\n" % self._KVM_NETWORK_SCRIPT) |
|
334 |
script.write(" # Execute the user-specific vif file\n") |
|
335 |
script.write(" %s\n" % self._KVM_NETWORK_SCRIPT) |
|
336 |
script.write("else\n") |
|
337 |
script.write(" ifconfig $INTERFACE 0.0.0.0 up\n") |
|
338 |
if nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_BRIDGED: |
|
339 |
script.write(" # Connect the interface to the bridge\n") |
|
340 |
script.write(" brctl addif $BRIDGE $INTERFACE\n") |
|
341 |
elif nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED: |
|
342 |
if not nic.ip: |
|
343 |
raise errors.HypervisorError("nic/%d is routed, but has no ip." % seq) |
|
344 |
script.write(" # Route traffic targeted at the IP to the interface\n") |
|
345 |
if nic.nicparams[constants.NIC_LINK]: |
|
346 |
script.write(" while ip rule del dev $INTERFACE; do :; done\n") |
|
347 |
script.write(" ip rule add dev $INTERFACE table $LINK\n") |
|
348 |
script.write(" ip route replace $IP table $LINK proto static" |
|
349 |
" dev $INTERFACE\n") |
|
350 |
else: |
|
351 |
script.write(" ip route replace $IP proto static" |
|
352 |
" dev $INTERFACE\n") |
|
353 |
interface_v4_conf = "/proc/sys/net/ipv4/conf/$INTERFACE" |
|
354 |
interface_v6_conf = "/proc/sys/net/ipv6/conf/$INTERFACE" |
|
355 |
script.write(" if [ -d %s ]; then\n" % interface_v4_conf) |
|
356 |
script.write(" echo 1 > %s/proxy_arp\n" % interface_v4_conf) |
|
357 |
script.write(" echo 1 > %s/forwarding\n" % interface_v4_conf) |
|
358 |
script.write(" fi\n") |
|
359 |
script.write(" if [ -d %s ]; then\n" % interface_v6_conf) |
|
360 |
script.write(" echo 1 > %s/proxy_ndp\n" % interface_v6_conf) |
|
361 |
script.write(" echo 1 > %s/forwarding\n" % interface_v6_conf) |
|
362 |
script.write(" fi\n") |
|
363 |
script.write("fi\n\n") |
|
418 |
script = _WriteNetScript(instance, nic, seq) |
|
419 |
|
|
364 | 420 |
# As much as we'd like to put this in our _ROOT_DIR, that will happen to be |
365 | 421 |
# mounted noexec sometimes, so we'll have to find another place. |
366 | 422 |
(tmpfd, tmpfile_name) = tempfile.mkstemp() |
367 | 423 |
tmpfile = os.fdopen(tmpfd, 'w') |
368 | 424 |
try: |
369 |
tmpfile.write(script.getvalue())
|
|
425 |
tmpfile.write(script) |
|
370 | 426 |
finally: |
371 | 427 |
tmpfile.close() |
372 | 428 |
os.chmod(tmpfile_name, 0755) |
... | ... | |
681 | 737 |
|
682 | 738 |
for nic_seq, nic in enumerate(kvm_nics): |
683 | 739 |
nic_val = "nic,vlan=%s,macaddr=%s,%s" % (nic_seq, nic.mac, nic_model) |
684 |
script = self._WriteNetScript(instance, nic_seq, nic) |
|
740 |
script = self._WriteNetScriptFile(instance, nic_seq, nic)
|
|
685 | 741 |
tap_val = "tap,vlan=%s,script=%s%s" % (nic_seq, script, tap_extra) |
686 | 742 |
kvm_cmd.extend(["-net", nic_val]) |
687 | 743 |
kvm_cmd.extend(["-net", tap_val]) |
Also available in: Unified diff