netdev-dpdk: fix mbuf leaks
[cascardo/ovs.git] / utilities / ovs-dev.py
1 #! /usr/bin/env python
2 # Copyright (c) 2013, 2014, 2015 Nicira, Inc.
3 #
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
7 #
8 #     http://www.apache.org/licenses/LICENSE-2.0
9 #
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import optparse
17 import os
18 import shutil
19 import subprocess
20 import sys
21 import tempfile
22
23 ENV = os.environ
24 HOME = ENV["HOME"]
25 PWD = os.getcwd()
26 OVS_SRC = HOME + "/ovs"
27 if os.path.exists(PWD + "/WHY-OVS.md"):
28     OVS_SRC = PWD  # Use current directory as OVS source tree
29 RUNDIR = OVS_SRC + "/_run"
30 BUILD_GCC = OVS_SRC + "/_build-gcc"
31 BUILD_CLANG = OVS_SRC + "/_build-clang"
32
33 options = None
34 parser = None
35 commands = []
36
37 def set_path(build):
38     PATH = "%(ovs)s/utilities:%(ovs)s/ovsdb:%(ovs)s/vswitchd" % {"ovs": build}
39
40     ENV["PATH"] = PATH + ":" + ENV["PATH"]
41
42 def _sh(*args, **kwargs):
43     print "------> " + " ".join(args)
44     shell = len(args) == 1
45     if kwargs.get("capture", False):
46         proc = subprocess.Popen(args, stdout=subprocess.PIPE, shell=shell)
47         return proc.stdout.readlines()
48     elif kwargs.get("check", True):
49         subprocess.check_call(args, shell=shell)
50     else:
51         subprocess.call(args, shell=shell)
52
53
54 def uname():
55     return _sh("uname", "-r", capture=True)[0].strip()
56
57
58 def sudo():
59     if os.geteuid() != 0:
60         _sh(" ".join(["sudo"] + sys.argv), check=True)
61         sys.exit(0)
62
63 def conf():
64     tag()
65
66     try:
67         os.remove(OVS_SRC + "/Makefile")
68     except OSError:
69         pass
70
71     configure = ["../configure",
72                  "--prefix=" + RUNDIR, "--localstatedir=" + RUNDIR,
73                  "--with-logdir=%s/log" % RUNDIR,
74                  "--with-rundir=%s/run" % RUNDIR,
75                  "--enable-silent-rules", "--with-dbdir=" + RUNDIR, "--silent"]
76
77     cflags = "-g -fno-omit-frame-pointer"
78
79     if options.werror:
80         configure.append("--enable-Werror")
81
82     if options.cache_time:
83         configure.append("--enable-cache-time")
84
85     if options.mandir:
86         configure.append("--mandir=" + options.mandir)
87
88     if options.with_dpdk:
89         configure.append("--with-dpdk=" + options.with_dpdk)
90         cflags += " -Wno-cast-align -Wno-bad-function-cast" # DPDK warnings.
91
92     if options.optimize is None:
93         options.optimize = 0
94
95     cflags += " -O%s" % str(options.optimize)
96
97     ENV["CFLAGS"] = cflags
98
99     _sh("./boot.sh")
100
101     try:
102         os.mkdir(BUILD_GCC)
103     except OSError:
104         pass # Directory exists.
105
106     os.chdir(BUILD_GCC)
107     _sh(*(configure + ["--with-linux=/lib/modules/%s/build" % uname()]))
108
109     try:
110         _sh("clang --version", check=True)
111         clang = True
112     except subprocess.CalledProcessError:
113         clang = False
114
115     try:
116         _sh("sparse --version", check=True)
117         sparse = True
118     except subprocess.CalledProcessError:
119         sparse = False
120
121     if clang:
122         try:
123             os.mkdir(BUILD_CLANG)
124         except OSError:
125             pass # Directory exists.
126
127         ENV["CC"] = "clang"
128         os.chdir(BUILD_CLANG)
129         _sh(*configure)
130
131     if sparse:
132         c1 = "C=1"
133     else:
134         c1 = ""
135
136     os.chdir(OVS_SRC)
137
138     make_str = "\t$(MAKE) -C %s $@\n"
139
140     mf = open(OVS_SRC + "/Makefile", "w")
141     mf.write("all:\n%:\n")
142     if clang:
143         mf.write(make_str % BUILD_CLANG)
144     mf.write("\t$(MAKE) -C %s %s $@\n" % (BUILD_GCC, c1))
145     mf.write("\ncheck-valgrind:\n")
146     mf.write("\ncheck:\n")
147     mf.write(make_str % BUILD_GCC)
148     mf.close()
149 commands.append(conf)
150
151
152 def make(args=""):
153     make = "make -s -j 8 " + args
154     _sh(make)
155 commands.append(make)
156
157
158 def check():
159     flags = ""
160     if options.jobs:
161         flags += "-j%d " % options.jobs
162     else:
163         flags += "-j8 "
164     if options.tests:
165         for arg in str.split(options.tests):
166             if arg[0].isdigit():
167                 flags += "%s " % arg
168             else:
169                 flags += "-k %s " % arg
170     ENV["TESTSUITEFLAGS"] = flags
171     make("check")
172 commands.append(check)
173
174
175 def tag():
176     ctags = ['ctags', '-R', '-f', '.tags']
177
178     try:
179         _sh(*(ctags + ['--exclude="datapath/"']))
180     except:
181         try:
182             _sh(*ctags)  # Some versions of ctags don't have --exclude
183         except:
184             pass
185
186     try:
187         _sh('cscope', '-R', '-b')
188     except:
189         pass
190 commands.append(tag)
191
192
193 def kill():
194     sudo()
195     for proc in ["ovs-vswitchd", "ovsdb-server"]:
196         if os.path.exists("%s/run/openvswitch/%s.pid" % (RUNDIR, proc)):
197             _sh("ovs-appctl", "-t", proc, "exit", check=False)
198             time.sleep(.1)
199         _sh("killall", "-q", "-2", proc, check=False)
200 commands.append(kill)
201
202
203 def reset():
204     sudo()
205     kill()
206     if os.path.exists(RUNDIR):
207         shutil.rmtree(RUNDIR)
208     for dp in _sh("ovs-dpctl dump-dps", capture=True):
209         _sh("ovs-dpctl", "del-dp", dp.strip())
210 commands.append(reset)
211
212
213 def run():
214     sudo()
215     kill()
216     for d in ["log", "run"]:
217         d = "%s/%s" % (RUNDIR, d)
218         shutil.rmtree(d, ignore_errors=True)
219         os.makedirs(d)
220
221     pki_dir = RUNDIR + "/pki"
222     if not os.path.exists(pki_dir):
223         os.mkdir(pki_dir)
224         os.chdir(pki_dir)
225         _sh("ovs-pki init")
226         _sh("ovs-pki req+sign ovsclient")
227         os.chdir(OVS_SRC)
228
229     if not os.path.exists(RUNDIR + "/conf.db"):
230         _sh("ovsdb-tool", "create", RUNDIR + "/conf.db",
231             OVS_SRC + "/vswitchd/vswitch.ovsschema")
232
233     opts = ["--pidfile", "--log-file"]
234
235     if (options.user == "") or (options.user == "root:root"):
236         _sh("chown", "root:root", "-R", RUNDIR)
237         if '--user' in sys.argv:
238            sys.argv.remove("--user")
239     else:
240         _sh("chown", options.user, "-R", RUNDIR);
241         opts = ["--user", options.user] + opts
242
243     if (options.monitor):
244         opts = ["--monitor"] + opts
245
246     _sh(*(["ovsdb-server",
247            "--remote=punix:%s/run/db.sock" % RUNDIR,
248            "--remote=db:Open_vSwitch,Open_vSwitch,manager_options",
249            "--private-key=db:Open_vSwitch,SSL,private_key",
250            "--certificate=db:Open_vSwitch,SSL,certificate",
251            "--bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert",
252            "--detach", "-vconsole:off"] + opts))
253
254     _sh("ovs-vsctl --no-wait --bootstrap set-ssl %s/ovsclient-privkey.pem" \
255         " %s/ovsclient-cert.pem %s/vswitchd.cacert"
256         % (pki_dir, pki_dir, pki_dir))
257     version = _sh("ovs-vsctl --no-wait --version", capture=True)
258     version = version[0].strip().split()[3]
259     root_uuid = _sh("ovs-vsctl --no-wait --bare list Open_vSwitch",
260                     capture=True)[0].strip()
261     _sh("ovs-vsctl --no-wait set Open_vSwitch %s ovs_version=%s"
262         % (root_uuid, version))
263
264     build = BUILD_CLANG if options.clang else BUILD_GCC
265     cmd = [build + "/vswitchd/ovs-vswitchd"]
266
267     if options.dpdk:
268         cmd.append("--dpdk")
269         cmd.extend(options.dpdk)
270         cmd.append("--")
271
272     if options.gdb:
273         cmd = ["gdb", "--args"] + cmd
274     elif options.valgrind:
275         cmd = ["valgrind", "--track-origins=yes", "--leak-check=full",
276                "--suppressions=%s/tests/glibc.supp" % OVS_SRC,
277                "--suppressions=%s/tests/openssl.supp" % OVS_SRC] + cmd
278     else:
279         opts = opts + ["-vconsole:off", "--detach", "--enable-dummy"]
280     _sh(*(cmd + opts))
281 commands.append(run)
282
283
284 def modinst():
285     if not os.path.exists("/lib/modules"):
286         print "Missing modules directory.  Is this a Linux system?"
287         sys.exit(1)
288
289     sudo()
290     try:
291         _sh("rmmod", "openvswitch")
292     except subprocess.CalledProcessError, e:
293         pass  # Module isn't loaded
294
295     try:
296         _sh("rm -f /lib/modules/%s/extra/openvswitch.ko" % uname())
297         _sh("rm -f /lib/modules/%s/extra/vport-*.ko" % uname())
298     except subprocess.CalledProcessError, e:
299         pass  # Module isn't installed
300
301     conf()
302     make()
303     make("modules_install")
304
305     _sh("modprobe", "openvswitch")
306     _sh("dmesg | grep openvswitch | tail -1")
307     _sh("find /lib/modules/%s/ -iname vport-*.ko -exec insmod '{}' \;" % uname())
308 commands.append(modinst)
309
310
311 def env():
312     print "export PATH=" + ENV["PATH"]
313 commands.append(env)
314
315
316 def doc():
317     parser.print_help()
318     print \
319 """
320 This program is designed to help developers build and run Open vSwitch without
321 necessarily needing to know the gory details. Given some basic requirements
322 (described below), it can be used to build and run Open vSwitch, keeping
323 runtime files in the user's home directory.
324
325 Basic Configuration:
326     # This section can be run as a script on ubuntu systems.
327
328     # First install the basic requirements needed to build Open vSwitch.
329     sudo apt-get install git build-essential libtool autoconf pkg-config \\
330             libssl-dev gdb libcap-ng-dev linux-headers-`uname -r`
331
332     # Next clone the Open vSwitch source.
333     git clone https://github.com/openvswitch/ovs.git %(ovs)s
334
335     # Setup environment variables.
336     `%(v)s env`
337
338     # Build the switch.
339     %(v)s conf make
340
341     # Install the kernel module
342     sudo insmod %(ovs)s/datapath/linux/openvswitch.ko
343
344     # If needed, manually load all required vport modules:
345     sudo insmod %(ovs)s/datapath/linux/vport-vxlan.ko
346     sudo insmod %(ovs)s/datapath/linux/vport-geneve.ko
347     [...]
348
349     # Run the switch.
350     %(v)s run
351
352 Commands:
353     conf    - Configure the ovs source.
354     make    - Build the source (must have been configured).
355     check   - Run the unit tests.
356     tag     - Run ctags and cscope over the source.
357     kill    - Kill all running instances of ovs.
358     reset   - Reset any runtime configuration in %(run)s.
359     run     - Run ovs.
360     modinst - Build ovs and install the kernel module.
361     env     - Print the required path environment variable.
362     doc     - Print this message.
363
364 Note:
365     If running as non-root user, "kill", "reset", "run" and "modinst"
366     will always run as the root user, by rerun the commands with "sudo".
367 """ % {"ovs": OVS_SRC, "v": sys.argv[0], "run": RUNDIR}
368     sys.exit(0)
369 commands.append(doc)
370
371 def parse_subargs(option, opt_str, value, parser):
372     subopts = []
373
374     while parser.rargs:
375         dpdkarg = parser.rargs.pop(0)
376         if dpdkarg == "--":
377             break
378         subopts.append(dpdkarg)
379
380     setattr(parser.values, option.dest, subopts)
381
382 def main():
383     global options
384     global parser
385
386     description = "Open vSwitch developer configuration. Try `%prog doc`."
387     cmd_names = [c.__name__ for c in commands]
388     parser = optparse.OptionParser(usage="usage: %prog"
389                                    + " [options] [%s] ..."
390                                    % "|".join(cmd_names),
391                                    description=description)
392
393     group = optparse.OptionGroup(parser, "conf")
394     group.add_option("--disable-Werror", dest="werror", action="store_false",
395                      default=True, help="compile without the Werror flag")
396     group.add_option("--cache-time", dest="cache_time",
397                      action="store_true", help="configure with cached timing")
398     group.add_option("--mandir", dest="mandir", metavar="MANDIR",
399                      help="configure the man documentation install directory")
400     group.add_option("--with-dpdk", dest="with_dpdk", metavar="DPDK_BUILD",
401                      help="built with dpdk libraries located at DPDK_BUILD");
402     parser.add_option_group(group)
403
404     group = optparse.OptionGroup(parser, "Optimization Flags")
405     for i in ["s", "g"] + range(4) + ["fast"]:
406         group.add_option("--O%s" % str(i), dest="optimize",
407                          action="store_const", const=i,
408                          help="compile with -O%s" % str(i))
409     parser.add_option_group(group)
410
411     group = optparse.OptionGroup(parser, "check")
412     group.add_option("-j", "--jobs", dest="jobs", metavar="N", type="int",
413                      help="Run N tests in parallel")
414     group.add_option("--tests", dest="tests", metavar="FILTER",
415                      help="""run specific tests and/or a test category
416                           eg, --tests=\"1-10 megaflow\"""")
417     parser.add_option_group(group)
418
419     group = optparse.OptionGroup(parser, "run")
420     group.add_option("-g", "--gdb", dest="gdb", action="store_true",
421                      help="run ovs-vswitchd under gdb")
422     group.add_option("--valgrind", dest="valgrind", action="store_true",
423                      help="run ovs-vswitchd under valgrind")
424     group.add_option("--dpdk", dest="dpdk", action="callback",
425                      callback=parse_subargs,
426                      help="run ovs-vswitchd with dpdk subopts (ended by --)")
427     group.add_option("--clang", dest="clang", action="store_true",
428                      help="Use binaries built by clang")
429     group.add_option("--user", dest="user", action="store", default="",
430                      help="run all daemons as a non root user")
431     group.add_option("--monitor", dest="monitor", action="store_true",
432                      help="run daemons with --monitor option")
433
434
435     parser.add_option_group(group)
436
437     options, args = parser.parse_args()
438
439     for arg in args:
440         if arg not in cmd_names:
441             print "Unknown argument " + arg
442             doc()
443
444     if options.clang:
445         set_path(BUILD_CLANG)
446     else:
447         set_path(BUILD_GCC)
448
449     try:
450         os.chdir(OVS_SRC)
451     except OSError:
452         print "Missing %s." % OVS_SRC
453         doc()
454
455     for arg in args:
456         for cmd in commands:
457             if arg == cmd.__name__:
458                 cmd()
459
460
461 if __name__ == '__main__':
462     main()