]>
Commit | Line | Data |
---|---|---|
c6b581b9 JS |
1 | #!/usr/bin/env python |
2 | # Copyright (c) 2013, 2014, 2015, 2016 Nicira, Inc. | |
fef5244f EJ |
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 | |
c6b581b9 | 21 | import time |
fef5244f EJ |
22 | |
23 | ENV = os.environ | |
24 | HOME = ENV["HOME"] | |
9bf2f075 | 25 | PWD = os.getcwd() |
fef5244f | 26 | OVS_SRC = HOME + "/ovs" |
3c8a3b31 | 27 | if os.path.exists(PWD + "/README.rst"): |
9bf2f075 | 28 | OVS_SRC = PWD # Use current directory as OVS source tree |
0c001985 | 29 | RUNDIR = OVS_SRC + "/_run" |
30fbc7b6 EJ |
30 | BUILD_GCC = OVS_SRC + "/_build-gcc" |
31 | BUILD_CLANG = OVS_SRC + "/_build-clang" | |
fef5244f EJ |
32 | |
33 | options = None | |
34 | parser = None | |
35 | commands = [] | |
36 | ||
c6b581b9 | 37 | |
97695cf7 EJ |
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"] | |
fef5244f | 42 | |
c6b581b9 | 43 | |
fef5244f | 44 | def _sh(*args, **kwargs): |
c6b581b9 | 45 | print("------> " + " ".join(args)) |
fef5244f EJ |
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(): | |
4591ed3a | 57 | return _sh("uname", "-r", capture=True)[0].decode().strip() |
fef5244f EJ |
58 | |
59 | ||
c5c9cb9e AZ |
60 | def sudo(): |
61 | if os.geteuid() != 0: | |
62 | _sh(" ".join(["sudo"] + sys.argv), check=True) | |
63 | sys.exit(0) | |
64 | ||
c6b581b9 | 65 | |
fef5244f EJ |
66 | def conf(): |
67 | tag() | |
47e501e1 | 68 | |
30fbc7b6 EJ |
69 | try: |
70 | os.remove(OVS_SRC + "/Makefile") | |
71 | except OSError: | |
72 | pass | |
73 | ||
0c001985 AZ |
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"] | |
fef5244f | 79 | |
25dfecf8 EJ |
80 | cflags = "-g -fno-omit-frame-pointer" |
81 | ||
fef5244f EJ |
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 | ||
25dfecf8 EJ |
91 | if options.with_dpdk: |
92 | configure.append("--with-dpdk=" + options.with_dpdk) | |
c6b581b9 | 93 | cflags += " -Wno-cast-align -Wno-bad-function-cast" # DPDK warnings. |
25dfecf8 | 94 | |
a2a2ac7b EJ |
95 | if options.optimize is None: |
96 | options.optimize = 0 | |
25dfecf8 | 97 | |
1bcf46c6 | 98 | cflags += " -O%s" % str(options.optimize) |
25dfecf8 EJ |
99 | |
100 | ENV["CFLAGS"] = cflags | |
a2a2ac7b | 101 | |
fef5244f | 102 | _sh("./boot.sh") |
30fbc7b6 EJ |
103 | |
104 | try: | |
105 | os.mkdir(BUILD_GCC) | |
106 | except OSError: | |
c6b581b9 | 107 | pass # Directory exists. |
30fbc7b6 EJ |
108 | |
109 | os.chdir(BUILD_GCC) | |
a3ea1821 | 110 | _sh(*(configure + ["--with-linux=/lib/modules/%s/build" % uname()])) |
30fbc7b6 EJ |
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: | |
c6b581b9 | 128 | pass # Directory exists. |
30fbc7b6 EJ |
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)) | |
c0b0b096 | 148 | mf.write("\ncheck-valgrind:\n") |
30fbc7b6 EJ |
149 | mf.write("\ncheck:\n") |
150 | mf.write(make_str % BUILD_GCC) | |
151 | mf.close() | |
884e0dfe DDP |
152 | |
153 | ||
fef5244f EJ |
154 | commands.append(conf) |
155 | ||
156 | ||
157 | def make(args=""): | |
158 | make = "make -s -j 8 " + args | |
fef5244f | 159 | _sh(make) |
884e0dfe DDP |
160 | |
161 | ||
fef5244f EJ |
162 | commands.append(make) |
163 | ||
164 | ||
165 | def check(): | |
de146e5d | 166 | flags = "" |
6a223e8e JS |
167 | if options.jobs: |
168 | flags += "-j%d " % options.jobs | |
169 | else: | |
170 | flags += "-j8 " | |
de146e5d JS |
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 | |
fef5244f | 178 | make("check") |
884e0dfe DDP |
179 | |
180 | ||
fef5244f EJ |
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 | |
884e0dfe DDP |
199 | |
200 | ||
fef5244f EJ |
201 | commands.append(tag) |
202 | ||
203 | ||
204 | def kill(): | |
c5c9cb9e | 205 | sudo() |
fef5244f | 206 | for proc in ["ovs-vswitchd", "ovsdb-server"]: |
0c001985 | 207 | if os.path.exists("%s/run/openvswitch/%s.pid" % (RUNDIR, proc)): |
fef5244f EJ |
208 | _sh("ovs-appctl", "-t", proc, "exit", check=False) |
209 | time.sleep(.1) | |
c5c9cb9e | 210 | _sh("killall", "-q", "-2", proc, check=False) |
884e0dfe DDP |
211 | |
212 | ||
fef5244f EJ |
213 | commands.append(kill) |
214 | ||
215 | ||
216 | def reset(): | |
c5c9cb9e | 217 | sudo() |
fef5244f | 218 | kill() |
0c001985 AZ |
219 | if os.path.exists(RUNDIR): |
220 | shutil.rmtree(RUNDIR) | |
fef5244f | 221 | for dp in _sh("ovs-dpctl dump-dps", capture=True): |
4591ed3a | 222 | _sh("ovs-dpctl", "del-dp", dp.decode().strip()) |
884e0dfe DDP |
223 | |
224 | ||
fef5244f EJ |
225 | commands.append(reset) |
226 | ||
227 | ||
228 | def run(): | |
c5c9cb9e | 229 | sudo() |
fef5244f EJ |
230 | kill() |
231 | for d in ["log", "run"]: | |
0c001985 | 232 | d = "%s/%s" % (RUNDIR, d) |
fef5244f EJ |
233 | shutil.rmtree(d, ignore_errors=True) |
234 | os.makedirs(d) | |
235 | ||
0c001985 | 236 | pki_dir = RUNDIR + "/pki" |
fef5244f EJ |
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 | ||
0c001985 AZ |
244 | if not os.path.exists(RUNDIR + "/conf.db"): |
245 | _sh("ovsdb-tool", "create", RUNDIR + "/conf.db", | |
fef5244f EJ |
246 | OVS_SRC + "/vswitchd/vswitch.ovsschema") |
247 | ||
3bacde2a | 248 | opts = ["--pidfile", "--log-file"] |
fef5244f | 249 | |
c543ef57 AZ |
250 | if (options.user == "") or (options.user == "root:root"): |
251 | _sh("chown", "root:root", "-R", RUNDIR) | |
252 | if '--user' in sys.argv: | |
c6b581b9 | 253 | sys.argv.remove("--user") |
c543ef57 | 254 | else: |
c6b581b9 | 255 | _sh("chown", options.user, "-R", RUNDIR) |
c543ef57 AZ |
256 | opts = ["--user", options.user] + opts |
257 | ||
bf66c067 AZ |
258 | if (options.monitor): |
259 | opts = ["--monitor"] + opts | |
260 | ||
fef5244f | 261 | _sh(*(["ovsdb-server", |
0c001985 | 262 | "--remote=punix:%s/run/db.sock" % RUNDIR, |
fef5244f EJ |
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 | ||
c6b581b9 | 269 | _sh("ovs-vsctl --no-wait --bootstrap set-ssl %s/ovsclient-privkey.pem" |
fef5244f EJ |
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) | |
4591ed3a | 273 | version = version[0].decode().strip().split()[3] |
fef5244f | 274 | root_uuid = _sh("ovs-vsctl --no-wait --bare list Open_vSwitch", |
4591ed3a | 275 | capture=True)[0].decode().strip() |
fef5244f EJ |
276 | _sh("ovs-vsctl --no-wait set Open_vSwitch %s ovs_version=%s" |
277 | % (root_uuid, version)) | |
278 | ||
97695cf7 EJ |
279 | build = BUILD_CLANG if options.clang else BUILD_GCC |
280 | cmd = [build + "/vswitchd/ovs-vswitchd"] | |
1a90b839 DDP |
281 | |
282 | if options.dpdk: | |
c6b581b9 | 283 | _sh("ovs-vsctl --no-wait set Open_vSwitch %s " |
bab69409 | 284 | "other_config:dpdk-init=true" % root_uuid) |
c6b581b9 | 285 | _sh("ovs-vsctl --no-wait set Open_vSwitch %s other_config:" |
eac84432 | 286 | "dpdk-extra=\"%s\"" % (root_uuid, ' '.join(options.dpdk))) |
bab69409 | 287 | else: |
c6b581b9 | 288 | _sh("ovs-vsctl --no-wait set Open_vSwitch %s " |
bab69409 | 289 | "other_config:dpdk-init=false" % root_uuid) |
1a90b839 | 290 | |
fef5244f EJ |
291 | if options.gdb: |
292 | cmd = ["gdb", "--args"] + cmd | |
293 | elif options.valgrind: | |
294a5550 | 294 | cmd = ["valgrind", "--track-origins=yes", "--leak-check=full", |
1e0879aa EJ |
295 | "--suppressions=%s/tests/glibc.supp" % OVS_SRC, |
296 | "--suppressions=%s/tests/openssl.supp" % OVS_SRC] + cmd | |
fef5244f | 297 | else: |
3bacde2a | 298 | opts = opts + ["-vconsole:off", "--detach", "--enable-dummy"] |
fef5244f | 299 | _sh(*(cmd + opts)) |
884e0dfe DDP |
300 | |
301 | ||
fef5244f EJ |
302 | commands.append(run) |
303 | ||
304 | ||
305 | def modinst(): | |
306 | if not os.path.exists("/lib/modules"): | |
c6b581b9 | 307 | print("Missing modules directory. Is this a Linux system?") |
fef5244f EJ |
308 | sys.exit(1) |
309 | ||
c5c9cb9e | 310 | sudo() |
fef5244f EJ |
311 | try: |
312 | _sh("rmmod", "openvswitch") | |
c6b581b9 | 313 | except subprocess.CalledProcessError: |
fef5244f EJ |
314 | pass # Module isn't loaded |
315 | ||
316 | try: | |
19c12401 BP |
317 | _sh("rm -f /lib/modules/%s/extra/openvswitch.ko" % uname()) |
318 | _sh("rm -f /lib/modules/%s/extra/vport-*.ko" % uname()) | |
c6b581b9 | 319 | except subprocess.CalledProcessError: |
fef5244f EJ |
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") | |
145a7e88 | 328 | _sh("find /lib/modules/%s/ -iname vport-*.ko -exec insmod '{}' \\;" |
c6b581b9 | 329 | % uname()) |
884e0dfe DDP |
330 | |
331 | ||
fef5244f EJ |
332 | commands.append(modinst) |
333 | ||
334 | ||
335 | def env(): | |
c6b581b9 | 336 | print("export PATH=" + ENV["PATH"]) |
884e0dfe DDP |
337 | |
338 | ||
fef5244f EJ |
339 | commands.append(env) |
340 | ||
341 | ||
342 | def doc(): | |
343 | parser.print_help() | |
c6b581b9 | 344 | print(""" |
fef5244f EJ |
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 \\ | |
bdc30bfb | 355 | libssl-dev gdb libcap-ng-dev linux-headers-`uname -r` |
fef5244f EJ |
356 | |
357 | # Next clone the Open vSwitch source. | |
6d616e99 | 358 | git clone https://github.com/openvswitch/ovs.git %(ovs)s |
fef5244f EJ |
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 | ||
e8ee793b TG |
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 | ||
fef5244f EJ |
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. | |
c5c9cb9e AZ |
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". | |
c6b581b9 | 392 | """ % {"ovs": OVS_SRC, "v": sys.argv[0], "run": RUNDIR}) |
fef5244f | 393 | sys.exit(0) |
884e0dfe DDP |
394 | |
395 | ||
fef5244f EJ |
396 | commands.append(doc) |
397 | ||
c6b581b9 | 398 | |
1a90b839 DDP |
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) | |
fef5244f | 409 | |
c6b581b9 | 410 | |
fef5244f EJ |
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] | |
c6b581b9 JS |
417 | usage = "usage: %prog" + " [options] [%s] ..." % "|".join(cmd_names) |
418 | parser = optparse.OptionParser(usage=usage, description=description) | |
fef5244f EJ |
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") | |
25dfecf8 | 427 | group.add_option("--with-dpdk", dest="with_dpdk", metavar="DPDK_BUILD", |
c6b581b9 | 428 | help="built with dpdk libraries located at DPDK_BUILD") |
1bcf46c6 | 429 | parser.add_option_group(group) |
a2a2ac7b | 430 | |
1bcf46c6 | 431 | group = optparse.OptionGroup(parser, "Optimization Flags") |
4591ed3a | 432 | for i in ["s", "g"] + list(range(4)) + ["fast"]: |
1bcf46c6 EJ |
433 | group.add_option("--O%s" % str(i), dest="optimize", |
434 | action="store_const", const=i, | |
435 | help="compile with -O%s" % str(i)) | |
fef5244f EJ |
436 | parser.add_option_group(group) |
437 | ||
de146e5d | 438 | group = optparse.OptionGroup(parser, "check") |
6a223e8e JS |
439 | group.add_option("-j", "--jobs", dest="jobs", metavar="N", type="int", |
440 | help="Run N tests in parallel") | |
de146e5d JS |
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 | ||
fef5244f EJ |
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") | |
eac84432 AC |
451 | group.add_option("--dpdk", dest="dpdk", action="callback", |
452 | callback=parse_subargs, | |
453 | help="run ovs-vswitchd with dpdk subopts (ended by --)") | |
97695cf7 EJ |
454 | group.add_option("--clang", dest="clang", action="store_true", |
455 | help="Use binaries built by clang") | |
c543ef57 AZ |
456 | group.add_option("--user", dest="user", action="store", default="", |
457 | help="run all daemons as a non root user") | |
bf66c067 AZ |
458 | group.add_option("--monitor", dest="monitor", action="store_true", |
459 | help="run daemons with --monitor option") | |
460 | ||
fef5244f EJ |
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: | |
c6b581b9 | 467 | print("Unknown argument " + arg) |
fef5244f EJ |
468 | doc() |
469 | ||
97695cf7 EJ |
470 | if options.clang: |
471 | set_path(BUILD_CLANG) | |
472 | else: | |
473 | set_path(BUILD_GCC) | |
474 | ||
fef5244f EJ |
475 | try: |
476 | os.chdir(OVS_SRC) | |
477 | except OSError: | |
c6b581b9 | 478 | print("Missing %s." % OVS_SRC) |
fef5244f EJ |
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() |