[ovs-dev] [gc 13/13] ovsdb: Implement garbage collection.

Ben Pfaff blp at nicira.com
Wed Mar 9 15:40:45 PST 2011


On Wed, Mar 09, 2011 at 01:49:30PM -0800, Ben Pfaff wrote:
> On Wed, Mar 09, 2011 at 01:19:02PM -0800, Ethan Jackson wrote:
> > > Another approach, which had not occurred to me before now, would be to
> > > use "true" as the default if a schema does not have any tables with
> > > "isRoot" explicitly specified (for compatibility), and "false"
> > > otherwise.  Do you like that better?  If you do, then I will implement
> > > it that way instead.
> > 
> > If it's relatively easy to do that sounds like a good idea to me.  I'd
> > prefer the default do the right thing if possible.  If it's too much
> > work I wouldn't bother though, we can always change it later if it
> > becomes a problem.  We don't add tables that often anyways.
> 
> It's not much work.

Here's an incremental that does it this way.

I'll send out the full patch separately.

--8<--------------------------cut here-------------------------->8--

diff --git a/ovsdb/SPECS b/ovsdb/SPECS
index ac1f1da..1bb21f3 100644
--- a/ovsdb/SPECS
+++ b/ovsdb/SPECS
@@ -153,14 +153,19 @@ is represented by <database-schema>, as described below.
         the database process is stopped and then started again, each
         "_version" also changes to a new random value.
 
-    If "isRoot" is specified as false, then any given row in the table
-    may exist only when it there is at least one reference to it, with
-    refType "strong", from a different row (in the same table or a
-    different table).  This is a "deferred" action: unreferenced rows
-    in the table are deleted just before transaction commit.  If
-    "isRoot" is omitted or specified as true, then rows in the table
-    exist independent of any references (they can be thought of as
-    part of the "root set" in a garbage collector).
+    If "isRoot" is omitted or specified as false, then any given row
+    in the table may exist only when it there is at least one
+    reference to it, with refType "strong", from a different row (in
+    the same table or a different table).  This is a "deferred"
+    action: unreferenced rows in the table are deleted just before
+    transaction commit.  If "isRoot" is specified as true, then rows
+    in the table exist independent of any references (they can be
+    thought of as part of the "root set" in a garbage collector).
+
+    For compatibility with schemas created before "isRoot" was
+    introduced, if "isRoot" is omitted or false in every
+    <table-schema> in a given <database-schema>, then every table is
+    part of the root set.
 
     If "maxRows" is specified, as a positive integer, it limits the
     maximum number of rows that may be present in the table.  This is
diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c
index e76544e..aad8415 100644
--- a/ovsdb/ovsdb.c
+++ b/ovsdb/ovsdb.c
@@ -127,6 +127,21 @@ is_valid_version(const char *s)
     return n != -1 && s[n] == '\0';
 }
 
+/* Returns the number of tables in 'schema''s root set. */
+static size_t
+root_set_size(const struct ovsdb_schema *schema)
+{
+    struct shash_node *node;
+    size_t n_root;
+
+    SHASH_FOR_EACH (node, &schema->tables) {
+        struct ovsdb_table_schema *table = node->data;
+
+        n_root += table->is_root;
+    }
+    return n_root;
+}
+
 struct ovsdb_error *
 ovsdb_schema_from_json(struct json *json, struct ovsdb_schema **schemap)
 {
@@ -205,6 +220,18 @@ ovsdb_schema_from_json(struct json *json, struct ovsdb_schema **schemap)
         }
     }
 
+    /* "isRoot" was not part of the original schema definition.  Before it was
+     * added, there was no support for garbage collection.  So, for backward
+     * compatibility, if the root set is empty then assume that every table is
+     * in the root set. */
+    if (root_set_size(schema) == 0) {
+        SHASH_FOR_EACH (node, &schema->tables) {
+            struct ovsdb_table_schema *table = node->data;
+
+            table->is_root = true;
+        }
+    }
+
     *schemap = schema;
     return 0;
 }
@@ -214,6 +241,7 @@ ovsdb_schema_to_json(const struct ovsdb_schema *schema)
 {
     struct json *json, *tables;
     struct shash_node *node;
+    bool default_is_root;
 
     json = json_object_create();
     json_object_put_string(json, "name", schema->name);
@@ -224,12 +252,18 @@ ovsdb_schema_to_json(const struct ovsdb_schema *schema)
         json_object_put_string(json, "cksum", schema->cksum);
     }
 
+    /* "isRoot" was not part of the original schema definition.  Before it was
+     * added, there was no support for garbage collection.  So, for backward
+     * compatibility, if every table is in the root set then do not output
+     * "isRoot" in table schemas. */
+    default_is_root = root_set_size(schema) == shash_count(&schema->tables);
+
     tables = json_object_create();
 
     SHASH_FOR_EACH (node, &schema->tables) {
         struct ovsdb_table_schema *table = node->data;
         json_object_put(tables, table->name,
-                        ovsdb_table_schema_to_json(table));
+                        ovsdb_table_schema_to_json(table, default_is_root));
     }
     json_object_put(json, "tables", tables);
 
diff --git a/ovsdb/table.c b/ovsdb/table.c
index bd0b1f2..2f69350 100644
--- a/ovsdb/table.c
+++ b/ovsdb/table.c
@@ -137,7 +137,7 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name,
     ts = ovsdb_table_schema_create(name,
                                    mutable ? json_boolean(mutable) : true,
                                    MIN(n_max_rows, UINT_MAX),
-                                   is_root ? json_boolean(is_root) : true);
+                                   is_root ? json_boolean(is_root) : false);
     SHASH_FOR_EACH (node, json_object(columns)) {
         struct ovsdb_column *column;
 
@@ -160,8 +160,19 @@ ovsdb_table_schema_from_json(const struct json *json, const char *name,
     return 0;
 }
 
+/* Returns table schema 'ts' serialized into JSON.
+ *
+ * The "isRoot" member is included in the JSON only if its value would differ
+ * from 'default_is_root'.  Ordinarily 'default_is_root' should be false,
+ * because ordinarily a table would be not be part of the root set if its
+ * "isRoot" member is omitted.  However, garbage collection was not orginally
+ * included in OVSDB, so in older schemas that do not include any "isRoot"
+ * members, every table is implicitly part of the root set.  To serialize such
+ * a schema in a way that can be read by older OVSDB tools, specify
+ * 'default_is_root' as true. */
 struct json *
-ovsdb_table_schema_to_json(const struct ovsdb_table_schema *ts)
+ovsdb_table_schema_to_json(const struct ovsdb_table_schema *ts,
+                           bool default_is_root)
 {
     struct json *json, *columns;
     struct shash_node *node;
@@ -170,8 +181,8 @@ ovsdb_table_schema_to_json(const struct ovsdb_table_schema *ts)
     if (!ts->mutable) {
         json_object_put(json, "mutable", json_boolean_create(false));
     }
-    if (!ts->is_root) {
-        json_object_put(json, "isRoot", json_boolean_create(false));
+    if (default_is_root != ts->is_root) {
+        json_object_put(json, "isRoot", json_boolean_create(ts->is_root));
     }
 
     columns = json_object_create();
diff --git a/ovsdb/table.h b/ovsdb/table.h
index 02a24e4..95da740 100644
--- a/ovsdb/table.h
+++ b/ovsdb/table.h
@@ -43,7 +43,8 @@ struct ovsdb_error *ovsdb_table_schema_from_json(const struct json *,
                                                  const char *name,
                                                  struct ovsdb_table_schema **)
     WARN_UNUSED_RESULT;
-struct json *ovsdb_table_schema_to_json(const struct ovsdb_table_schema *);
+struct json *ovsdb_table_schema_to_json(const struct ovsdb_table_schema *,
+                                        bool default_is_root);
 
 const struct ovsdb_column *ovsdb_table_schema_get_column(
     const struct ovsdb_table_schema *, const char *name);
diff --git a/python/ovs/db/schema.py b/python/ovs/db/schema.py
index fec4e19..bb4981c 100644
--- a/python/ovs/db/schema.py
+++ b/python/ovs/db/schema.py
@@ -34,6 +34,22 @@ class DbSchema(object):
                 self.__check_ref_table(column, column.type.key, "key")
                 self.__check_ref_table(column, column.type.value, "value")
 
+        # "isRoot" was not part of the original schema definition.  Before it
+        # was added, there was no support for garbage collection.  So, for
+        # backward compatibility, if the root set is empty then assume that
+        # every table is in the root set.
+        if self.__root_set_size() == 0:
+            for table in self.tables.itervalues():
+                table.is_root = True
+
+    def __root_set_size(self):
+        """Returns the number of tables in the schema's root set."""
+        n_root = 0
+        for table in self.tables.itervalues():
+            if table.is_root:
+                n_root += 1
+        return n_root
+
     @staticmethod
     def from_json(json):
         parser = ovs.db.parser.Parser(json, "database schema")
@@ -60,9 +76,15 @@ class DbSchema(object):
         return DbSchema(name, version, tables)
 
     def to_json(self):
+        # "isRoot" was not part of the original schema definition.  Before it
+        # was added, there was no support for garbage collection.  So, for
+        # backward compatibility, if every table is in the root set then do not
+        # output "isRoot" in table schemas. */
+        default_is_root = self.__root_set_size() == len(self.tables)
+
         tables = {}
         for table in self.tables.itervalues():
-            tables[table.name] = table.to_json()
+            tables[table.name] = table.to_json(default_is_root)
         json = {"name": self.name, "tables": tables}
         if self.version:
             json["version"] = self.version
@@ -110,7 +132,7 @@ class TableSchema(object):
         columnsJson = parser.get("columns", [dict])
         mutable = parser.get_optional("mutable", [bool], True)
         max_rows = parser.get_optional("maxRows", [int])
-        is_root = parser.get_optional("isRoot", [bool], True)
+        is_root = parser.get_optional("isRoot", [bool], False)
         parser.finish()
 
         if max_rows == None:
@@ -133,12 +155,23 @@ class TableSchema(object):
 
         return TableSchema(name, columns, mutable, max_rows, is_root)
 
-    def to_json(self):
+    def to_json(self, default_is_root=False):
+        """Returns this table schema serialized into JSON.
+        
+        The "isRoot" member is included in the JSON only if its value would
+        differ from 'default_is_root'.  Ordinarily 'default_is_root' should be
+        false, because ordinarily a table would be not be part of the root set
+        if its "isRoot" member is omitted.  However, garbage collection was not
+        orginally included in OVSDB, so in older schemas that do not include
+        any "isRoot" members, every table is implicitly part of the root set.
+        To serialize such a schema in a way that can be read by older OVSDB
+        tools, specify 'default_is_root' as True.
+        """
         json = {}
         if not self.mutable:
             json["mutable"] = False
-        if not self.is_root:
-            json["isRoot"] = False
+        if default_is_root != self.is_root:
+            json["isRoot"] = self.is_root
 
         json["columns"] = columns = {}
         for column in self.columns.itervalues():
diff --git a/tests/ovsdb-execution.at b/tests/ovsdb-execution.at
index 5e9f91c..ebf1186 100644
--- a/tests/ovsdb-execution.at
+++ b/tests/ovsdb-execution.at
@@ -60,6 +60,12 @@ m4_define([WEAK_SCHEMA],
 m4_define([GC_SCHEMA],
   [[{"name": "gc",
      "tables": {
+       "root": {
+         "columns": {
+           "a": {"type": {"key": {"type": "uuid",
+                                  "refTable": "a"},
+                            "min": 0, "max": "unlimited"}}},
+         "isRoot": true},
        "a": {
          "columns": {
            "a": {"type": "integer"},
@@ -76,8 +82,7 @@ m4_define([GC_SCHEMA],
            "wa2b": {"type": {"key": {"type": "uuid",
                                     "refTable": "b",
                                     "refType": "weak"},
-                             "min": 0, "max": "unlimited"}}},
-         "isRoot": false},
+                             "min": 0, "max": "unlimited"}}}},
        "b": {
          "columns": {
            "b": {"type": "integer"},
diff --git a/tests/ovsdb-table.at b/tests/ovsdb-table.at
index be44e43..cf206c4 100644
--- a/tests/ovsdb-table.at
+++ b/tests/ovsdb-table.at
@@ -1,6 +1,6 @@
 AT_BANNER([OVSDB -- tables])
 
-OVSDB_CHECK_POSITIVE_CPY([table with one column],
+OVSDB_CHECK_POSITIVE_CPY([non-root table with one column],
   [[parse-table mytable '{"columns": {"name": {"type": "string"}}}']],
   [[{"columns":{"name":{"type":"string"}}}]])
 
@@ -10,12 +10,22 @@ OVSDB_CHECK_POSITIVE_CPY([immutable table with one column],
       "mutable": false}']],
   [[{"columns":{"name":{"type":"string"}},"mutable":false}]])
 
-OVSDB_CHECK_POSITIVE_CPY([non-root table with one column],
+OVSDB_CHECK_POSITIVE_CPY([root table with one column],
   [[parse-table mytable \
     '{"columns": {"name": {"type": "string"}},
-      "isRoot": false}']],
+      "isRoot": true}']],
+  [[{"columns":{"name":{"type":"string"}},"isRoot":true}]])
+
+OVSDB_CHECK_POSITIVE_CPY([non-root table with default_is_root=true],
+  [[parse-table mytable '{"columns": {"name": {"type": "string"}}}' true]],
   [[{"columns":{"name":{"type":"string"}},"isRoot":false}]])
 
+OVSDB_CHECK_POSITIVE_CPY([root table with default_is_root=true],
+  [[parse-table mytable \
+    '{"columns": {"name": {"type": "string"}},
+      "isRoot": true}' true]],
+  [[{"columns":{"name":{"type":"string"}}}]])
+
 OVSDB_CHECK_POSITIVE_CPY([table with maxRows of 2],
   [[parse-table mytable '{"columns": {"name": {"type": "string"}}, 
                           "maxRows": 2}']],
diff --git a/tests/test-ovsdb.c b/tests/test-ovsdb.c
index c424abe..990bf6d 100644
--- a/tests/test-ovsdb.c
+++ b/tests/test-ovsdb.c
@@ -141,7 +141,7 @@ usage(void)
            "    parse string DATUMs as data of given TYPE, and re-serialize\n"
            "  parse-column NAME OBJECT\n"
            "    parse column NAME with info OBJECT, and re-serialize\n"
-           "  parse-table NAME OBJECT\n"
+           "  parse-table NAME OBJECT [DEFAULT-IS-ROOT]\n"
            "    parse table NAME with info OBJECT\n"
            "  parse-row TABLE ROW..., and re-serialize\n"
            "    parse each ROW of defined TABLE\n"
@@ -608,12 +608,15 @@ static void
 do_parse_table(int argc OVS_UNUSED, char *argv[])
 {
     struct ovsdb_table_schema *ts;
+    bool default_is_root;
     struct json *json;
 
+    default_is_root = argc > 3 && !strcmp(argv[3], "true");
+
     json = parse_json(argv[2]);
     check_ovsdb_error(ovsdb_table_schema_from_json(json, argv[1], &ts));
     json_destroy(json);
-    print_and_free_json(ovsdb_table_schema_to_json(ts));
+    print_and_free_json(ovsdb_table_schema_to_json(ts, default_is_root));
     ovsdb_table_schema_destroy(ts);
 }
 
@@ -1932,7 +1935,7 @@ static struct command all_commands[] = {
     { "parse-data-strings", 2, INT_MAX, do_parse_data_strings },
     { "sort-atoms", 2, 2, do_sort_atoms },
     { "parse-column", 2, 2, do_parse_column },
-    { "parse-table", 2, 2, do_parse_table },
+    { "parse-table", 2, 3, do_parse_table },
     { "parse-rows", 2, INT_MAX, do_parse_rows },
     { "compare-rows", 2, INT_MAX, do_compare_rows },
     { "parse-conditions", 2, INT_MAX, do_parse_conditions },
diff --git a/tests/test-ovsdb.py b/tests/test-ovsdb.py
index 863bcb8..2eafe99 100644
--- a/tests/test-ovsdb.py
+++ b/tests/test-ovsdb.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2009, 2010 Nicira Networks
+# Copyright (c) 2009, 2010, 2011 Nicira Networks
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -121,10 +121,11 @@ def do_parse_column(name, column_string):
     column = ovs.db.schema.ColumnSchema.from_json(column_json, name)
     print ovs.json.to_string(column.to_json(), sort_keys=True)
 
-def do_parse_table(name, table_string):
+def do_parse_table(name, table_string, default_is_root_string='false'):
+    default_is_root = default_is_root_string == 'true'
     table_json = unbox_json(ovs.json.from_string(table_string))
     table = ovs.db.schema.TableSchema.from_json(table_json, name)
-    print ovs.json.to_string(table.to_json(), sort_keys=True)
+    print ovs.json.to_string(table.to_json(default_is_root), sort_keys=True)
 
 def do_parse_rows(table_string, *rows):
     table_json = unbox_json(ovs.json.from_string(table_string))
@@ -272,7 +273,7 @@ parse-data TYPE DATUM...
   parse JSON DATUMs as data of given TYPE, and re-serialize
 parse-column NAME OBJECT
   parse column NAME with info OBJECT, and re-serialize
-parse-table NAME OBJECT
+parse-table NAME OBJECT [DEFAULT-IS-ROOT]
   parse table NAME with info OBJECT
 parse-schema JSON
   parse JSON as an OVSDB schema, and re-serialize
@@ -332,7 +333,7 @@ def main(argv):
                 "parse-data": (do_parse_data, (2,)),
                 "sort-atoms": (do_sort_atoms, 2),
                 "parse-column": (do_parse_column, 2),
-                "parse-table": (do_parse_table, 2),
+                "parse-table": (do_parse_table, (2, 3)),
                 "parse-schema": (do_parse_schema, 1),
                 "idl": (do_idl, (1,))}
 
diff --git a/vswitchd/vswitch.gv b/vswitchd/vswitch.gv
index b5c2b56..5988698 100644
--- a/vswitchd/vswitch.gv
+++ b/vswitchd/vswitch.gv
@@ -3,7 +3,7 @@ digraph Open_vSwitch {
 	margin="0";
 	node [shape=box];
 	edge [dir=none, arrowhead=none, arrowtail=none];
-	Bridge [];
+	Bridge [style=bold];
 	Bridge -> sFlow [label="sflow"];
 	Bridge -> Mirror [label="mirrors"];
 	Bridge -> Port [label="ports"];
@@ -11,28 +11,28 @@ digraph Open_vSwitch {
 	Bridge -> NetFlow [label="netflow"];
 	QoS [style=bold];
 	QoS -> Queue [label="queues value"];
-	Monitor [];
+	Monitor [style=bold];
 	Monitor -> Maintenance_Point [label="remote_mps"];
-	sFlow [];
+	sFlow [style=bold];
 	Open_vSwitch [style=bold];
 	Open_vSwitch -> Bridge [label="bridges"];
 	Open_vSwitch -> Capability [label="capabilities value"];
 	Open_vSwitch -> SSL [label="ssl"];
 	Open_vSwitch -> Manager [label="manager_options"];
-	Controller [];
+	Controller [style=bold];
 	Queue [style=bold];
-	SSL [];
-	Manager [];
-	Capability [];
-	Mirror [];
+	SSL [style=bold];
+	Manager [style=bold];
+	Capability [style=bold];
+	Mirror [style=bold];
 	Mirror -> Port [style=dotted, constraint=false, label="select_src_port"];
 	Mirror -> Port [style=dotted, constraint=false, label="output_port"];
 	Mirror -> Port [style=dotted, constraint=false, label="select_dst_port"];
-	Interface [];
+	Interface [style=bold];
 	Interface -> Monitor [label="monitor"];
-	NetFlow [];
-	Maintenance_Point [];
-	Port [];
+	NetFlow [style=bold];
+	Maintenance_Point [style=bold];
+	Port [style=bold];
 	Port -> QoS [label="qos"];
 	Port -> Interface [label="interfaces"];
 }
diff --git a/vswitchd/vswitch.ovsschema b/vswitchd/vswitch.ovsschema
index 739952b..7618e2d 100644
--- a/vswitchd/vswitch.ovsschema
+++ b/vswitchd/vswitch.ovsschema
@@ -1,6 +1,6 @@
 {"name": "Open_vSwitch",
  "version": "2.1.0",
- "cksum": "2276559359 15915",
+ "cksum": "1990266641 15714",
  "tables": {
    "Open_vSwitch": {
      "columns": {
@@ -43,13 +43,13 @@
        "system_version": {
          "type": {"key": {"type": "string"},
                   "min": 0, "max": 1}}},
+     "isRoot": true,
      "maxRows": 1},
    "Capability": {
      "columns": {
        "details": {
          "type": {"key": "string", "value": "string",
-                  "min": 0, "max": "unlimited"}}},
-     "isRoot": false},
+                  "min": 0, "max": "unlimited"}}}},
    "Bridge": {
      "columns": {
        "name": {
@@ -92,8 +92,7 @@
          "type": {"key": {"type": "integer",
                           "minInteger": 0,
                           "maxInteger": 4095},
-                  "min": 0, "max": 4096}}},
-     "isRoot": false},
+                  "min": 0, "max": 4096}}}},
    "Port": {
      "columns": {
        "name": {
@@ -139,8 +138,7 @@
        "other_config": {
          "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}},
        "external_ids": {
-         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}},
-     "isRoot": false},
+         "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"}}}},
    "Interface": {
      "columns": {
        "name": {
@@ -197,8 +195,7 @@
          "ephemeral": true},
        "mtu": {
          "type": {"key": "integer", "min": 0, "max": 1},
-         "ephemeral": true}},
-     "isRoot": false},
+         "ephemeral": true}}},
    "Monitor": {
      "columns": {
        "mpid": {
@@ -242,8 +239,7 @@
            "key": { "type": "boolean"},
            "min": 0,
            "max": 1},
-         "ephemeral": true}},
-     "isRoot": false},
+         "ephemeral": true}}},
    "Maintenance_Point": {
      "columns": {
        "mpid": {
@@ -255,8 +251,7 @@
            "key": { "type": "boolean"},
            "min": 0,
            "max": 1},
-         "ephemeral": true}},
-     "isRoot": false},
+         "ephemeral": true}}},
    "QoS": {
      "columns": {
        "type": {
@@ -273,7 +268,8 @@
                   "min": 0, "max": "unlimited"}},
        "external_ids": {
          "type": {"key": "string", "value": "string",
-                  "min": 0, "max": "unlimited"}}}},
+                  "min": 0, "max": "unlimited"}}},
+     "isRoot": true},
    "Queue": {
      "columns": {
        "other_config": {
@@ -281,7 +277,8 @@
                   "min": 0, "max": "unlimited"}},
        "external_ids": {
          "type": {"key": "string", "value": "string",
-                  "min": 0, "max": "unlimited"}}}},
+                  "min": 0, "max": "unlimited"}}},
+     "isRoot": true},
    "Mirror": {
      "columns": {
        "name": {
@@ -316,8 +313,7 @@
                   "min": 0, "max": 1}},
        "external_ids": {
          "type": {"key": "string", "value": "string",
-                  "min": 0, "max": "unlimited"}}},
-     "isRoot": false},
+                  "min": 0, "max": "unlimited"}}}},
    "NetFlow": {
      "columns": {
        "targets": {
@@ -340,8 +336,7 @@
                           "minInteger": -1}}},
        "external_ids": {
          "type": {"key": "string", "value": "string",
-                  "min": 0, "max": "unlimited"}}},
-     "isRoot": false},
+                  "min": 0, "max": "unlimited"}}}},
    "sFlow": {
      "columns": {
        "targets": {
@@ -356,8 +351,7 @@
          "type": {"key": "string", "min": 0, "max": 1}},
        "external_ids": {
          "type": {"key": "string", "value": "string",
-                  "min": 0, "max": "unlimited"}}},
-     "isRoot": false},
+                  "min": 0, "max": "unlimited"}}}},
    "Controller": {
      "columns": {
        "target": {
@@ -406,8 +400,7 @@
          "ephemeral": true},
        "status": {
          "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"},
-         "ephemeral": true}},
-     "isRoot": false},
+         "ephemeral": true}}},
    "Manager": {
      "columns": {
        "target": {
@@ -430,8 +423,7 @@
          "ephemeral": true},
        "status": {
          "type": {"key": "string", "value": "string", "min": 0, "max": "unlimited"},
-         "ephemeral": true}},
-     "isRoot": false},
+         "ephemeral": true}}},
    "SSL": {
      "columns": {
        "private_key": {
@@ -445,5 +437,4 @@
        "external_ids": {
          "type": {"key": "string", "value": "string",
                   "min": 0, "max": "unlimited"}}},
-     "maxRows": 1,
-     "isRoot": false}}}
+     "maxRows": 1}}}
diff --git a/vswitchd/vswitch.pic b/vswitchd/vswitch.pic
index f7264df..86296e8 100644
--- a/vswitchd/vswitch.pic
+++ b/vswitchd/vswitch.pic
@@ -1,39 +1,51 @@
-.\" Generated from vswitch.gv with cksum "1443954516 1149"
+.\" Generated from vswitch.gv with cksum "1122829786 1269"
 .PS
 linethick = 1;
-linethick = 1;
+linethick = 0.5;
 box at 2.320997253,3.1110975 wid 0.5020540998 height 0.296295 "Bridge"
-linethick = 1;
+box at 2.320997253,3.1110975 wid 0.446498544244444 height 0.240739444444444
+linethick = 0.5;
 box at 0.2304523251,2.37036 wid 0.4609046502 height 0.296295 "sFlow"
-linethick = 1;
+box at 0.2304523251,2.37036 wid 0.405349094644444 height 0.240739444444444
+linethick = 0.5;
 box at 0.847759254,2.37036 wid 0.4855919496 height 0.296295 "Mirror"
-linethick = 1;
+box at 0.847759254,2.37036 wid 0.430036394044444 height 0.240739444444444
+linethick = 0.5;
 box at 2.320997253,2.37036 wid 0.4444425 height 0.296295 "Port"
-linethick = 1;
+box at 2.320997253,2.37036 wid 0.388886944444444 height 0.240739444444444
+linethick = 0.5;
 box at 3.045260751,2.37036 wid 0.707789496 height 0.296295 "Controller"
-linethick = 1;
+box at 3.045260751,2.37036 wid 0.652233940444444 height 0.240739444444444
+linethick = 0.5;
 box at 3.851835,2.37036 wid 0.609064002 height 0.296295 "NetFlow"
+box at 3.851835,2.37036 wid 0.553508446444444 height 0.240739444444444
 linethick = 0.5;
 box at 2.057590998,1.6296225 wid 0.4444425 height 0.296295 "QoS"
 box at 2.057590998,1.6296225 wid 0.388886944444444 height 0.240739444444444
 linethick = 0.5;
 box at 1.991754249,0.888885 wid 0.5102851749 height 0.296295 "Queue"
 box at 1.991754249,0.888885 wid 0.454729619344444 height 0.240739444444444
-linethick = 1;
+linethick = 0.5;
 box at 2.938238997,0.888885 wid 0.5761278498 height 0.296295 "Monitor"
-linethick = 1;
+box at 2.938238997,0.888885 wid 0.520572294244444 height 0.240739444444444
+linethick = 0.5;
 box at 2.938238997,0.1481475 wid 1.218128004 height 0.296295 "Maintenance_Point"
+box at 2.938238997,0.1481475 wid 1.16257244844444 height 0.240739444444444
 linethick = 0.5;
 box at 3.637850751,3.851835 wid 0.954721749 height 0.296295 "Open_vSwitch"
 box at 3.637850751,3.851835 wid 0.899166193444444 height 0.240739444444444
-linethick = 1;
+linethick = 0.5;
 box at 3.061734753,3.1110975 wid 0.699611754 height 0.296295 "Capability"
-linethick = 1;
+box at 3.061734753,3.1110975 wid 0.644056198444444 height 0.240739444444444
+linethick = 0.5;
 box at 4.22220375,3.1110975 wid 0.4444425 height 0.296295 "SSL"
-linethick = 1;
+box at 4.22220375,3.1110975 wid 0.388886944444444 height 0.240739444444444
+linethick = 0.5;
 box at 4.905341502,3.1110975 wid 0.633715746 height 0.296295 "Manager"
-linethick = 1;
+box at 4.905341502,3.1110975 wid 0.578160190444444 height 0.240739444444444
+linethick = 0.5;
 box at 2.872402248,1.6296225 wid 0.641952747 height 0.296295 "Interface"
+box at 2.872402248,1.6296225 wid 0.586397191444444 height 0.240739444444444
 linethick = 1;
 spline -> from 2.072227971,3.066534732 to 2.072227971,3.066534732 to 1.825829049,3.018534942 to 1.439934441,2.932787169 to 1.119343251,2.8148025 to 0.887818338,2.729588058 to 0.637567581,2.60087751 to 0.4617876093,2.503870527
 "sflow" at 1.271579622,2.74072875



More information about the dev mailing list