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