]> git.proxmox.com Git - ovs.git/blob - python/ovstest/util.py
db2ae989a2bd396534cda77b0d8cd0ec1599b3b5
[ovs.git] / python / ovstest / util.py
1 # Copyright (c) 2011, 2012, 2017 Nicira, Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """
16 util module contains some helper function
17 """
18 import array
19 import fcntl
20
21 import os
22 import re
23 import select
24 import signal
25 import socket
26 import struct
27 import subprocess
28
29 import exceptions
30
31 import six.moves.xmlrpc_client
32 from six.moves import range
33
34
35 def str_ip(ip_address):
36 """
37 Converts an IP address from binary format to a string.
38 """
39 (x1, x2, x3, x4) = struct.unpack("BBBB", ip_address)
40 return ("%u.%u.%u.%u") % (x1, x2, x3, x4)
41
42
43 def get_interface_mtu(iface):
44 """
45 Returns MTU of the given interface.
46 """
47 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
48 indata = iface + ('\0' * (32 - len(iface)))
49 try:
50 outdata = fcntl.ioctl(s.fileno(), 0x8921, indata) # socket.SIOCGIFMTU
51 mtu = struct.unpack("16si12x", outdata)[1]
52 except:
53 return 0
54
55 return mtu
56
57
58 def get_interface(address):
59 """
60 Finds first interface that has given address
61 """
62 bytes = 256 * 32
63 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
64 names = array.array('B', '\0' * bytes)
65 outbytes = struct.unpack('iL', fcntl.ioctl(
66 s.fileno(),
67 0x8912, # SIOCGIFCONF
68 struct.pack('iL', bytes, names.buffer_info()[0])
69 ))[0]
70 namestr = names.tostring()
71
72 for i in range(0, outbytes, 40):
73 name = namestr[i:i + 16].split('\0', 1)[0]
74 if address == str_ip(namestr[i + 20:i + 24]):
75 return name
76 return None # did not find interface we were looking for
77
78
79 def uname():
80 os_info = os.uname()
81 return os_info[2] # return only the kernel version number
82
83
84 def start_process(args):
85 try:
86 p = subprocess.Popen(args,
87 stdin=subprocess.PIPE,
88 stdout=subprocess.PIPE,
89 stderr=subprocess.PIPE)
90 out, err = p.communicate()
91 return (p.returncode, out, err)
92 except exceptions.OSError:
93 return (-1, None, None)
94
95
96 def get_driver(iface):
97 ret, out, _err = start_process(["ethtool", "-i", iface])
98 if ret == 0:
99 lines = out.splitlines()
100 driver = "%s(%s)" % (lines[0], lines[1]) # driver name + version
101 else:
102 driver = None
103 return driver
104
105
106 def interface_up(iface):
107 """
108 This function brings given iface up.
109 """
110 ret, _out, _err = start_process(["ip", "link", "set", iface, "up"])
111 return ret
112
113
114 def interface_assign_ip(iface, ip_addr, mask):
115 """
116 This function adds an IP address to an interface. If mask is None
117 then a mask will be selected automatically. In case of success
118 this function returns 0.
119 """
120 interface_ip_op(iface, ip_addr, mask, "add")
121
122
123 def interface_remove_ip(iface, ip_addr, mask):
124 """
125 This function removes an IP address from an interface. If mask is
126 None then a mask will be selected automatically. In case of
127 success this function returns 0.
128 """
129 interface_ip_op(iface, ip_addr, mask, "del")
130
131
132 def interface_ip_op(iface, ip_addr, mask, op):
133 if mask is not None:
134 arg = "%s/%s" % (ip_addr, mask)
135 elif '/' in ip_addr:
136 arg = ip_addr
137 else:
138 (x1, x2, x3, x4) = struct.unpack("BBBB", socket.inet_aton(ip_addr))
139 if x1 < 128:
140 arg = "%s/8" % ip_addr
141 elif x1 < 192:
142 arg = "%s/16" % ip_addr
143 else:
144 arg = "%s/24" % ip_addr
145 ret, _out, _err = start_process(["ip", "addr", op, arg, "dev", iface])
146 return ret
147
148
149 def interface_get_ip(iface):
150 """
151 This function returns tuple - ip and mask that was assigned to the
152 interface.
153 """
154 args = ["ip", "addr", "show", iface]
155 ret, out, _err = start_process(args)
156
157 if ret == 0:
158 ip = re.search(r'inet (\S+)/(\S+)', out)
159 if ip is not None:
160 return (ip.group(1), ip.group(2))
161 else:
162 return ret
163
164
165 def move_routes(iface1, iface2):
166 """
167 This function moves routes from iface1 to iface2.
168 """
169 args = ["ip", "route", "show", "dev", iface1]
170 ret, out, _err = start_process(args)
171 if ret == 0:
172 for route in out.splitlines():
173 args = ["ip", "route", "replace", "dev", iface2] + route.split()
174 start_process(args)
175
176
177 def get_interface_from_routing_decision(ip):
178 """
179 This function returns the interface through which the given ip address
180 is reachable.
181 """
182 args = ["ip", "route", "get", ip]
183 ret, out, _err = start_process(args)
184 if ret == 0:
185 iface = re.search(r'dev (\S+)', out)
186 if iface:
187 return iface.group(1)
188 return None
189
190
191 def rpc_client(ip, port):
192 return six.moves.xmlrpc_client.Server("http://%s:%u/" % (ip, port),
193 allow_none=True)
194
195
196 def sigint_intercept():
197 """
198 Intercept SIGINT from child (the local ovs-test server process).
199 """
200 signal.signal(signal.SIGINT, signal.SIG_IGN)
201
202
203 def start_local_server(port):
204 """
205 This function spawns an ovs-test server that listens on specified port
206 and blocks till the spawned ovs-test server is ready to accept XML RPC
207 connections.
208 """
209 p = subprocess.Popen(["ovs-test", "-s", str(port)],
210 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
211 preexec_fn=sigint_intercept)
212 fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL,
213 fcntl.fcntl(p.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
214
215 while p.poll() is None:
216 fd = select.select([p.stdout.fileno()], [], [])[0]
217 if fd:
218 out = p.stdout.readline()
219 if out.startswith("Starting RPC server"):
220 break
221 if p.poll() is not None:
222 raise RuntimeError("Couldn't start local instance of ovs-test server")
223 return p
224
225
226 def get_datagram_sizes(mtu1, mtu2):
227 """
228 This function calculates all the "interesting" datagram sizes so that
229 we test both - receive and send side with different packets sizes.
230 """
231 s1 = set([8, mtu1 - 100, mtu1 - 28, mtu1])
232 s2 = set([8, mtu2 - 100, mtu2 - 28, mtu2])
233 return sorted(s1.union(s2))
234
235
236 def ip_from_cidr(string):
237 """
238 This function removes the netmask (if present) from the given string and
239 returns the IP address.
240 """
241 token = string.split("/")
242 return token[0]
243
244
245 def bandwidth_to_string(bwidth):
246 """Convert bandwidth from long to string and add units."""
247 bwidth = bwidth * 8 # Convert back to bits/second
248 if bwidth >= 10000000:
249 return str(int(bwidth / 1000000)) + "Mbps"
250 elif bwidth > 10000:
251 return str(int(bwidth / 1000)) + "Kbps"
252 else:
253 return str(int(bwidth)) + "bps"