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])
|