ia64/xen-unstable

view tools/xm-test/lib/XmTestLib/NetConfig.py @ 16739:33dcf04d7715

tools/docs: Fix example and default IP addresses.

In various places in documentation and code, IP addresses are provided
as examples, defaults, or dummy configuration. In general the
specific IP addresses used in Xen are not always appropriate. (For
example, 1.2.3.4 is used in a few places!)

The following addresses should be used:
* For examples and documentation, 192.0.2.0/24. (See RFC3330.)
* For defaults for private networks, a random network from RFC1918.
I have randomly selected 172.30.206.0/24 for this purpose and
documented this in at the only registry I know of,
www.ucam.org/cam-grin. This network should henceforth be used for
default configurations of local bridges, test networks, etc. in
Xen tools.

The following addresses should NOT be used:
* 10.0.*.*, 10.1.*.*, 192.168.0.*, 192.168.1.*, etc. Using these
addresses gives greatly increased likelihood of collision, as
ignorant network administrators and reckless middlebox vendors
often pick networks from the bottom of 10/8 and 192.168/16.
* 169.254.*.*. These are reserved for zeroconf (ad-hoc networking)
and should not be used for Xen private networks, bridges, etc.,
etc. Use of these addresses by Xen scripts causes trouble on hosts
(eg laptops) which find themselves in ad-hoc networking
environments. I think this is not hypothetical (!) since at least
one Linux distribution have specific code to detect this case and
cause Xen startup to fail iff the host already has an external
zeroconf address.
* 1.2.3.4. WTF !?

I have also used 127.0.255.255 in one place where apparently a dummy
address is needed (some Linux kernels won't accept a lack of an NFS
server address). If 127.0.255.255 is mistakenly used it is unlikely
to do any damage to real traffic even if it does escape into the
network at large.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jan 17 15:13:40 2008 +0000 (2008-01-17)
parents 9a39dac6660a
children 6c7ae9c859f5
line source
1 #!/usr/bin/python
2 """
3 Copyright (C) International Business Machines Corp., 2005, 2006
4 Authors: Dan Smith <danms@us.ibm.com>
5 Daniel Stekloff <dsteklof@us.ibm.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; under version 2 of the License.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 """
22 import sys
23 import commands
24 import os
25 import re
26 import time
27 import random
28 from xen.xend.sxp import Parser
30 from Xm import *
31 from Test import *
32 from config import *
34 class NetworkError(Exception):
35 def __init__(self, msg):
36 self.errMsg = msg
38 def __str__(self):
39 return str(self.errMsg)
41 def getXendNetConfig():
42 # Find out what environment we're in: bridge, nat, or route
43 xconfig = os.getenv("XEND_CONFIG")
44 if not xconfig:
45 xconfig = "/etc/xen/xend-config.sxp"
47 try:
48 configfile = open(xconfig, 'r')
49 except:
50 return "bridge"
52 S = configfile.read()
53 pin = Parser()
54 pin.input(S)
55 pin.input_eof()
56 val = pin.get_val()
57 while val[0] != 'network-script':
58 val = pin.get_val()
60 if val[1] == "network-bridge":
61 netenv = "bridge"
62 elif val[1] == "network-route":
63 netenv = "route"
64 elif val[1] == "network-nat":
65 netenv = "nat"
66 else:
67 raise NetworkError("Failed to get network env from xend config")
69 configfile.close()
70 return netenv
72 class NetConfig:
74 def __init__(self):
75 self.netenv = getXendNetConfig()
76 self.used_ips = {}
77 self.free_oct_ips = [ 0, 0, 0, 0 ]
78 self.total_ips = 0
80 if NETWORK_IP_RANGE == 'dhcp':
81 self.netmask = NETWORK_IP_RANGE
82 self.network = NETWORK_IP_RANGE
83 self.max_ip = NETWORK_IP_RANGE
84 self.min_ip = NETWORK_IP_RANGE
85 else:
86 self.netmask = NETMASK
87 self.network = NETWORK
88 s_ip = ''
90 # Get starting ip and max ip from configured ip range
91 s_ip = NETWORK_IP_RANGE
92 ips = s_ip.split("-")
93 self.max_ip = ips[1]
94 self.min_ip = ips[0]
96 self.__setMaxNumberIPs()
98 # Clean out any aliases in the network range for dom0's interface.
99 # If an alias exists, a test xendevice add command could fail.
100 if NETWORK_IP_RANGE != "dhcp":
101 self.__cleanDom0Aliases()
103 def __setMaxNumberIPs(self):
104 # Count the number of IPs available, to help tests know whether they
105 # have enough to run or not
106 masko = self.netmask.split('.')
107 maxo = self.max_ip.split('.')
108 mino = self.min_ip.split('.')
109 ips = 0
111 # Last octet
112 self.free_oct_ips[3] = (int(maxo[3]) - int(mino[3])) + 1
114 # 3rd octet
115 self.free_oct_ips[2] = (int(maxo[2]) - int(mino[2])) + 1
117 # 2nd octet
118 self.free_oct_ips[1] = (int(maxo[1]) - int(mino[1])) + 1
120 # 1st octet
121 self.free_oct_ips[0] = (int(maxo[0]) - int(mino[0])) + 1
123 self.total_ips = self.free_oct_ips[3]
124 if self.free_oct_ips[2] > 1:
125 self.total_ips = (self.total_ips * self.free_oct_ips[2])
126 if self.free_oct_ips[1] > 1:
127 self.total_ips = (self.total_ips * self.free_oct_ips[1])
128 if self.free_oct_ips[0] > 1:
129 self.total_ips = (self.total_ips * self.free_oct_ips[0])
131 def __cleanDom0Aliases(self):
132 # Remove any aliases within the supplied network IP range on dom0
133 scmd = 'ip addr show dev %s' % (DOM0_INTF)
135 status, output = traceCommand(scmd)
136 if status:
137 raise NetworkError("Failed to show %s aliases: %d" %
138 (DOM0_INTF, status))
140 lines = output.split("\n")
141 for line in lines:
142 ip = re.search('(\d+\.\d+\.\d+\.\d+)', line)
143 if ip and self.isIPInRange(ip.group(1)) == True:
144 dcmd = 'ip addr del %s dev %s' % (ip.group(1), DOM0_INTF)
145 dstatus, doutput = traceCommand(dcmd)
146 if dstatus:
147 raise NetworkError("Failed to remove %s aliases: %d" %
148 (DOM0_INTF, status))
150 def getNetEnv(self):
151 return self.netenv
153 def setUsedIP(self, domname, interface, ip):
154 self.used_ips['%s:%s' % (domname, interface)] = ip
156 def __findFirstOctetIP(self, prefix, min, max):
157 for i in range(min, max):
158 ip = '%s%s' % (prefix, str(i))
159 found = False
160 for k in self.used_ips.keys():
161 if self.used_ips[k] == ip:
162 found = True
163 if found == False:
164 return ip
166 if found == True:
167 return None
169 def getFreeIP(self, domname, interface):
170 # Get a free IP. It uses the starting ip octets and then the
171 # total number of allowed numbers for that octet. It only
172 # calculates ips for the last two octets, we shouldn't need more
173 start_octets = self.min_ip.split(".")
174 ip = None
176 # Only working with ips from last two octets, shouldn't need more
177 max = int(start_octets[2]) + self.free_oct_ips[2]
178 for i in range(int(start_octets[2]), max):
179 prefix = '%s.%s.%s.' % (start_octets[0], start_octets[1], str(i))
180 ip = self.__findFirstOctetIP(prefix, int(start_octets[3]), self.free_oct_ips[3])
181 if ip:
182 break
184 if not ip:
185 raise NetworkError("Ran out of configured addresses.")
187 self.setUsedIP(domname, interface, ip)
188 return ip
190 def getNetMask(self):
191 return self.netmask
193 def getNetwork(self):
194 return self.network
196 def getIP(self, domname, interface):
197 # Depending on environment, set an IP. Uses the configured range
198 # of IPs, network address, and netmask
199 if NETWORK_IP_RANGE == "dhcp":
200 return None
202 # Make sure domain and interface aren't already assigned an IP
203 if self.used_ips.has_key('%s:%s' % (domname, interface)):
204 raise NetworkError("Domain %s interface %s is already has IP"
205 % (domname, interface))
207 return self.getFreeIP(domname, interface)
209 def setIP(self, domname, interface, ip):
210 # Make sure domain and interface aren't already assigned an IP
211 if self.used_ips.has_key('%s:%s' % (domname, interface)):
212 raise NetworkError("Domain %s interface %s is already has IP"
213 % (domname, interface))
215 self.setUsedIP(domname, interface, ip)
217 def releaseIP(self, domname, interface, ip):
218 if self.used_ips.has_key('%s:%s' % (domname, interface)):
219 del self.used_ips['%s:%s' % (domname, interface)]
221 def getNumberAllowedIPs(self):
222 return self.total_ips
224 def canRunNetTest(self, ips):
225 # Check to see if a test can run, returns true or false. Input is
226 # number of ips needed.
227 if NETWORK_IP_RANGE == "dhcp":
228 return True
230 if self.total_ips >= ips:
231 return True
233 return False
235 def isIPInRange(self, ip):
236 # Checks to see if supplied ip is in the range of allowed ips
237 maxo = self.max_ip.split('.')
238 mino = self.min_ip.split('.')
239 ipo = ip.split('.')
241 if int(ipo[0]) < int(mino[0]):
242 return False
243 elif int(ipo[0]) > int(maxo[0]):
244 return False
246 if int(ipo[1]) < int(mino[1]):
247 return False
248 elif int(ipo[1]) > int(maxo[1]):
249 return False
251 if int(ipo[2]) < int(mino[2]):
252 return False
253 elif int(ipo[2]) > int(maxo[2]):
254 return False
256 if int(ipo[3]) < int(mino[3]):
257 return False
258 elif int(ipo[3]) > int(maxo[3]):
259 return False
261 return True