Cleanly separate IDL annotations from OVSDB schema information.
authorBen Pfaff <blp@nicira.com>
Thu, 7 Jan 2010 23:52:58 +0000 (15:52 -0800)
committerBen Pfaff <blp@nicira.com>
Tue, 26 Jan 2010 17:46:42 +0000 (09:46 -0800)
Until now, the OVSDB IDL annotations have been glommed together with the
schema information in a single file, and then we've used ovsdb-idlc to
extract the schema from that file.  This commit reverses the process:
the schema and the annotations are stored separately and then glommed
together as necessary at build time.

This new arrangement has a few advantages:

    - We can now easily have multiple different sets of IDL annotations
      for a single OVSDB schema.  For example, some users may not need
      access to columns that other users do.

    - Bugs in ovsdb-idlc cannot screw up the underlying schema (as shown
      by a recent commit).

18 files changed:
Makefile.am
debian/openvswitch-common.install
debian/rules
ovsdb/automake.mk
ovsdb/ovsdb-idlc.1
ovsdb/ovsdb-idlc.in
tests/.gitignore
tests/automake.mk
tests/idltest.ann [new file with mode: 0644]
tests/idltest.ovsidl [deleted file]
tests/idltest.ovsschema [new file with mode: 0644]
tests/ovsdb-idl.at
tests/ovsdb-macros.at
vswitchd/.gitignore
vswitchd/automake.mk
vswitchd/vswitch-idl.ann [new file with mode: 0644]
vswitchd/vswitch-idl.ovsidl [deleted file]
vswitchd/vswitch.ovsschema [new file with mode: 0644]

index bfba76f8211de91d38e96e0934a7e651c973aab7..bb8245efd804a3453023619f9d2f20e1d248e47b 100644 (file)
@@ -48,6 +48,7 @@ noinst_HEADERS =
 noinst_LIBRARIES =
 noinst_PROGRAMS =
 noinst_SCRIPTS =
+OVSIDL_BUILT =
 SUFFIXES =
 
 EXTRA_DIST += soexpand.pl
index 314c762567137b93c46606cbae537fc641aafd5f..c46d9be3cf7c1f20f43293a8081307ace98a525c 100644 (file)
@@ -4,4 +4,4 @@ _debian/utilities/ovs-appctl usr/sbin
 _debian/utilities/ovs-ofctl usr/sbin
 _debian/utilities/ovs-parse-leaks usr/bin
 _debian/utilities/ovs-pki usr/sbin
-_debian/vswitchd/vswitch-idl.ovsschema usr/share/openvswitch
+vswitchd/vswitch-idl.ovsschema usr/share/openvswitch
index 99d1f09ae620bc80c825a11a25d642cd4e3f268c..0d0abf1647f4d88736da6b7141dd07967f9043ba 100755 (executable)
@@ -85,10 +85,6 @@ install-arch: build-arch
        $(MAKE) -C _debian DESTDIR=$(CURDIR)/debian/openvswitch install
        cp debian/openvswitch-switch-config.overrides debian/openvswitch-switch-config/usr/share/lintian/overrides/openvswitch-switch-config
        cp debian/openvswitch-switch.template debian/openvswitch-switch/usr/share/openvswitch/switch/default.template
-       @# If we are working from a "make dist" tarball then make sure that
-       @# the ovsschema file is available in the build directory.
-       test -e _debian/vswitchd/vswitch-idl.ovsschema || \
-               cp vswitchd/vswitch-idl.ovsschema _debian/vswitchd/vswitch-idl.ovsschema
        dh_install -s
        env TERMINFO=debian/openvswitch-switchui/usr/share/terminfo tic -x extras/ezio/ezio3.ti
 
index 1596a4b5add9cfe5722994574df229b8d735071f..86054100bd2a24103b2368a6be14078e68b9117b 100644 (file)
@@ -88,15 +88,26 @@ EXTRA_DIST += \
        ovsdb/ovsdb-idlc.1
 DISTCLEANFILES += ovsdb/ovsdb-idlc
 SUFFIXES += .ovsidl .txt
+OVSDB_IDLC = $(PYTHON) $(srcdir)/ovsdb/ovsdb-idlc.in
 .ovsidl.c:
-       $(PYTHON) $(srcdir)/ovsdb/ovsdb-idlc.in c-idl-source $< > $@.tmp
+       $(OVSDB_IDLC) c-idl-source $< > $@.tmp
        mv $@.tmp $@
 .ovsidl.h:
-       $(PYTHON) $(srcdir)/ovsdb/ovsdb-idlc.in c-idl-header $< > $@.tmp
-       mv $@.tmp $@
-.ovsidl.ovsschema:
-       $(PYTHON) $(srcdir)/ovsdb/ovsdb-idlc.in ovsdb-schema $< > $@.tmp
+       $(OVSDB_IDLC) c-idl-header $< > $@.tmp
        mv $@.tmp $@
 .ovsidl.txt:
-       $(PYTHON) $(srcdir)/ovsdb/ovsdb-idlc.in doc $< | fmt -s > $@.tmp
+       $(OVSDB_IDLC) doc $< | fmt -s > $@.tmp
        mv $@.tmp $@
+
+EXTRA_DIST += $(OVSIDL_BUILT)
+BUILT_SOURCES += $(OVSIDL_BUILT)
+
+# This must be done late: macros in targets are expanded when the
+# target line is read, so if this file were to be included before some
+# other file that added to OVSIDL_BUILT, then those files wouldn't get
+# the dependency.
+#
+# However, current versions of Automake seem to output all variable
+# assignments before any targets, so it doesn't seem to be a problem,
+# at least for now.
+$(OVSIDL_BUILT): ovsdb/ovsdb-idlc.in
index 1311759c0f89680b1c6a2be3bc9ea455e9fc875e..1a7e8041d0a210f23d5d638513822a88b2a8a0bb 100644 (file)
@@ -6,13 +6,11 @@
 ovsdb\-idlc \- Open vSwitch IDL (Interface Definition Language) compiler
 .
 .SH SYNOPSIS
-\fBovsdb\-idlc \fBvalidate\fI schema\fR
+\fBovsdb\-idlc \fBannotate\fI schema annotations\fR 
 .br
-\fBovsdb\-idlc \fBovsdb\-schema\fI schema\fR
+\fBovsdb\-idlc \fBc\-idl\-header\fI idl\fR
 .br
-\fBovsdb\-idlc \fBc\-idl\-header\fI schema\fR
-.br
-\fBovsdb\-idlc \fBc\-idl\-source\fI schema\fR
+\fBovsdb\-idlc \fBc\-idl\-source\fI idl\fR
 .br
 \fBovsdb\-idlc --help\fR
 .br
@@ -26,13 +24,9 @@ installation or configuration time.  Thus, it is not normally
 installed as part of Open vSwitch.
 .
 .PP
-The \fIschema\fR files used as \fBovsdb\-idlc\fR input have the same
-format as the OVSDB schemas, specified in the OVSDB specification,
-with a few additions:
-.
-.IP "\fB//\fR comments"
-Lines that begin with \fB//\fR (two forward slashes) are ignored and
-thus can be used for comments.
+The \fIidl\fR files used as input for most \fBovsdb\-idlc\fR commands
+have the same format as the OVSDB schemas, specified in the OVSDB
+specification, with a few additions:
 .
 .IP "\fB""\fBidlPrefix\fR"" member of <database-schema>"
 This member, which is required, specifies a string that is prefixed to
@@ -57,29 +51,34 @@ the given type.
 Analogous to \fB"keyRefTable"\fR in meaning and effect, except that it
 applies to the \fB"value"\fR member of the <type>.
 .SS "Commands"
-.
-.IP "\fBvalidate\fI schema\fR"
-Reads \fIschema\fR and checks its format, without producing any output.
-.
-.IP "\fBovsdb\-schema\fI schema\fR"
-Reads \fIschema\fR and prints it on standard output with the parts
-that are not part of the OVSDB schema specification stripped out.
-.
-.IP "\fBc\-idl\-header\fI schema\fR"
-Reads \fIschema\fR and prints on standard output a C header file that
+.IP "\fBannotate\fI schema annotations\fR"
+Reads \fIschema\fR, which should be a file in JSON format (ordinarily
+an OVSDB schema file), then reads and executes the Python syntax
+fragment in \fIannotations\fR.  The Python syntax fragment is passed
+the JSON object as a local variable named \fBs\fR.  It may modify this
+data in any way.  After the Python code returns, the object as
+modified is re-serialized as JSON on standard output.
+.
+.IP "\fBc\-idl\-header\fI idl\fR"
+Reads \fIidl\fR and prints on standard output a C header file that
 defines a structure for each table defined by the schema.
 .
-.IP "\fBc\-idl\-source\fI schema\fR"
-Reads \fIschema\fR and prints on standard output a C source file that
+.IP "\fBc\-idl\-source\fI idl\fR"
+Reads \fIidl\fR and prints on standard output a C source file that
 implements C bindings for the database defined by the schema.
 .
+.IP "\fBdoc\fI idl\fR"
+Reads \fIidl\fR and prints on standard output a text file that
+documents the schema.  The output may have very long lines, so it
+makes sense to pipe it through, e.g. \fBfmt \-s\fR.
+.
 .SS "Options"
 .so lib/common.man
 .
 .SH "BUGS"
 \fBovsdb\-idlc\fR is more lenient about the format of OVSDB schemas
-than other OVSDB tools, so the \fBovsdb\-schema\fR command may output
-schemas that other programs refuse to read.
+than other OVSDB tools.  It may successfully parse schemas that, e.g.,
+\fBovsdb\-tool\fR rejects.
 .
 .SH "SEE ALSO"
 The OVSDB specification.
index 716998267d62b54d6f64b8d47b2b1740351ae36a..2dd25d8029cd9acb636b70f5799a51e44e558ab8 100755 (executable)
@@ -1,6 +1,7 @@
 #! @PYTHON@
 
 import getopt
+import os
 import re
 import sys
 
@@ -184,12 +185,12 @@ def atomicTypeToEnglish(base, refTable):
         return base
 
 def parseSchema(filename):
-    file = open(filename, "r")
-    s = ""
-    for line in file:
-        if not line.startswith('//'):
-            s += line
-    return DbSchema.fromJson(json.loads(s))
+    return DbSchema.fromJson(json.load(open(filename, "r")))
+
+def annotateSchema(schemaFile, annotationFile):
+    schemaJson = json.load(open(schemaFile, "r"))
+    execfile(annotationFile, globals(), {"s": schemaJson})
+    json.dump(schemaJson, sys.stdout)
 
 def cBaseType(prefix, type, refTable=None):
     if type == 'uuid' and refTable:
@@ -265,7 +266,8 @@ def cMembers(prefix, columnName, column, const):
                         'comment': ''})
     return members
 
-def printCIDLHeader(schema):
+def printCIDLHeader(schemaFile):
+    schema = parseSchema(schemaFile)
     prefix = schema.idlPrefix
     print '''\
 /* Generated automatically -- do not modify!    -*- buffer-read-only: t -*- */
@@ -323,7 +325,8 @@ def printEnum(members):
     print "    %s" % members[-1]
     print "};"
 
-def printCIDLSource(schema):
+def printCIDLSource(schemaFile):
+    schema = parseSchema(schemaFile)
     prefix = schema.idlPrefix
     print '''\
 /* Generated automatically -- do not modify!    -*- buffer-read-only: t -*- */
@@ -651,10 +654,8 @@ def ovsdb_escape(string):
             return '\\x%02x' % ord(c)
     return re.sub(r'["\\\000-\037]', escape, string)
 
-def printOVSDBSchema(schema):
-    json.dump(schema.toJson(), sys.stdout, sort_keys=True, indent=2)
-
-def printDoc(schema):
+def printDoc(schemaFile):
+    schema = parseSchema(schemaFile)
     print schema.name
     if schema.comment:
         print schema.comment
@@ -676,15 +677,13 @@ def printDoc(schema):
 def usage():
     print """\
 %(argv0)s: ovsdb schema compiler
-usage: %(argv0)s [OPTIONS] ACTION SCHEMA
-where SCHEMA is the ovsdb schema to read (in JSON format).
+usage: %(argv0)s [OPTIONS] COMMAND ARG...
 
-One of the following actions must specified:
-  validate                    validate schema without taking any other action
-  c-idl-header                print C header file for IDL
-  c-idl-source                print C source file for IDL implementation
-  ovsdb-schema                print ovsdb parseable schema
-  doc                         print schema documentation
+The following commands are supported:
+  annotate SCHEMA ANNOTATIONS print SCHEMA combined with ANNOTATIONS
+  c-idl-header IDL            print C header file for IDL
+  c-idl-source IDL            print C source file for IDL implementation
+  doc IDL                     print schema documentation
 
 The following options are also available:
   -h, --help                  display this help message
@@ -695,42 +694,49 @@ The following options are also available:
 if __name__ == "__main__":
     try:
         try:
-            options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
-                                              ['help',
+            options, args = getopt.gnu_getopt(sys.argv[1:], 'C:hV',
+                                              ['directory',
+                                               'help',
                                                'version'])
         except getopt.GetoptError, geo:
             sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
             sys.exit(1)
             
+        for key, value in options:
+            if key in ['-h', '--help']:
+                usage()
+            elif key in ['-V', '--version']:
+                print "ovsdb-idlc (Open vSwitch) @VERSION@"
+            elif key in ['-C', '--directory']:
+                os.chdir(value)
+            else:
+                sys.exit(0)
+            
         optKeys = [key for key, value in options]
-        if '-h' in optKeys or '--help' in optKeys:
-            usage()
-        elif '-V' in optKeys or '--version' in optKeys:
-            print "ovsdb-idlc (Open vSwitch) @VERSION@"
-            sys.exit(0)
-
-        if len(args) != 2:
-            sys.stderr.write("%s: exactly two non-option arguments are "
-                             "required (use --help for help)\n" % argv0)
+
+        if not args:
+            sys.stderr.write("%s: missing command argument "
+                             "(use --help for help)\n" % argv0)
             sys.exit(1)
 
-        action, inputFile = args
-        schema = parseSchema(inputFile)
-        if action == 'validate':
-            pass
-        elif action == 'ovsdb-schema':
-            printOVSDBSchema(schema)
-        elif action == 'c-idl-header':
-            printCIDLHeader(schema)
-        elif action == 'c-idl-source':
-            printCIDLSource(schema)
-        elif action == 'doc':
-            printDoc(schema)
-        else:
-            sys.stderr.write(
-                "%s: unknown action '%s' (use --help for help)\n" %
-                (argv0, action))
+        commands = {"annotate": (annotateSchema, 2),
+                    "c-idl-header": (printCIDLHeader, 1),
+                    "c-idl-source": (printCIDLSource, 1),
+                    "doc": (printDoc, 1)}
+
+        if not args[0] in commands:
+            sys.stderr.write("%s: unknown command \"%s\" "
+                             "(use --help for help)\n" % (argv0, args[0]))
             sys.exit(1)
+
+        func, n_args = commands[args[0]]
+        if len(args) - 1 != n_args:
+            sys.stderr.write("%s: \"%s\" requires %d arguments but %d "
+                             "provided\n"
+                             % (argv0, args[0], n_args, len(args) - 1))
+            sys.exit(1)
+
+        func(*args[1:])
     except Error, e:
         sys.stderr.write("%s: %s\n" % (argv0, e.msg))
         sys.exit(1)
index 3d9b76e31be5474ecae1b37274fe17f07078fdc0..c987014e376cd7dedc184e86a40fcc044065d26d 100644 (file)
@@ -4,7 +4,7 @@
 /atlocal
 /idltest.c
 /idltest.h
-/idltest.ovsschema
+/idltest.ovsidl
 /test-aes128
 /test-classifier
 /test-csum
index f77bdac180a1e5c156c339072f00da41a30d400e..e1738f6991872e5dc6f960cbb0140e08da457b51 100644 (file)
@@ -112,15 +112,22 @@ tests_test_lockfile_SOURCES = tests/test-lockfile.c
 tests_test_lockfile_LDADD = lib/libopenvswitch.a
 
 noinst_PROGRAMS += tests/test-ovsdb
-tests_test_ovsdb_SOURCES = tests/test-ovsdb.c tests/idltest.c tests/idltest.h
+tests_test_ovsdb_SOURCES = \
+       tests/test-ovsdb.c \
+       tests/idltest.c \
+       tests/idltest.h
+EXTRA_DIST += tests/uuidfilt.pl
 tests_test_ovsdb_LDADD = ovsdb/libovsdb.a lib/libopenvswitch.a $(SSL_LIBS)
-EXTRA_DIST += tests/uuidfilt.pl tests/idltest.ovsidl
-BUILT_SOURCES += tests/idltest.c tests/idltest.h
-noinst_DATA += tests/idltest.ovsschema
-DISTCLEANFILES += tests/idltest.ovsschema
-tests/idltest.c tests/idltest.h tests/idltest.ovsschema: ovsdb/ovsdb-idlc.in
+
+# idltest schema and IDL
+OVSIDL_BUILT +=        tests/idltest.c tests/idltest.h tests/idltest.ovsidl
+IDLTEST_IDL_FILES = tests/idltest.ovsschema tests/idltest.ann
+EXTRA_DIST += $(IDLTEST_IDL_FILES)
+tests/idltest.ovsidl: $(IDLTEST_IDL_FILES)
+       $(OVSDB_IDLC) -C $(srcdir) annotate $(IDLTEST_IDL_FILES) > $@.tmp
+       mv $@.tmp $@
+
 tests/idltest.c: tests/idltest.h
-EXTRA_DIST += tests/idltest.c tests/idltest.h tests/idltest.ovsschema
 
 noinst_PROGRAMS += tests/test-reconnect
 tests_test_reconnect_SOURCES = tests/test-reconnect.c
diff --git a/tests/idltest.ann b/tests/idltest.ann
new file mode 100644 (file)
index 0000000..2ffd1af
--- /dev/null
@@ -0,0 +1,13 @@
+# -*- python -*-
+
+# This code, when invoked by "ovsdb-idlc annotate" (by the build
+# process), annotates idltest.ovsschema with additional data that give
+# the ovsdb-idl engine information about the types involved, so that
+# it can generate more programmer-friendly data structures.
+
+s["idlPrefix"] = "idltest_"
+s["idlHeader"] = "\"tests/idltest.h\""
+s["tables"]["link1"]["columns"]["k"]["type"]["keyRefTable"] = "link1"
+s["tables"]["link1"]["columns"]["ka"]["type"]["keyRefTable"] = "link1"
+s["tables"]["link1"]["columns"]["l2"]["type"]["keyRefTable"] = "link2"
+s["tables"]["link2"]["columns"]["l1"]["type"]["keyRefTable"] = "link1"
diff --git a/tests/idltest.ovsidl b/tests/idltest.ovsidl
deleted file mode 100644 (file)
index 75d50ef..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// This is an ovsdb-idl schema.  The OVSDB IDL compiler, ovsdb-idlc,
-// can translate it into an OVSDB schema (which simply entails
-// deleting some members from the schema) or C headers or source for
-// use with the IDL at runtime.
-//
-
-{"name": "idltest",
- "idlPrefix": "idltest_",
- "idlHeader": "\"tests/idltest.h\"",
- "tables": {
-   "simple": {
-     "columns": {
-       "i": {"type": "integer"},
-       "r": {"type": "real"},
-       "b": {"type": "boolean"},
-       "s": {"type": "string"},
-       "u": {"type": "uuid"},
-       "ia": {"type": {"key": "integer", "min": 0, "max": "unlimited"}},
-       "ra": {"type": {"key": "real", "min": 0, "max": "unlimited"}},
-       "ba": {"type": {"key": "boolean", "min": 0, "max": "unlimited"}},
-       "sa": {"type": {"key": "string", "min": 0, "max": "unlimited"}},
-       "ua": {"type": {"key": "uuid", "min": 0, "max": "unlimited"}}}},
-   "link1": {
-     "columns": {
-       "i": {"type": "integer"},
-       "k": {"type": {"key": "uuid", "keyRefTable": "link1"}},
-       "ka": {"type": {"key": "uuid", "keyRefTable": "link1",
-                       "min": 0, "max": "unlimited"}},
-       "l2": {"type": {"key": "uuid", "keyRefTable": "link2",
-                       "min": 0, "max": 1}}}},
-   "link2": {
-     "columns": {
-       "i": {"type": "integer"},
-       "l1": {"type": {"key": "uuid", "keyRefTable": "link1",
-                       "min": 0, "max": 1}}}}}}
diff --git a/tests/idltest.ovsschema b/tests/idltest.ovsschema
new file mode 100644 (file)
index 0000000..239a343
--- /dev/null
@@ -0,0 +1,25 @@
+{"name": "idltest",
+ "tables": {
+   "simple": {
+     "columns": {
+       "i": {"type": "integer"},
+       "r": {"type": "real"},
+       "b": {"type": "boolean"},
+       "s": {"type": "string"},
+       "u": {"type": "uuid"},
+       "ia": {"type": {"key": "integer", "min": 0, "max": "unlimited"}},
+       "ra": {"type": {"key": "real", "min": 0, "max": "unlimited"}},
+       "ba": {"type": {"key": "boolean", "min": 0, "max": "unlimited"}},
+       "sa": {"type": {"key": "string", "min": 0, "max": "unlimited"}},
+       "ua": {"type": {"key": "uuid", "min": 0, "max": "unlimited"}}}},
+   "link1": {
+     "columns": {
+       "i": {"type": "integer"},
+       "k": {"type": {"key": "uuid"}},
+       "ka": {"type": {"key": "uuid",
+                       "min": 0, "max": "unlimited"}},
+       "l2": {"type": {"key": "uuid", "min": 0, "max": 1}}}},
+   "link2": {
+     "columns": {
+       "i": {"type": "integer"},
+       "l1": {"type": {"key": "uuid", "min": 0, "max": 1}}}}}}
index 0ce65355aa4700bd1bddad0a5b113afba4dbb749..d16982bbb1c1b9054db7575fc56c29007dac7e53 100644 (file)
@@ -17,17 +17,8 @@ AT_BANNER([OVSDB -- interface description language (IDL)])
 m4_define([OVSDB_CHECK_IDL], 
   [AT_SETUP([$1])
    AT_KEYWORDS([ovsdb server idl positive $5])
-   OVS_CHECK_LCOV(
-     [SCHEMA=$abs_builddir/idltest.ovsschema
-      if test ! -e $SCHEMA; then
-        SCHEMA=$abs_srcdir/idltest.ovsschema
-          if test ! -e $SCHEMA; then
-            echo 'Failed to find idltest.ovsschema'
-            exit 1
-          fi
-      fi
-      ovsdb-tool create db $SCHEMA],
-     [0], [stdout], [ignore])
+   OVS_CHECK_LCOV([ovsdb-tool create db $abs_srcdir/idltest.ovsschema],
+                  [0], [stdout], [ignore])
    AT_CHECK([ovsdb-server '-vPATTERN:console:ovsdb-server|%c|%m' --detach --pidfile=$PWD/server-pid --remote=punix:socket --unixctl=$PWD/unixctl db], [0], [ignore], [ignore])
    m4_if([$2], [], [],
      [OVS_CHECK_LCOV([ovsdb-client transact unix:socket $2], [0], [ignore], [ignore], [kill `cat server-pid`])])
index 96c273efaa293eed87acc6d82b22322ce8f0925f..c0033b337892bef03fb3bffb6983126015223fc4 100644 (file)
@@ -11,7 +11,7 @@ m4_define([OVSDB_INIT],
             exit 1
           fi
       fi
-      ovsdb-tool create $1 $SCHEMA],
+      ovsdb-tool create $1 $abs_top_srcdir/vswitchd/vswitch.ovsschema],
      [0], [stdout], [ignore])
    OVS_CHECK_LCOV(
      [[ovsdb-tool transact $1 \
index 1943444e2b8c2dede9977ff30192a1aab80a7318..872a72673f056d4267d66fee146f3f81b449e8a5 100644 (file)
@@ -7,5 +7,5 @@
 /ovs-vswitchd.conf.5
 /vswitch-idl.c
 /vswitch-idl.h
-/vswitch-idl.ovsschema
+/vswitch-idl.ovsidl
 /vswitch-idl.txt
index f39a032542db85c78853044790bd09d5ff1c05a8..9121169afec5309e855d0a0cc3604afc4f97a128 100644 (file)
@@ -32,18 +32,15 @@ EXTRA_DIST += \
        vswitchd/ovs-vswitchd.8.in \
        vswitchd/ovs-brcompatd.8.in
 
-EXTRA_DIST += vswitchd/vswitch-idl.ovsidl
-BUILT_SOURCES += vswitchd/vswitch-idl.c vswitchd/vswitch-idl.h
-DISTCLEANFILES += vswitchd/vswitch-idl.c vswitchd/vswitch-idl.h
-noinst_DATA += vswitchd/vswitch-idl.ovsschema vswitchd/vswitch-idl.txt
-DISTCLEANFILES += vswitchd/vswitch-idl.ovsschema vswitchd/vswitch-idl.txt
-vswitchd/vswitch-idl.c vswitchd/vswitch-idl.h \
-vswitchd/vswitch-idl.ovsschema vswitchd/vswitch-idl.txt: \
-       ovsdb/ovsdb-idlc.in
-vswitchd/vswitch-idl.c: vswitchd/vswitch-idl.h
-EXTRA_DIST += \
+
+# vswitch schema and IDL
+OVSIDL_BUILT += \
        vswitchd/vswitch-idl.c \
        vswitchd/vswitch-idl.h \
-       vswitchd/vswitch-idl.ovsschema \
-       vswitchd/vswitch-idl.txt
-
+       vswitchd/vswitch-idl.ovsidl
+VSWITCH_IDL_FILES = vswitchd/vswitch.ovsschema vswitchd/vswitch-idl.ann
+noinst_DATA += vswitchd/vswitch-idl.txt
+EXTRA_DIST += $(VSWITCH_IDL_FILES) vswitchd/vswitch-idl.txt
+vswitchd/vswitch-idl.ovsidl: $(VSWITCH_IDL_FILES)
+       $(OVSDB_IDLC) -C $(srcdir) annotate $(VSWITCH_IDL_FILES) > $@.tmp
+       mv $@.tmp $@
diff --git a/vswitchd/vswitch-idl.ann b/vswitchd/vswitch-idl.ann
new file mode 100644 (file)
index 0000000..ff5766a
--- /dev/null
@@ -0,0 +1,20 @@
+# -*- python -*-
+
+# This code, when invoked by "ovsdb-idlc annotate" (by the build
+# process), annotates vswitch.ovsschema with additional data that give
+# the ovsdb-idl engine information about the types involved, so that
+# it can generate more programmer-friendly data structures.
+
+s["idlPrefix"] = "ovsrec_"
+s["idlHeader"] = "\"vswitchd/vswitch-idl.h\""
+s["tables"]["Open_vSwitch"]["columns"]["bridges"]["type"]["keyRefTable"] = "Bridge"
+s["tables"]["Open_vSwitch"]["columns"]["controller"]["type"]["keyRefTable"] = "Controller"
+s["tables"]["Open_vSwitch"]["columns"]["ssl"]["type"]["keyRefTable"] = "SSL"
+s["tables"]["Bridge"]["columns"]["ports"]["type"]["keyRefTable"] = "Port"
+s["tables"]["Bridge"]["columns"]["mirrors"]["type"]["keyRefTable"] = "Mirror"
+s["tables"]["Bridge"]["columns"]["netflow"]["type"]["keyRefTable"] = "NetFlow"
+s["tables"]["Bridge"]["columns"]["controller"]["type"]["keyRefTable"] = "Controller"
+s["tables"]["Port"]["columns"]["interfaces"]["type"]["keyRefTable"] = "Interface"
+s["tables"]["Mirror"]["columns"]["select_src_port"]["type"]["keyRefTable"] = "Port"
+s["tables"]["Mirror"]["columns"]["select_dst_port"]["type"]["keyRefTable"] = "Port"
+s["tables"]["Mirror"]["columns"]["output_port"]["type"]["keyRefTable"] = "Port"
diff --git a/vswitchd/vswitch-idl.ovsidl b/vswitchd/vswitch-idl.ovsidl
deleted file mode 100644 (file)
index 8726ba3..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-//
-// This is an ovsdb-idl schema.  The OVSDB IDL compiler, ovsdb-idlc,
-// can translate it into an OVSDB schema (which simply entails
-// deleting some members from the schema) or C headers or source for
-// use with the IDL at runtime.
-//
-
-{"name": "ovs_vswitchd_db",
- "comment": "Configuration for one Open vSwitch daemon.",
- "idlPrefix": "ovsrec_",
- "idlHeader": "\"vswitchd/vswitch-idl.h\"",
- "tables": {
-   "Open_vSwitch": {
-     "comment": "Configuration for an Open vSwitch daemon.",
-     "columns": {
-       "bridges": {
-         "comment": "Set of bridges managed by the daemon.",
-         "type": {"key": "uuid", "keyRefTable": "Bridge",
-                  "min": 0, "max": "unlimited"}},
-       "management_id": {
-         "comment": "Exactly 12 hex digits that identify the daemon.",
-         "type": "string"},
-       "controller": {
-         "comment": "Default Controller used by bridges.",
-         "type": {"key": "uuid", "keyRefTable": "Controller", "min": 0, "max": 1}},
-       "managers": {
-         "comment": "Remote database clients to which the Open vSwitch's database server should connect or to which it should listen.",
-         "type": {"key": "string", "min": 0, "max": "unlimited"}},
-       "ssl": {
-         "comment": "SSL used globally by the daemon.",
-         "type": {"key": "uuid", "keyRefTable": "SSL", "min": 0, "max": 1}},
-       "next_cfg": {
-         "comment": "Sequence number for client to increment when it modifies the configuration and wishes to wait for Open vSwitch to finish applying the changes.",
-         "type": "integer"},
-       "cur_cfg": {
-         "comment": "Sequence number that Open vSwitch sets to the current value of 'next_cfg' after it finishing applying a set of configuration changes.",
-         "type": "integer"}}},
-   "Bridge": {
-     "comment": "Configuration for a bridge within an Open_vSwitch.",
-     "columns": {
-       "name": {
-         "comment": "Bridge identifier.  Should be alphanumeric and no more than about 8 bytes long.  Must be unique among the names of ports, interfaces, and bridges on a host.",
-         "type": "string"},
-       "datapath_id": {
-         "comment": "Reports the OpenFlow datapath ID in use.  Exactly 12 hex digits.",
-         "type": {"key": "string", "min": 0, "max": 1},
-         "ephemeral": true},
-       "ports": {
-         "comment": "Ports included in the bridge.",
-         "type": {"key": "uuid", "keyRefTable": "Port", "min": 0, "max": "unlimited"}},
-       "mirrors": {
-         "comment": "Port mirroring configuration.",
-         "type": {"key": "uuid", "keyRefTable": "Mirror", "min": 0, "max": "unlimited"}},
-       "netflow": {
-         "comment": "NetFlow configuration.",
-         "type": {"key": "uuid", "keyRefTable": "NetFlow", "min": 0, "max": 1}},
-       "controller": {
-         "comment": "OpenFlow controller.  If unset, defaults to that specified by the parent Open_vSwitch.",
-         "type": {"key": "uuid", "keyRefTable": "Controller", "min": 0, "max": 1}},
-       "other_config": {
-         "comment": "Key-value pairs for configuring rarely used bridge features.  The currently defined key-value pairs are: \"datapath-id\", exactly 12 hex digits to set the OpenFlow datapath ID to a specific value; \"hwaddr\", exactly 12 hex digits in the form \"XX:XX:XX:XX:XX:XX\" to set the hardware address of the local port and influence the datapath ID.",
-         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
-       "external_ids": {
-         "comment": "Key-value pairs that identify this bridge's role in external systems.  The currently defined key-value pairs are: \"xs-network-uuids\", a space-delimited set of the Citrix XenServer network UUIDs with which this bridge is associated; \"xs-network-names\", a semicolon-delimited set of Citrix XenServer network names with which this bridge is associated.",
-         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
-       "flood_vlans": {
-         "comment": "VLAN IDs of VLANs on which MAC address learning should be disabled, so that packets are flooded instead of being sent to specific ports that are believed to contain packets' destination MACs.  This should ordinarily be used to disable MAC learning on VLANs used for mirroring (RSPAN VLANs).  It may also be useful for debugging.",
-         "type": {"key": "integer", "min": 0, "max": 4096}
-}}},
-   "Port": {
-     "comment": "A port within a Bridge.  May contain a single Interface or multiple (bonded) Interfaces.",
-     "columns": {
-       "name": {
-         "comment": "Port name.  Should be alphanumeric and no more than about 8 bytes long.    May be the same as the interface name, for non-bonded ports.  Must otherwise be unique among the names of ports, interfaces, and bridges on a host.",
-         "type": "string"},
-       "interfaces": {
-         "comment": "The Port's Interfaces.  If there is more than one, this is a bonded Port.",
-         "type": {"key": "uuid", "keyRefTable": "Interface", "min": 1, "max": "unlimited"}},
-       "trunks": {
-         "comment": "The 802.1Q VLAN(s) that this port trunks.  Should be empty if this port trunks all VLAN(s) or if this is not a trunk port.",
-         "type": {"key": "integer", "min": 0, "max": 4096}},
-       "tag": {
-         "comment": "This port's implicitly tagged VLAN.  Should be empty if this is a trunk port.",
-         "type": {"key": "integer", "min": 0, "max": 1}},
-       "mac": {
-         "comment": "The MAC address to use for this port for the purpose of choosing the bridge's MAC address.  This column does not necessarily reflect the port's actual MAC address, nor will setting it change the port's actual MAC address.  Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
-         "type": {"key": "string", "min": 0, "max": 1}},
-       "bond_updelay": {
-         "comment": "For a bonded port, the number of milliseconds for which carrier must stay up on an interface before the interface is considered to be up.  Ignored for non-bonded ports.",
-         "type": "integer"},
-       "bond_downdelay": {
-         "comment": "For a bonded port, the number of milliseconds for which carrier must stay down on an interface before the interface is considered to be down.  Ignored for non-bonded ports.",
-         "type": "integer"},
-       "bond_fake_iface": {
-         "comment": "For a bonded port, whether to create a fake interface with the name of the port.  Use only for compatibility with legacy software that requires this.",
-         "type": "boolean"},
-       "fake_bridge": {
-         "comment": "Does this port represent a sub-bridge for its tagged VLAN within the Bridge?  See ovs-vsctl(8) for more information.",
-         "type": "boolean"},
-       "other_config": {
-         "comment": "Key-value pairs for configuring rarely used port features.  The currently defined key-value pairs are: \"hwaddr\", exactly 12 hex digits in the form \"XX:XX:XX:XX:XX:XX\".",
-         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
-       "external_ids": {
-         "comment": "Key-value pairs that identify this port's role in external systems.  No key-value pairs native to Port are currently defined.  For fake bridges (see the \"fake-bridge\" column), external IDs for the fake bridge are defined here by prefixing their keys with \"fake-bridge\", e.g. \"fake-bridge-xs-network-uuids\".",
-         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}},
-   "Interface": {
-     "comment": "An interface within a Port.",
-     "columns": {
-       "name": {
-         "comment": "Interface name.  Should be alphanumeric and no more than about 8 bytes long.  May be the same as the port name, for non-bonded ports.  Must otherwise be unique among the names of ports, interfaces, and bridges on a host.",
-         "type": "string"},
-       "type": {
-         "comment": "The interface type.  Normal network devices, e.g.  eth0, have type \"system\" or \"\" (which are synonyms).  Internal ports have type \"internal\".  TUN/TAP devices have type \"tap\".  GRE devices have type \"gre\".",
-         "type": "string"},
-       "options": {
-         "comment": "Configuration options whose interpretation varies based on \"type\".",
-         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
-       "ingress_policing_rate": {
-         "comment": "Maximum rate for data received on this interface, in kbps.  Set to 0 to disable policing.",
-         "type": "integer"},
-       "ingress_policing_burst": {
-         "comment": "Maximum burst size for data received on this interface, in kb.  The default burst size if set to 0 is 1000 kb.",
-         "type": "integer"},
-       "mac": {
-         "comment": "Ethernet address to set for this interface.  If unset then the default MAC address is used.  May not be supported on all interfaces.  Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
-         "type": {"key": "string", "min": 0, "max": 1}},
-       "external_ids": {
-         "comment": "Key-value pairs that identify this interface's role in external systems.  The currently defined key-value pairs are: \"xs-vif-uuid\", the UUID of the Citrix XenServer VIF associated with this interface; \"xs-network-uuid\", the UUID of the Citrix XenServer network to which this interface is attached; \"xs-vif-vm-uuid\", the UUID of the Citrix XenServer VM to which this interface belongs; \"xs-vif-mac\", the value of the \"MAC\" field in the Citrix XenServer VIF record for this interface.",
-         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
-       "ofport": {
-         "comment": "OpenFlow port number for this interface.  This is populated when the port number becomes known.  Before it is populated its value will be missing.  If the interface cannot be added then this is indicated by a value of -1.",
-         "type": {"key": "integer", "min": 0, "max": 1},
-         "ephemeral": true}}},
-   "Mirror": {
-     "comment": "A port mirror within a Bridge.",
-     "columns": {
-       "name": {
-         "comment": "Arbitrary identifier for the Mirror.",
-         "type": "string"},
-       "select_src_port": {
-         "comment": "Ports on which arriving packets are selected for mirroring.",
-         "type": {"key": "uuid", "keyRefTable": "Port", "min": 0, "max": "unlimited"}},
-       "select_dst_port": {
-         "comment": "Ports on which departing packets are selected for mirroring.",
-         "type": {"key": "uuid", "keyRefTable": "Port", "min": 0, "max": "unlimited"}},
-       "select_vlan": {
-         "comment": "VLANs on which packets are selected for mirroring.",
-         "type": {"key": "integer", "min": 0, "max": 4096}},
-       "output_port": {
-         "comment": "Output port for selected packets.  Mutually exclusive with output_vlan.",
-         "type": {"key": "uuid", "keyRefTable": "Port", "min": 0, "max": 1}},
-       "output_vlan": {
-         "comment": "Output VLAN for selected packets.  Mutually exclusive with output_port.",
-         "type": {"key": "integer", "min": 0, "max": 1}}}},
-   "NetFlow": {
-     "comment": "A NetFlow target.",
-     "columns": {
-       "targets": {
-         "comment": "NetFlow targets in the form \"IP:PORT\".",
-         "type": {"key": "string", "min": 1, "max": "unlimited"}},
-       "engine_type": {
-         "comment": "Engine type to use in NetFlow messages.  Defaults to datapath index if not specified.",
-         "type": {"key": "integer", "min": 0, "max": 1}},
-       "engine_id": {
-         "comment": "Engine ID to use in NetFlow messages.  Defaults to datapath index if not specified.",
-         "type": {"key": "integer", "min": 0, "max": 1}},
-       "add_id_to_interface": {
-         "comment": "Place least-significant 7 bits of engine ID into most significant bits of ingress and egress interface fields of NetFlow records?",
-         "type": "boolean"},
-       "active_timeout": {
-         "comment": "Active timeout interval, in seconds.  A value of 0 requests the default timeout; a negative value disables active timeouts.",
-         "type": "integer"}}},
-   "Controller": {
-     "comment": "An OpenFlow controller.",
-     "columns": {
-       "target": {
-         "comment": "Connection method for controller, e.g. \"ssl:...\", \"tcp:...\".  The special string \"discover\" enables controller discovery.  The special string \"none\" disables the controller.",
-         "type": "string"},
-       "max_backoff": {
-         "comment": "Maximum number of milliseconds to wait between connection attempts.  Default is implementation-specific.",
-         "type": {"key": "integer", "min": 0, "max": 1}},
-       "inactivity_probe": {
-         "comment": "Maximum number of milliseconds of idle time on connection to controller before sending an inactivity probe message.  Default is implementation-specific.",
-         "type": {"key": "integer", "min": 0, "max": 1}},
-       "fail_mode": {
-         "comment": "Either \"standalone\" or \"secure\", or empty to use the implementation's default.",
-         "type": {"key": "string", "min": 0, "max": 1}},
-       "discover_accept_regex": {
-         "comment": "If \"target\" is \"discover\", a POSIX extended regular expression against which the discovered controller location is validated.  If not specified, the default is implementation-specific.",
-         "type": {"key": "string", "min": 0, "max": 1}},
-       "discover_update_resolv_conf": {
-         "comment": "If \"target\" is \"discover\", whether to update /etc/resolv.conf when the controller is discovered.  If not specified, the default is implementation-specific.",
-         "type": {"key": "boolean", "min": 0, "max": 1}},
-       "connection_mode": {
-         "comment": "Either \"in-band\" or \"out-of-band\".  If not specified, the default is implementation-specific.",
-         "type": {"key": "string", "min": 0, "max": 1}},
-       "local_ip": {
-         "comment": "If \"target\" is not \"discover\", the IP address to configure on the local port.",
-         "type": {"key": "string", "min": 0, "max": 1}},
-       "local_netmask": {
-         "comment": "If \"target\" is not \"discover\", the IP netmask to configure on the local port.",
-         "type": {"key": "string", "min": 0, "max": 1}},
-       "local_gateway": {
-         "comment": "If \"target\" is not \"discover\", the IP gateway to configure on the local port.",
-         "type": {"key": "string", "min": 0, "max": 1}},
-       "controller_rate_limit": {
-         "comment": "The maximum rate at which packets will be forwarded to the OpenFlow controller, in packets per second.  If not specified, the default is implementation-specific.",
-         "type": {"key": "integer", "min": 0, "max": 1}},
-       "controller_burst_limit": {
-         "comment": "The maximum number of unused packet credits that the bridge will allow to accumulate, in packets.  If not specified, the default is implementation-specific.",
-         "type": {"key": "integer", "min": 0, "max": 1}}}},
-   "SSL": {
-     "comment": "SSL configuration for an Open_vSwitch.",
-     "columns": {
-       "private_key": {
-         "comment": "Name of a PEM file containing the private key used as the switch's identity for SSL connections to the controller.",
-         "type": "string"},
-       "certificate": {
-         "comment": "Name of a PEM file containing a certificate, signed by the certificate authority (CA) used by the controller and manager, that certifies the switch's private key, identifying a trustworthy switch.",
-         "type": "string"},
-       "ca_cert": {
-         "comment": "Name of a PEM file containing the CA certificate used to verify that the switch is connected to a trustworthy controller.",
-         "type": "string"},
-       "bootstrap_ca_cert": {
-         "comment": "If set to true, then Open vSwitch will attempt to obtain the CA certificate from the controller on its first SSL connection and save it to the named PEM file. If it is successful, it will immediately drop the connection and reconnect, and from then on all SSL connections must be authenticated by a certificate signed by the CA certificate thus obtained.  This option exposes the SSL connection to a man-in-the-middle attack obtaining the initial CA certificate, but it may be useful for bootstrapping.",
-         "type": "boolean"}}}}}
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
new file mode 100644 (file)
index 0000000..2c7fdf1
--- /dev/null
@@ -0,0 +1,216 @@
+{"name": "ovs_vswitchd_db",
+ "comment": "Configuration for one Open vSwitch daemon.",
+ "tables": {
+   "Open_vSwitch": {
+     "comment": "Configuration for an Open vSwitch daemon.",
+     "columns": {
+       "bridges": {
+         "comment": "Set of bridges managed by the daemon.",
+         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
+       "management_id": {
+         "comment": "Exactly 12 hex digits that identify the daemon.",
+         "type": "string"},
+       "controller": {
+         "comment": "Default Controller used by bridges.",
+         "type": {"key": "uuid", "min": 0, "max": 1}},
+       "managers": {
+         "comment": "Remote database clients to which the Open vSwitch's database server should connect or to which it should listen.",
+         "type": {"key": "string", "min": 0, "max": "unlimited"}},
+       "ssl": {
+         "comment": "SSL used globally by the daemon.",
+         "type": {"key": "uuid", "min": 0, "max": 1}},
+       "next_cfg": {
+         "comment": "Sequence number for client to increment when it modifies the configuration and wishes to wait for Open vSwitch to finish applying the changes.",
+         "type": "integer"},
+       "cur_cfg": {
+         "comment": "Sequence number that Open vSwitch sets to the current value of 'next_cfg' after it finishing applying a set of configuration changes.",
+         "type": "integer"}}},
+   "Bridge": {
+     "comment": "Configuration for a bridge within an Open_vSwitch.",
+     "columns": {
+       "name": {
+         "comment": "Bridge identifier.  Should be alphanumeric and no more than about 8 bytes long.  Must be unique among the names of ports, interfaces, and bridges on a host.",
+         "type": "string"},
+       "datapath_id": {
+         "comment": "Reports the OpenFlow datapath ID in use.  Exactly 12 hex digits.",
+         "type": {"key": "string", "min": 0, "max": 1},
+         "ephemeral": true},
+       "ports": {
+         "comment": "Ports included in the bridge.",
+         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
+       "mirrors": {
+         "comment": "Port mirroring configuration.",
+         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
+       "netflow": {
+         "comment": "NetFlow configuration.",
+         "type": {"key": "uuid", "min": 0, "max": 1}},
+       "controller": {
+         "comment": "OpenFlow controller.  If unset, defaults to that specified by the parent Open_vSwitch.",
+         "type": {"key": "uuid", "min": 0, "max": 1}},
+       "other_config": {
+         "comment": "Key-value pairs for configuring rarely used bridge features.  The currently defined key-value pairs are: \"datapath-id\", exactly 12 hex digits to set the OpenFlow datapath ID to a specific value; \"hwaddr\", exactly 12 hex digits in the form \"XX:XX:XX:XX:XX:XX\" to set the hardware address of the local port and influence the datapath ID.",
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
+       "external_ids": {
+         "comment": "Key-value pairs that identify this bridge's role in external systems.  The currently defined key-value pairs are: \"xs-network-uuids\", a space-delimited set of the Citrix XenServer network UUIDs with which this bridge is associated; \"xs-network-names\", a semicolon-delimited set of Citrix XenServer network names with which this bridge is associated.",
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
+       "flood_vlans": {
+         "comment": "VLAN IDs of VLANs on which MAC address learning should be disabled, so that packets are flooded instead of being sent to specific ports that are believed to contain packets' destination MACs.  This should ordinarily be used to disable MAC learning on VLANs used for mirroring (RSPAN VLANs).  It may also be useful for debugging.",
+         "type": {"key": "integer", "min": 0, "max": 4096}
+}}},
+   "Port": {
+     "comment": "A port within a Bridge.  May contain a single Interface or multiple (bonded) Interfaces.",
+     "columns": {
+       "name": {
+         "comment": "Port name.  Should be alphanumeric and no more than about 8 bytes long.    May be the same as the interface name, for non-bonded ports.  Must otherwise be unique among the names of ports, interfaces, and bridges on a host.",
+         "type": "string"},
+       "interfaces": {
+         "comment": "The Port's Interfaces.  If there is more than one, this is a bonded Port.",
+         "type": {"key": "uuid", "min": 1, "max": "unlimited"}},
+       "trunks": {
+         "comment": "The 802.1Q VLAN(s) that this port trunks.  Should be empty if this port trunks all VLAN(s) or if this is not a trunk port.",
+         "type": {"key": "integer", "min": 0, "max": 4096}},
+       "tag": {
+         "comment": "This port's implicitly tagged VLAN.  Should be empty if this is a trunk port.",
+         "type": {"key": "integer", "min": 0, "max": 1}},
+       "mac": {
+         "comment": "The MAC address to use for this port for the purpose of choosing the bridge's MAC address.  This column does not necessarily reflect the port's actual MAC address, nor will setting it change the port's actual MAC address.  Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "bond_updelay": {
+         "comment": "For a bonded port, the number of milliseconds for which carrier must stay up on an interface before the interface is considered to be up.  Ignored for non-bonded ports.",
+         "type": "integer"},
+       "bond_downdelay": {
+         "comment": "For a bonded port, the number of milliseconds for which carrier must stay down on an interface before the interface is considered to be down.  Ignored for non-bonded ports.",
+         "type": "integer"},
+       "bond_fake_iface": {
+         "comment": "For a bonded port, whether to create a fake interface with the name of the port.  Use only for compatibility with legacy software that requires this.",
+         "type": "boolean"},
+       "fake_bridge": {
+         "comment": "Does this port represent a sub-bridge for its tagged VLAN within the Bridge?  See ovs-vsctl(8) for more information.",
+         "type": "boolean"},
+       "other_config": {
+         "comment": "Key-value pairs for configuring rarely used port features.  The currently defined key-value pairs are: \"hwaddr\", exactly 12 hex digits in the form \"XX:XX:XX:XX:XX:XX\".",
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
+       "external_ids": {
+         "comment": "Key-value pairs that identify this port's role in external systems.  No key-value pairs native to Port are currently defined.  For fake bridges (see the \"fake-bridge\" column), external IDs for the fake bridge are defined here by prefixing their keys with \"fake-bridge\", e.g. \"fake-bridge-xs-network-uuids\".",
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}},
+   "Interface": {
+     "comment": "An interface within a Port.",
+     "columns": {
+       "name": {
+         "comment": "Interface name.  Should be alphanumeric and no more than about 8 bytes long.  May be the same as the port name, for non-bonded ports.  Must otherwise be unique among the names of ports, interfaces, and bridges on a host.",
+         "type": "string"},
+       "type": {
+         "comment": "The interface type.  Normal network devices, e.g.  eth0, have type \"system\" or \"\" (which are synonyms).  Internal ports have type \"internal\".  TUN/TAP devices have type \"tap\".  GRE devices have type \"gre\".",
+         "type": "string"},
+       "options": {
+         "comment": "Configuration options whose interpretation varies based on \"type\".",
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
+       "ingress_policing_rate": {
+         "comment": "Maximum rate for data received on this interface, in kbps.  Set to 0 to disable policing.",
+         "type": "integer"},
+       "ingress_policing_burst": {
+         "comment": "Maximum burst size for data received on this interface, in kb.  The default burst size if set to 0 is 1000 kb.",
+         "type": "integer"},
+       "mac": {
+         "comment": "Ethernet address to set for this interface.  If unset then the default MAC address is used.  May not be supported on all interfaces.  Exactly 12 hex digits in the form XX:XX:XX:XX:XX:XX.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "external_ids": {
+         "comment": "Key-value pairs that identify this interface's role in external systems.  The currently defined key-value pairs are: \"xs-vif-uuid\", the UUID of the Citrix XenServer VIF associated with this interface; \"xs-network-uuid\", the UUID of the Citrix XenServer network to which this interface is attached; \"xs-vif-vm-uuid\", the UUID of the Citrix XenServer VM to which this interface belongs; \"xs-vif-mac\", the value of the \"MAC\" field in the Citrix XenServer VIF record for this interface.",
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
+       "ofport": {
+         "comment": "OpenFlow port number for this interface.  This is populated when the port number becomes known.  Before it is populated its value will be missing.  If the interface cannot be added then this is indicated by a value of -1.",
+         "type": {"key": "integer", "min": 0, "max": 1},
+         "ephemeral": true}}},
+   "Mirror": {
+     "comment": "A port mirror within a Bridge.",
+     "columns": {
+       "name": {
+         "comment": "Arbitrary identifier for the Mirror.",
+         "type": "string"},
+       "select_src_port": {
+         "comment": "Ports on which arriving packets are selected for mirroring.",
+         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
+       "select_dst_port": {
+         "comment": "Ports on which departing packets are selected for mirroring.",
+         "type": {"key": "uuid", "min": 0, "max": "unlimited"}},
+       "select_vlan": {
+         "comment": "VLANs on which packets are selected for mirroring.",
+         "type": {"key": "integer", "min": 0, "max": 4096}},
+       "output_port": {
+         "comment": "Output port for selected packets.  Mutually exclusive with output_vlan.",
+         "type": {"key": "uuid", "min": 0, "max": 1}},
+       "output_vlan": {
+         "comment": "Output VLAN for selected packets.  Mutually exclusive with output_port.",
+         "type": {"key": "integer", "min": 0, "max": 1}}}},
+   "NetFlow": {
+     "comment": "A NetFlow target.",
+     "columns": {
+       "targets": {
+         "comment": "NetFlow targets in the form \"IP:PORT\".",
+         "type": {"key": "string", "min": 1, "max": "unlimited"}},
+       "engine_type": {
+         "comment": "Engine type to use in NetFlow messages.  Defaults to datapath index if not specified.",
+         "type": {"key": "integer", "min": 0, "max": 1}},
+       "engine_id": {
+         "comment": "Engine ID to use in NetFlow messages.  Defaults to datapath index if not specified.",
+         "type": {"key": "integer", "min": 0, "max": 1}},
+       "add_id_to_interface": {
+         "comment": "Place least-significant 7 bits of engine ID into most significant bits of ingress and egress interface fields of NetFlow records?",
+         "type": "boolean"},
+       "active_timeout": {
+         "comment": "Active timeout interval, in seconds.  A value of 0 requests the default timeout; a negative value disables active timeouts.",
+         "type": "integer"}}},
+   "Controller": {
+     "comment": "An OpenFlow controller.",
+     "columns": {
+       "target": {
+         "comment": "Connection method for controller, e.g. \"ssl:...\", \"tcp:...\".  The special string \"discover\" enables controller discovery.  The special string \"none\" disables the controller.",
+         "type": "string"},
+       "max_backoff": {
+         "comment": "Maximum number of milliseconds to wait between connection attempts.  Default is implementation-specific.",
+         "type": {"key": "integer", "min": 0, "max": 1}},
+       "inactivity_probe": {
+         "comment": "Maximum number of milliseconds of idle time on connection to controller before sending an inactivity probe message.  Default is implementation-specific.",
+         "type": {"key": "integer", "min": 0, "max": 1}},
+       "fail_mode": {
+         "comment": "Either \"standalone\" or \"secure\", or empty to use the implementation's default.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "discover_accept_regex": {
+         "comment": "If \"target\" is \"discover\", a POSIX extended regular expression against which the discovered controller location is validated.  If not specified, the default is implementation-specific.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "discover_update_resolv_conf": {
+         "comment": "If \"target\" is \"discover\", whether to update /etc/resolv.conf when the controller is discovered.  If not specified, the default is implementation-specific.",
+         "type": {"key": "boolean", "min": 0, "max": 1}},
+       "connection_mode": {
+         "comment": "Either \"in-band\" or \"out-of-band\".  If not specified, the default is implementation-specific.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "local_ip": {
+         "comment": "If \"target\" is not \"discover\", the IP address to configure on the local port.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "local_netmask": {
+         "comment": "If \"target\" is not \"discover\", the IP netmask to configure on the local port.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "local_gateway": {
+         "comment": "If \"target\" is not \"discover\", the IP gateway to configure on the local port.",
+         "type": {"key": "string", "min": 0, "max": 1}},
+       "controller_rate_limit": {
+         "comment": "The maximum rate at which packets will be forwarded to the OpenFlow controller, in packets per second.  If not specified, the default is implementation-specific.",
+         "type": {"key": "integer", "min": 0, "max": 1}},
+       "controller_burst_limit": {
+         "comment": "The maximum number of unused packet credits that the bridge will allow to accumulate, in packets.  If not specified, the default is implementation-specific.",
+         "type": {"key": "integer", "min": 0, "max": 1}}}},
+   "SSL": {
+     "comment": "SSL configuration for an Open_vSwitch.",
+     "columns": {
+       "private_key": {
+         "comment": "Name of a PEM file containing the private key used as the switch's identity for SSL connections to the controller.",
+         "type": "string"},
+       "certificate": {
+         "comment": "Name of a PEM file containing a certificate, signed by the certificate authority (CA) used by the controller and manager, that certifies the switch's private key, identifying a trustworthy switch.",
+         "type": "string"},
+       "ca_cert": {
+         "comment": "Name of a PEM file containing the CA certificate used to verify that the switch is connected to a trustworthy controller.",
+         "type": "string"},
+       "bootstrap_ca_cert": {
+         "comment": "If set to true, then Open vSwitch will attempt to obtain the CA certificate from the controller on its first SSL connection and save it to the named PEM file. If it is successful, it will immediately drop the connection and reconnect, and from then on all SSL connections must be authenticated by a certificate signed by the CA certificate thus obtained.  This option exposes the SSL connection to a man-in-the-middle attack obtaining the initial CA certificate, but it may be useful for bootstrapping.",
+         "type": "boolean"}}}}}