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