socket-util: poll() for Windows.
[sliver-openvswitch.git] / utilities / ovs-dev.py
1 #!/usr/bin/python
2 # Copyright (c) 2013 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 PATH = "%(ovs)s/utilities:%(ovs)s/ovsdb:%(ovs)s/vswitchd" % {"ovs": BUILD_GCC}
30
31 ENV["CFLAGS"] = "-g -fno-omit-frame-pointer"
32 ENV["PATH"] = PATH + ":" + ENV["PATH"]
33
34 options = None
35 parser = None
36 commands = []
37
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     if options.werror:
68         configure.append("--enable-Werror")
69
70     if options.cache_time:
71         configure.append("--enable-cache-time")
72
73     if options.mandir:
74         configure.append("--mandir=" + options.mandir)
75
76     if options.optimize is None:
77         options.optimize = 0
78     ENV["CFLAGS"] = "%s -O%d" % (ENV["CFLAGS"], options.optimize)
79
80     _sh("./boot.sh")
81
82     try:
83         os.mkdir(BUILD_GCC)
84     except OSError:
85         pass # Directory exists.
86
87     os.chdir(BUILD_GCC)
88     _sh(*(configure + ["--with-linux=/lib/modules/%s/build" % uname()]))
89
90     try:
91         _sh("clang --version", check=True)
92         clang = True
93     except subprocess.CalledProcessError:
94         clang = False
95
96     try:
97         _sh("sparse --version", check=True)
98         sparse = True
99     except subprocess.CalledProcessError:
100         sparse = False
101
102     if clang:
103         try:
104             os.mkdir(BUILD_CLANG)
105         except OSError:
106             pass # Directory exists.
107
108         ENV["CC"] = "clang"
109         os.chdir(BUILD_CLANG)
110         _sh(*configure)
111
112     if sparse:
113         c1 = "C=1"
114     else:
115         c1 = ""
116
117     os.chdir(OVS_SRC)
118
119     make_str = "\t$(MAKE) -C %s $@\n"
120
121     mf = open(OVS_SRC + "/Makefile", "w")
122     mf.write("all:\n%:\n")
123     if clang:
124         mf.write(make_str % BUILD_CLANG)
125     mf.write("\t$(MAKE) -C %s %s $@\n" % (BUILD_GCC, c1))
126     mf.write("\ncheck:\n")
127     mf.write(make_str % BUILD_GCC)
128     mf.close()
129 commands.append(conf)
130
131
132 def make(args=""):
133     make = "make -s -j 8 " + args
134     _sh(make)
135 commands.append(make)
136
137
138 def check():
139     make("check")
140 commands.append(check)
141
142
143 def tag():
144     ctags = ['ctags', '-R', '-f', '.tags']
145
146     try:
147         _sh(*(ctags + ['--exclude="datapath/"']))
148     except:
149         try:
150             _sh(*ctags)  # Some versions of ctags don't have --exclude
151         except:
152             pass
153
154     try:
155         _sh('cscope', '-R', '-b')
156     except:
157         pass
158 commands.append(tag)
159
160
161 def kill():
162     for proc in ["ovs-vswitchd", "ovsdb-server"]:
163         if os.path.exists("%s/run/openvswitch/%s.pid" % (ROOT, proc)):
164             _sh("ovs-appctl", "-t", proc, "exit", check=False)
165             time.sleep(.1)
166         _sh("sudo", "killall", "-q", "-2", proc, check=False)
167 commands.append(kill)
168
169
170 def reset():
171     kill()
172     if os.path.exists(ROOT):
173         shutil.rmtree(ROOT)
174     for dp in _sh("ovs-dpctl dump-dps", capture=True):
175         _sh("ovs-dpctl", "del-dp", dp.strip())
176 commands.append(reset)
177
178
179 def run():
180     kill()
181     for d in ["log", "run"]:
182         d = "%s/%s" % (ROOT, d)
183         shutil.rmtree(d, ignore_errors=True)
184         os.makedirs(d)
185
186     pki_dir = ROOT + "/pki"
187     if not os.path.exists(pki_dir):
188         os.mkdir(pki_dir)
189         os.chdir(pki_dir)
190         _sh("ovs-pki init")
191         _sh("ovs-pki req+sign ovsclient")
192         os.chdir(OVS_SRC)
193
194     if not os.path.exists(ROOT + "/conf.db"):
195         _sh("ovsdb-tool", "create", ROOT + "/conf.db",
196             OVS_SRC + "/vswitchd/vswitch.ovsschema")
197
198     opts = ["--pidfile", "--log-file", "--enable-dummy"]
199
200     _sh(*(["ovsdb-server",
201            "--remote=punix:%s/run/db.sock" % ROOT,
202            "--remote=db:Open_vSwitch,Open_vSwitch,manager_options",
203            "--private-key=db:Open_vSwitch,SSL,private_key",
204            "--certificate=db:Open_vSwitch,SSL,certificate",
205            "--bootstrap-ca-cert=db:Open_vSwitch,SSL,ca_cert",
206            "--detach", "-vconsole:off"] + opts))
207
208     _sh("ovs-vsctl --no-wait --bootstrap set-ssl %s/ovsclient-privkey.pem" \
209         " %s/ovsclient-cert.pem %s/vswitchd.cacert"
210         % (pki_dir, pki_dir, pki_dir))
211     version = _sh("ovs-vsctl --no-wait --version", capture=True)
212     version = version[0].strip().split()[3]
213     root_uuid = _sh("ovs-vsctl --no-wait --bare list Open_vSwitch",
214                     capture=True)[0].strip()
215     _sh("ovs-vsctl --no-wait set Open_vSwitch %s ovs_version=%s"
216         % (root_uuid, version))
217
218     cmd = [BUILD_GCC + "/vswitchd/ovs-vswitchd"]
219     if options.gdb:
220         cmd = ["gdb", "--args"] + cmd
221     elif options.valgrind:
222         cmd = ["valgrind", "--track-origins=yes", "--leak-check=full",
223                "--suppressions=%s/tests/glibc.supp" % OVS_SRC,
224                "--suppressions=%s/tests/openssl.supp" % OVS_SRC] + cmd
225     else:
226         cmd = ["sudo"] + cmd
227         opts = opts + ["-vconsole:off", "--detach"]
228     _sh(*(cmd + opts))
229 commands.append(run)
230
231
232 def modinst():
233     if not os.path.exists("/lib/modules"):
234         print "Missing modules directory.  Is this a Linux system?"
235         sys.exit(1)
236
237     try:
238         _sh("rmmod", "openvswitch")
239     except subprocess.CalledProcessError, e:
240         pass  # Module isn't loaded
241
242     try:
243         _sh("rm /lib/modules/%s/extra/openvswitch.ko" % uname())
244     except subprocess.CalledProcessError, e:
245         pass  # Module isn't installed
246
247     conf()
248     make()
249     make("modules_install")
250
251     _sh("modprobe", "openvswitch")
252     _sh("dmesg | grep openvswitch | tail -1")
253 commands.append(modinst)
254
255
256 def env():
257     print "export PATH=" + ENV["PATH"]
258 commands.append(env)
259
260
261 def doc():
262     parser.print_help()
263     print \
264 """
265 This program is designed to help developers build and run Open vSwitch without
266 necessarily needing to know the gory details. Given some basic requirements
267 (described below), it can be used to build and run Open vSwitch, keeping
268 runtime files in the user's home directory.
269
270 Basic Configuration:
271     # This section can be run as a script on ubuntu systems.
272
273     # First install the basic requirements needed to build Open vSwitch.
274     sudo apt-get install git build-essential libtool autoconf pkg-config \\
275             libssl-dev gdb linux-headers-`uname -r`
276
277     # Next clone the Open vSwitch source.
278     git clone git://git.openvswitch.org/openvswitch %(ovs)s
279
280     # Setup environment variables.
281     `%(v)s env`
282
283     # Build the switch.
284     %(v)s conf make
285
286     # Install the kernel module
287     sudo insmod %(ovs)s/datapath/linux/openvswitch.ko
288
289     # Run the switch.
290     %(v)s run
291
292 Commands:
293     conf    - Configure the ovs source.
294     make    - Build the source (must have been configured).
295     check   - Run the unit tests.
296     tag     - Run ctags and cscope over the source.
297     kill    - Kill all running instances of ovs.
298     reset   - Reset any runtime configuration in %(run)s.
299     run     - Run ovs.
300     modinst - Build ovs and install the kernel module.
301     env     - Print the required path environment variable.
302     doc     - Print this message.
303 """ % {"ovs": OVS_SRC, "v": sys.argv[0], "run": ROOT}
304     sys.exit(0)
305 commands.append(doc)
306
307
308 def main():
309     global options
310     global parser
311
312     description = "Open vSwitch developer configuration. Try `%prog doc`."
313     cmd_names = [c.__name__ for c in commands]
314     parser = optparse.OptionParser(usage="usage: %prog"
315                                    + " [options] [%s] ..."
316                                    % "|".join(cmd_names),
317                                    description=description)
318
319     group = optparse.OptionGroup(parser, "conf")
320     group.add_option("--disable-Werror", dest="werror", action="store_false",
321                      default=True, help="compile without the Werror flag")
322     group.add_option("--cache-time", dest="cache_time",
323                      action="store_true", help="configure with cached timing")
324     group.add_option("--mandir", dest="mandir", metavar="MANDIR",
325                      help="configure the man documentation install directory")
326
327     for i in range(4):
328         group.add_option("--O%d" % i, dest="optimize", action="store_const",
329                          const=i, help="compile with -O%d" % i)
330     parser.add_option_group(group)
331
332     group = optparse.OptionGroup(parser, "run")
333     group.add_option("-g", "--gdb", dest="gdb", action="store_true",
334                      help="run ovs-vswitchd under gdb")
335     group.add_option("--valgrind", dest="valgrind", action="store_true",
336                      help="run ovs-vswitchd under valgrind")
337     parser.add_option_group(group)
338
339     options, args = parser.parse_args()
340
341     for arg in args:
342         if arg not in cmd_names:
343             print "Unknown argument " + arg
344             doc()
345
346     try:
347         os.chdir(OVS_SRC)
348     except OSError:
349         print "Missing %s." % OVS_SRC
350         doc()
351
352     for arg in args:
353         for cmd in commands:
354             if arg == cmd.__name__:
355                 cmd()
356
357
358 if __name__ == '__main__':
359     main()