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