netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / python / ovstest / util.py
1 # Copyright (c) 2011, 2012 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 exceptions
20 import fcntl
21 import os
22 import select
23 import socket
24 import struct
25 import signal
26 import subprocess
27 import re
28
29 from six.moves import range
30 import six.moves.xmlrpc_client
31
32
33 def str_ip(ip_address):
34     """
35     Converts an IP address from binary format to a string.
36     """
37     (x1, x2, x3, x4) = struct.unpack("BBBB", ip_address)
38     return ("%u.%u.%u.%u") % (x1, x2, x3, x4)
39
40
41 def get_interface_mtu(iface):
42     """
43     Returns MTU of the given interface.
44     """
45     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
46     indata = iface + ('\0' * (32 - len(iface)))
47     try:
48         outdata = fcntl.ioctl(s.fileno(), 0x8921, indata)  # socket.SIOCGIFMTU
49         mtu = struct.unpack("16si12x", outdata)[1]
50     except:
51         return 0
52
53     return mtu
54
55
56 def get_interface(address):
57     """
58     Finds first interface that has given address
59     """
60     bytes = 256 * 32
61     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
62     names = array.array('B', '\0' * bytes)
63     outbytes = struct.unpack('iL', fcntl.ioctl(
64         s.fileno(),
65         0x8912,  # SIOCGIFCONF
66         struct.pack('iL', bytes, names.buffer_info()[0])
67     ))[0]
68     namestr = names.tostring()
69
70     for i in range(0, outbytes, 40):
71         name = namestr[i:i + 16].split('\0', 1)[0]
72         if address == str_ip(namestr[i + 20:i + 24]):
73             return name
74     return None  # did not find interface we were looking for
75
76
77 def uname():
78     os_info = os.uname()
79     return os_info[2]  # return only the kernel version number
80
81
82 def start_process(args):
83     try:
84         p = subprocess.Popen(args,
85                              stdin=subprocess.PIPE,
86                              stdout=subprocess.PIPE,
87                              stderr=subprocess.PIPE)
88         out, err = p.communicate()
89         return (p.returncode, out, err)
90     except exceptions.OSError:
91         return (-1, None, None)
92
93
94 def get_driver(iface):
95     ret, out, _err = start_process(["ethtool", "-i", iface])
96     if ret == 0:
97         lines = out.splitlines()
98         driver = "%s(%s)" % (lines[0], lines[1])  # driver name + version
99     else:
100         driver = None
101     return driver
102
103
104 def interface_up(iface):
105     """
106     This function brings given iface up.
107     """
108     ret, _out, _err = start_process(["ifconfig", iface, "up"])
109     return ret
110
111
112 def interface_assign_ip(iface, ip_addr, mask):
113     """
114     This function allows to assign IP address to an interface. If mask is an
115     empty string then ifconfig will decide what kind of mask to use. The
116     caller can also specify the mask by using CIDR notation in ip argument by
117     leaving the mask argument as an empty string. In case of success this
118     function returns 0.
119     """
120     args = ["ifconfig", iface, ip_addr]
121     if mask is not None:
122         args.append("netmask")
123         args.append(mask)
124     ret, _out, _err = start_process(args)
125     return ret
126
127
128 def interface_get_ip(iface):
129     """
130     This function returns tuple - ip and mask that was assigned to the
131     interface.
132     """
133     args = ["ifconfig", iface]
134     ret, out, _err = start_process(args)
135
136     if ret == 0:
137         ip = re.search(r'inet addr:(\S+)', out)
138         mask = re.search(r'Mask:(\S+)', out)
139         if ip is not None and mask is not None:
140             return (ip.group(1), mask.group(1))
141     else:
142         return ret
143
144
145 def move_routes(iface1, iface2):
146     """
147     This function moves routes from iface1 to iface2.
148     """
149     args = ["ip", "route", "show", "dev", iface1]
150     ret, out, _err = start_process(args)
151     if ret == 0:
152         for route in out.splitlines():
153             args = ["ip", "route", "replace", "dev", iface2] + route.split()
154             start_process(args)
155
156
157 def get_interface_from_routing_decision(ip):
158     """
159     This function returns the interface through which the given ip address
160     is reachable.
161     """
162     args = ["ip", "route", "get", ip]
163     ret, out, _err = start_process(args)
164     if ret == 0:
165         iface = re.search(r'dev (\S+)', out)
166         if iface:
167             return iface.group(1)
168     return None
169
170
171 def rpc_client(ip, port):
172     return six.moves.xmlrpc_client.Server("http://%s:%u/" % (ip, port),
173                                           allow_none=True)
174
175
176 def sigint_intercept():
177     """
178     Intercept SIGINT from child (the local ovs-test server process).
179     """
180     signal.signal(signal.SIGINT, signal.SIG_IGN)
181
182
183 def start_local_server(port):
184     """
185     This function spawns an ovs-test server that listens on specified port
186     and blocks till the spawned ovs-test server is ready to accept XML RPC
187     connections.
188     """
189     p = subprocess.Popen(["ovs-test", "-s", str(port)],
190                          stdout=subprocess.PIPE, stderr=subprocess.PIPE,
191                          preexec_fn=sigint_intercept)
192     fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL,
193         fcntl.fcntl(p.stdout.fileno(), fcntl.F_GETFL) | os.O_NONBLOCK)
194
195     while p.poll() is None:
196         fd = select.select([p.stdout.fileno()], [], [])[0]
197         if fd:
198             out = p.stdout.readline()
199             if out.startswith("Starting RPC server"):
200                 break
201     if p.poll() is not None:
202         raise RuntimeError("Couldn't start local instance of ovs-test server")
203     return p
204
205
206 def get_datagram_sizes(mtu1, mtu2):
207     """
208     This function calculates all the "interesting" datagram sizes so that
209     we test both - receive and send side with different packets sizes.
210     """
211     s1 = set([8, mtu1 - 100, mtu1 - 28, mtu1])
212     s2 = set([8, mtu2 - 100, mtu2 - 28, mtu2])
213     return sorted(s1.union(s2))
214
215
216 def ip_from_cidr(string):
217     """
218     This function removes the netmask (if present) from the given string and
219     returns the IP address.
220     """
221     token = string.split("/")
222     return token[0]
223
224
225 def bandwidth_to_string(bwidth):
226     """Convert bandwidth from long to string and add units."""
227     bwidth = bwidth * 8  # Convert back to bits/second
228     if bwidth >= 10000000:
229         return str(int(bwidth / 1000000)) + "Mbps"
230     elif bwidth > 10000:
231         return str(int(bwidth / 1000)) + "Kbps"
232     else:
233         return str(int(bwidth)) + "bps"