vswitchd: Add entity-relationship diagram to ovs-vswitchd.conf.db.5.
authorBen Pfaff <blp@nicira.com>
Wed, 23 Jun 2010 16:41:09 +0000 (09:41 -0700)
committerBen Pfaff <blp@nicira.com>
Thu, 24 Jun 2010 20:18:43 +0000 (13:18 -0700)
I've updated http://openvswitch.org/ovs-vswitchd.conf.db.5.pdf with
example output.

INSTALL.Linux
configure.ac
m4/openvswitch.m4
ovsdb/automake.mk
ovsdb/ovsdb-doc.in
ovsdb/ovsdb-dot.in [new file with mode: 0755]
vswitchd/automake.mk
vswitchd/vswitch.pic [new file with mode: 0644]

index b4f9b767863a705d3439e5f8cad5a4d49434bf05..181a2dfd0597f74f4be60da4d34dcf17e2bcb76a 100644 (file)
@@ -81,6 +81,12 @@ following:
 
     - pyuic4 from PyQt4 (http://www.riverbankcomputing.co.uk).
 
+If you modify the vswitchd database schema, then the E-R diagram in
+the ovs-vswitchd.conf.db(5) manpage will be updated properly only if
+you have the following:
+
+    - "dot" from graphviz (http://www.graphviz.org/).
+
 Installation Requirements
 -------------------------
 
index 2128c64c78546f2cbb28ccc6c2e0a199e9d5bb76..aff53a1f69e23722eab87054e190b1ed115956d0 100644 (file)
@@ -52,6 +52,7 @@ OVS_CHECK_PCRE
 OVS_CHECK_PYTHON
 OVS_CHECK_PYUIC4
 OVS_CHECK_OVSDBMONITOR
+OVS_CHECK_ER_DIAGRAMS
 OVS_CHECK_IF_PACKET
 OVS_CHECK_STRTOK_R
 AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec],
index 2206aff1b870cf457283bdd4b48f03bb8821e08a..0b22f64ebc05a82ac9e36d14709c8ad0738ae00c 100644 (file)
@@ -265,6 +265,32 @@ else:
    fi
    AM_CONDITIONAL([HAVE_PYTHON], [test "$HAVE_PYTHON" = yes])])
 
+dnl Checks for dot.
+AC_DEFUN([OVS_CHECK_DOT],
+  [AC_CACHE_CHECK(
+    [for dot],
+    [ovs_cv_dot],
+    [dnl "dot" writes -V output to stderr:
+     if (dot -V) 2>&1 | grep '^dot - [gG]raphviz version' >/dev/null 2>&1; then
+       ovs_cv_dot=yes
+     else
+       ovs_cv_dot=no
+     fi])])
+
+dnl Check whether to build E-R diagrams.
+AC_DEFUN([OVS_CHECK_ER_DIAGRAMS],
+  [AC_REQUIRE([OVS_CHECK_DOT])
+   AC_REQUIRE([OVS_CHECK_PYTHON])
+   AC_CACHE_CHECK(
+    [whether to build E-R diagrams for database],
+    [ovs_cv_er_diagrams],
+    [if test $ovs_cv_dot != no && test $ovs_cv_python != no; then
+       ovs_cv_er_diagrams=yes
+     else
+       ovs_cv_er_diagrams=no
+     fi])
+   AM_CONDITIONAL([BUILD_ER_DIAGRAMS], [test $ovs_cv_er_diagrams = yes])])
+
 dnl Checks for pyuic4.
 AC_DEFUN([OVS_CHECK_PYUIC4],
   [AC_CACHE_CHECK(
index 37d669bb3b01168f4612e95e9d73f74cf054e1ab..5745697ae1d865f7cbe3a7d54f2cc8336210e39c 100644 (file)
@@ -117,4 +117,10 @@ noinst_SCRIPTS += ovsdb/ovsdb-doc
 DISTCLEANFILES += ovsdb/ovsdb-doc
 OVSDB_DOC = $(PYTHON) $(srcdir)/ovsdb/ovsdb-doc.in
 
+# ovsdb-dot
+EXTRA_DIST += ovsdb/ovsdb-dot.in
+noinst_SCRIPTS += ovsdb/ovsdb-dot
+DISTCLEANFILES += ovsdb/ovsdb-dot
+OVSDB_DOT = $(PYTHON) $(srcdir)/ovsdb/ovsdb-dot.in
+
 include ovsdb/ovsdbmonitor/automake.mk
index c4faf6f2c705a3e89d47ac1d4b2a74dba26ccaff..4950e47e4ce90a1f3b199f0d46677dc377df2f3f 100755 (executable)
@@ -213,10 +213,10 @@ Column    Type
     s += body
     return s
 
-def docsToNroff(schemaFile, xmlFile, title=None):
+def docsToNroff(schemaFile, xmlFile, erFile, title=None):
     schema = DbSchema.fromJson(json.load(open(schemaFile, "r")))
     doc = xml.dom.minidom.parse(xmlFile).documentElement
-
+    
     schemaDate = os.stat(schemaFile).st_mtime
     xmlDate = os.stat(xmlFile).st_mtime
     d = date.fromtimestamp(max(schemaDate, xmlDate))
@@ -224,7 +224,10 @@ def docsToNroff(schemaFile, xmlFile, title=None):
     if title == None:
         title = schema.name
 
-    s = r'''.TH %s 5 "%s" "Open vSwitch" "Open vSwitch Manual"
+    # Putting '\" pt as the first line tells "man" that the manpage
+    # needs to be preprocessed by "pic" and "tbl".
+    s = r''''\" pt
+.TH %s 5 "%s" "Open vSwitch" "Open vSwitch Manual"
 .\" -*- nroff -*-
 .de TQ
 .  br
@@ -275,6 +278,24 @@ Table      Purpose
         tableSummary += "%s\t%s\n" % (name, textToNroff(title))
     tableSummary += '.TE\n'
     s += tableSummary
+
+    if erFile:
+        s += """
+.sp 1
+.SH "TABLE RELATIONSHIPS"
+.PP
+The following diagram shows the relationship among tables in the
+database.  Each node represents a table.  Each edge leads from the
+table that contains it and points to the table that its value
+represents.  Edges are labeled with their column names.
+.RS -1in
+"""
+        erStream = open(erFile, "r")
+        for line in erStream:
+            s += line + '\n'
+        erStream.close()
+        s += ".RE\n"
+
     for node in tableNodes:
         s += tableToNroff(schema, node) + "\n"
     return s
@@ -288,6 +309,7 @@ where SCHEMA is an OVSDB schema in JSON format
   and XML is OVSDB documentation in XML format.
 
 The following options are also available:
+  --er-diagram=DIAGRAM.PIC    include E-R diagram from DIAGRAM.PIC
   --title=TITLE               use TITLE as title instead of schema name
   -h, --help                  display this help message
   -V, --version               display version information\
@@ -298,14 +320,18 @@ if __name__ == "__main__":
     try:
         try:
             options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
-                                              ['title=', 'help', 'version'])
+                                              ['er-diagram=', 'title=',
+                                               'help', 'version'])
         except getopt.GetoptError, geo:
             sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
             sys.exit(1)
 
+        er_diagram = None
         title = None
         for key, value in options:
-            if key == '--title':
+            if key == '--er-diagram':
+                er_diagram = value
+            elif key == '--title':
                 title = value
             elif key in ['-h', '--help']:
                 usage()
@@ -320,7 +346,7 @@ if __name__ == "__main__":
             sys.exit(1)
         
         # XXX we should warn about undocumented tables or columns
-        s = docsToNroff(args[0], args[1])
+        s = docsToNroff(args[0], args[1], er_diagram)
         for line in s.split("\n"):
             line = line.strip()
             if len(line):
diff --git a/ovsdb/ovsdb-dot.in b/ovsdb/ovsdb-dot.in
new file mode 100755 (executable)
index 0000000..1793530
--- /dev/null
@@ -0,0 +1,87 @@
+#! @PYTHON@
+
+from datetime import date
+import getopt
+import os
+import re
+import sys
+
+sys.path.insert(0, "@abs_top_srcdir@/ovsdb")
+import simplejson as json
+
+from OVSDB import *
+
+argv0 = sys.argv[0]
+
+def printEdge(tableName, baseType, label):
+    if baseType.refTable:
+        options = {}
+        options['label'] = '"%s"' % label
+        if baseType.refType == 'weak':
+            options['constraint'] = 'false'
+        print "\t%s -> %s [%s];" % (
+            tableName,
+            baseType.refTable,
+            ', '.join(['%s=%s' % (k,v) for k,v in options.items()]))
+
+def schemaToDot(schemaFile):
+    schema = DbSchema.fromJson(json.load(open(schemaFile, "r")))
+
+    print "digraph %s {" % schema.name
+    for tableName, table in schema.tables.iteritems():
+        print '\tsize="6.5,4";'
+        print '\tmargin="0";'
+        print "\tnode [shape=box];"
+        print "\t%s;" % tableName
+        for columnName, column in table.columns.iteritems():
+            if column.type.value:
+                printEdge(tableName, column.type.key, "%s key" % columnName)
+                printEdge(tableName, column.type.value, "%s value" % columnName)
+            else:
+                printEdge(tableName, column.type.key, columnName)
+    print "}";
+
+def usage():
+    print """\
+%(argv0)s: compiles ovsdb schemas to graphviz format
+Prints a .dot file that "dot" can render to an entity-relationship diagram
+usage: %(argv0)s [OPTIONS] SCHEMA
+where SCHEMA is an OVSDB schema in JSON format
+
+The following options are also available:
+  -h, --help                  display this help message
+  -V, --version               display version information\
+""" % {'argv0': argv0}
+    sys.exit(0)
+
+if __name__ == "__main__":
+    try:
+        try:
+            options, args = getopt.gnu_getopt(sys.argv[1:], 'hV',
+                                              ['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-dot (Open vSwitch) @VERSION@"
+            else:
+                sys.exit(0)
+            
+        if len(args) != 1:
+            sys.stderr.write("%s: exactly 1 non-option argument required "
+                             "(use --help for help)\n" % argv0)
+            sys.exit(1)
+
+        schemaToDot(args[0])
+        
+    except Error, e:
+        sys.stderr.write("%s: %s\n" % (argv0, e.msg))
+        sys.exit(1)
+
+# Local variables:
+# mode: python
+# End:
index 6c2019118828a8cedc015ba3db86f81eaa202a6d..592be607a7a782fa1f24a70d03395274ed0e5e0d 100644 (file)
@@ -46,13 +46,31 @@ vswitchd/vswitch-idl.ovsidl: $(VSWITCH_IDL_FILES)
        $(OVSDB_IDLC) -C $(srcdir) annotate $(VSWITCH_IDL_FILES) > $@.tmp
        mv $@.tmp $@
 
+# vswitch E-R diagram
+if BUILD_ER_DIAGRAMS
+$(srcdir)/vswitchd/vswitch.pic: ovsdb/ovsdb-dot.in vswitchd/vswitch.ovsschema
+       $(OVSDB_DOT) $(srcdir)/vswitchd/vswitch.ovsschema \
+               | dot -T pic \
+               | sed -e "/^'/d" \
+                     -e '/^box attrs0/d' \
+                     -e 's/linethick = 0;/linethick = 1;/' \
+               > $@.tmp
+       mv $@.tmp $@
+else
+$(srcdir)/vswitchd/vswitch.pic: ovsdb/ovsdb-dot.in vswitchd/vswitch.ovsschema
+       touch $@
+endif
+EXTRA_DIST += vswitchd/vswitch.pic
+
 # vswitch schema documentation
 EXTRA_DIST += vswitchd/vswitch.xml
 dist_man_MANS += vswitchd/ovs-vswitchd.conf.db.5
 vswitchd/ovs-vswitchd.conf.db.5: \
-       ovsdb/ovsdb-doc.in vswitchd/vswitch.xml vswitchd/vswitch.ovsschema
+       ovsdb/ovsdb-doc.in vswitchd/vswitch.xml vswitchd/vswitch.ovsschema \
+       $(srcdir)/vswitchd/vswitch.pic
        $(OVSDB_DOC) \
                --title="ovs-vswitchd.conf.db" \
+               --er-diagram=$(srcdir)/vswitchd/vswitch.pic \
                $(srcdir)/vswitchd/vswitch.ovsschema \
                $(srcdir)/vswitchd/vswitch.xml > $@.tmp
        mv $@.tmp $@
diff --git a/vswitchd/vswitch.pic b/vswitchd/vswitch.pic
new file mode 100644 (file)
index 0000000..67c3338
--- /dev/null
@@ -0,0 +1,1017 @@
+.\"  Creator: Graphviz version 2.20.2 (Sun Oct 12 22:28:10 UTC 2008)
+.\"  For: (blp) Ben Pfaff,,,
+.\"  Title: Open_vSwitch
+.\"  save point size and font
+.nr .S \n(.s
+.nr DF \n(.f
+.PS 6.50000 3.59722
+# to change drawing size, multiply the width and height on the .PS line above and the number on the two lines below (rounded to the nearest integer) by a scale factor
+.nr SF 6500
+scalethickness = 6500
+# don't change anything below this line in this drawing
+# non-fatal run-time pic version determination, version 2
+boxrad=2.0 # will be reset to 0.0 by gpic only
+scale=1.0 # required for comparisons
+# boxrad is now 0.0 in gpic, else it remains 2.0
+# dashwid is 0.1 in 10th Edition, 0.05 in DWB 2 and in gpic
+# fillval is 0.3 in 10th Edition (fill 0 means black), 0.5 in gpic (fill 0 means white), undefined in DWB 2
+# fill has no meaning in DWB 2, gpic can use fill or filled, 10th Edition uses fill only
+# DWB 2 doesn't use fill and doesn't define fillval
+# reset works in gpic and 10th edition, but isn't defined in DWB 2
+# DWB 2 compatibility definitions
+if boxrad > 1.0 && dashwid < 0.075 then X
+       fillval = 1;
+       define fill Y Y;
+       define solid Y Y;
+       define reset Y scale=1.0 Y;
+X
+reset # set to known state
+# GNU pic vs. 10th Edition d\(e'tente
+if fillval > 0.4 then X
+       define setfillval Y fillval = 1 - Y;
+       define bold Y thickness 2 Y;
+       # if you use gpic and it barfs on encountering "solid",
+       #       install a more recent version of gpic or switch to DWB or 10th Edition pic;
+       #       sorry, the groff folks changed gpic; send any complaint to them;
+X else Z
+       define setfillval Y fillval = Y;
+       define bold Y Y;
+       define filled Y fill Y;
+Z
+# arrowhead has no meaning in DWB 2, arrowhead = 7 makes filled arrowheads in gpic and in 10th Edition
+# arrowhead is undefined in DWB 2, initially 1 in gpic, 2 in 10th Edition
+arrowhead = 7 # not used by graphviz
+# GNU pic supports a boxrad variable to draw boxes with rounded corners; DWB and 10th Ed. do not
+boxrad = 0 # no rounded corners in graphviz
+# GNU pic supports a linethick variable to set line thickness; DWB and 10th Ed. do not
+linethick = 1; oldlinethick = linethick
+# .PS w/o args causes GNU pic to scale drawing to fit 8.5x11 paper; DWB does not
+# maxpsht and maxpswid have no meaning in DWB 2.0, set page boundaries in gpic and in 10th Edition
+# maxpsht and maxpswid are predefined to 11.0 and 8.5 in gpic
+maxpsht = 3.597222
+maxpswid = 6.500000
+Dot: [
+define attrs0 % %; define unfilled % %; define rounded % %; define diagonals % %
+setfillval 0.000000
+setfillval 0.827451
+.ft R 
+.ps 8*\n(SFu/6500u
+setfillval 1.000000
+setfillval 1.000000
+setfillval 1.000000
+{
+define attrs1 % %
+#      Bridge
+setfillval 0.000000
+box attrs1 wid 0.53352 ht 0.32011 at (2.19631,2.56088);
+{
+define attrs2 % %
+setfillval 0.000000
+"Bridge" at (2.19631,2.55791);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      sFlow
+setfillval 0.000000
+box attrs1 wid 0.49795 ht 0.32011 at (0.24897,1.76060);
+{
+define attrs2 % %
+setfillval 0.000000
+"sFlow" at (0.24897,1.75764);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Bridge -> sFlow
+setfillval 0.000000
+setfillval 0.000000
+P0: (1.92955,2.52531)
+P1: (1.84522,2.51062)
+P2: (1.75320,2.49315)
+P3: (1.65489,2.47281)
+P4: (1.55168,2.44948)
+P5: (1.44494,2.42305)
+P6: (1.33607,2.39342)
+P7: (1.22645,2.36049)
+P8: (1.11747,2.32414)
+P9: (1.01051,2.28427)
+P10: (0.90698,2.24077)
+P11: (0.86432,2.21866)
+P12: (0.82183,2.19517)
+P13: (0.77965,2.17050)
+P14: (0.73796,2.14488)
+P15: (0.69690,2.11850)
+P16: (0.65665,2.09160)
+P17: (0.61736,2.06437)
+P18: (0.57918,2.03703)
+P19: (0.54229,2.00981)
+P20: (0.50684,1.98290)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (0.52462,1.95622)
+P1: (0.43570,1.92066)
+P2: (0.48016,2.00068)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"sflow" at (1.12483,2.15777);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Mirror
+setfillval 0.000000
+box attrs1 wid 0.51573 ht 0.32011 at (1.73393,1.76060);
+{
+define attrs2 % %
+setfillval 0.000000
+"Mirror" at (1.73393,1.75764);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Bridge -> Mirror
+setfillval 0.000000
+setfillval 0.000000
+P0: (2.09850,2.40082)
+P1: (2.08807,2.38482)
+P2: (2.07808,2.36881)
+P3: (2.06840,2.35280)
+P4: (2.05894,2.33680)
+P5: (2.04959,2.32079)
+P6: (2.04024,2.30479)
+P7: (2.03077,2.28878)
+P8: (2.02110,2.27278)
+P9: (2.01111,2.25677)
+P10: (2.00068,2.24077)
+P11: (1.98735,2.21676)
+P12: (1.97401,2.19275)
+P13: (1.96067,2.16874)
+P14: (1.94733,2.14473)
+P15: (1.93399,2.12073)
+P16: (1.92066,2.09672)
+P17: (1.90732,2.07271)
+P18: (1.89398,2.04870)
+P19: (1.88064,2.02469)
+P20: (1.86731,2.00068)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (1.89398,1.98290)
+P1: (1.82285,1.92066)
+P2: (1.84063,2.00958)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"mirrors" at (2.24966,2.15777);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Port
+setfillval 0.000000
+box attrs1 wid 0.48016 ht 0.32011 at (3.31669,1.76060);
+{
+define attrs2 % %
+setfillval 0.000000
+"Port" at (3.31224,1.75764);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Bridge -> Port
+setfillval 0.000000
+setfillval 0.000000
+P0: (2.37415,2.40082)
+P1: (2.40743,2.37073)
+P2: (2.44300,2.33936)
+P3: (2.48050,2.30703)
+P4: (2.51955,2.27406)
+P5: (2.55976,2.24077)
+P6: (2.60078,2.20747)
+P7: (2.64223,2.17450)
+P8: (2.68373,2.14217)
+P9: (2.72490,2.11080)
+P10: (2.76539,2.08071)
+P11: (2.78699,2.06471)
+P12: (2.80907,2.04877)
+P13: (2.83157,2.03294)
+P14: (2.85445,2.01726)
+P15: (2.87765,2.00180)
+P16: (2.90112,1.98660)
+P17: (2.92480,1.97172)
+P18: (2.94863,1.95722)
+P19: (2.97258,1.94314)
+P20: (2.99658,1.92955)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (3.01436,1.95622)
+P1: (3.07661,1.88509)
+P2: (2.98769,1.90287)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"ports" at (2.92100,2.15777);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Controller
+setfillval 0.000000
+box attrs1 wid 0.74692 ht 0.32011 at (4.09029,1.76060);
+{
+define attrs2 % %
+setfillval 0.000000
+"Controller" at (4.08584,1.75764);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Bridge -> Controller
+setfillval 0.000000
+setfillval 0.000000
+P0: (2.46306,2.48085)
+P1: (2.51818,2.46164)
+P2: (2.57638,2.44137)
+P3: (2.63704,2.42003)
+P4: (2.69952,2.39762)
+P5: (2.76317,2.37415)
+P6: (2.82735,2.34960)
+P7: (2.89142,2.32399)
+P8: (2.95475,2.29732)
+P9: (3.01669,2.26958)
+P10: (3.07661,2.24077)
+P11: (3.11337,2.22284)
+P12: (3.14447,2.20619)
+P13: (3.17120,2.19051)
+P14: (3.19483,2.17546)
+P15: (3.21666,2.16074)
+P16: (3.23794,2.14601)
+P17: (3.25998,2.13097)
+P18: (3.28404,2.11528)
+P19: (3.31141,2.09864)
+P20: (3.34337,2.08071)
+P21: (3.37271,2.06713)
+P22: (3.40205,2.05318)
+P23: (3.43140,2.03902)
+P24: (3.46074,2.02480)
+P25: (3.49008,2.01069)
+P26: (3.51943,1.99684)
+P27: (3.54877,1.98342)
+P28: (3.57811,1.97059)
+P29: (3.60746,1.95851)
+P30: (3.63680,1.94733)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+move to P20; line attrs1 to P21 then to P22
+move to P22; line attrs1 to P23 then to P24
+move to P24; line attrs1 to P25 then to P26
+move to P26; line attrs1 to P27 then to P28
+move to P28; line attrs1 to P29 then to P30
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (3.64569,1.97401)
+P1: (3.71683,1.91176)
+P2: (3.61902,1.92066)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"controller" at (3.63680,2.15777);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      NetFlow
+setfillval 0.000000
+box attrs1 wid 0.65800 ht 0.32011 at (0.98700,1.76060);
+{
+define attrs2 % %
+setfillval 0.000000
+"NetFlow" at (0.98700,1.75764);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Bridge -> NetFlow
+setfillval 0.000000
+setfillval 0.000000
+P0: (1.92955,2.48085)
+P1: (1.88055,2.46404)
+P2: (1.82989,2.44564)
+P3: (1.77806,2.42563)
+P4: (1.72553,2.40402)
+P5: (1.67279,2.38081)
+P6: (1.62032,2.35601)
+P7: (1.56860,2.32960)
+P8: (1.51810,2.30159)
+P9: (1.46931,2.27198)
+P10: (1.42271,2.24077)
+P11: (1.39363,2.21891)
+P12: (1.36509,2.19609)
+P13: (1.33708,2.17242)
+P14: (1.30960,2.14801)
+P15: (1.28266,2.12295)
+P16: (1.25625,2.09736)
+P17: (1.23038,2.07134)
+P18: (1.20503,2.04500)
+P19: (1.18023,2.01845)
+P20: (1.15595,1.99179)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (1.18263,1.97401)
+P1: (1.10260,1.92066)
+P2: (1.12927,2.00958)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"netflow" at (1.71170,2.15777);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Mirror -> Port
+setfillval 0.000000
+setfillval 0.000000
+P0: (1.79617,1.60055)
+P1: (1.81565,1.56758)
+P2: (1.83679,1.53318)
+P3: (1.85963,1.49803)
+P4: (1.88424,1.46283)
+P5: (1.91065,1.42827)
+P6: (1.93894,1.39504)
+P7: (1.96914,1.36384)
+P8: (2.00132,1.33535)
+P9: (2.03553,1.31029)
+P10: (2.07182,1.28933)
+P11: (2.17646,1.23651)
+P12: (2.27299,1.19543)
+P13: (2.36344,1.16609)
+P14: (2.44983,1.14848)
+P15: (2.53420,1.14261)
+P16: (2.61857,1.14848)
+P17: (2.70496,1.16609)
+P18: (2.79541,1.19543)
+P19: (2.89194,1.23651)
+P20: (2.99658,1.28933)
+P21: (3.02512,1.30421)
+P22: (3.05207,1.32191)
+P23: (3.07741,1.34207)
+P24: (3.10115,1.36431)
+P25: (3.12329,1.38825)
+P26: (3.14383,1.41353)
+P27: (3.16277,1.43977)
+P28: (3.18011,1.46660)
+P29: (3.19585,1.49364)
+P30: (3.20999,1.52052)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+move to P20; line attrs1 to P21 then to P22
+move to P22; line attrs1 to P23 then to P24
+move to P24; line attrs1 to P25 then to P26
+move to P26; line attrs1 to P27 then to P28
+move to P28; line attrs1 to P29 then to P30
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (3.18331,1.53830)
+P1: (3.25445,1.60055)
+P2: (3.23666,1.51163)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"select_src_port" at (2.52975,1.35750);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Mirror -> Port
+setfillval 0.000000
+setfillval 0.000000
+P0: (1.99179,1.76060)
+P1: (2.07850,1.76060)
+P2: (2.17219,1.76060)
+P3: (2.27133,1.76060)
+P4: (2.37436,1.76060)
+P5: (2.47974,1.76060)
+P6: (2.58592,1.76060)
+P7: (2.69135,1.76060)
+P8: (2.79448,1.76060)
+P9: (2.89378,1.76060)
+P10: (2.98769,1.76060)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (2.98769,1.79617)
+P1: (3.07661,1.76060)
+P2: (2.98769,1.73393)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"output_port" at (2.52975,1.82877);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Mirror -> Port
+setfillval 0.000000
+setfillval 0.000000
+P0: (1.99179,1.60055)
+P1: (1.99979,1.59788)
+P2: (2.00780,1.59521)
+P3: (2.01580,1.59254)
+P4: (2.02380,1.58988)
+P5: (2.03181,1.58721)
+P6: (2.03981,1.58454)
+P7: (2.04781,1.58187)
+P8: (2.05581,1.57921)
+P9: (2.06382,1.57654)
+P10: (2.07182,1.57387)
+P11: (2.17501,1.54698)
+P12: (2.26780,1.52521)
+P13: (2.35312,1.50889)
+P14: (2.43390,1.49833)
+P15: (2.51308,1.49384)
+P16: (2.59360,1.49576)
+P17: (2.67838,1.50441)
+P18: (2.77037,1.52009)
+P19: (2.87249,1.54314)
+P20: (2.98769,1.57387)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (2.97880,1.60055)
+P1: (3.07661,1.60055)
+P2: (2.99658,1.54720)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"select_dst_port" at (2.53420,1.64204);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      QoS
+setfillval 0.000000
+box attrs1 wid 0.48016 ht 0.32011 at (2.77428,0.96033);
+{
+define attrs2 % %
+setfillval 0.000000
+"QoS" at (2.76984,0.95736);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Port -> QoS
+setfillval 0.000000
+setfillval 0.000000
+P0: (3.20999,1.60055)
+P1: (3.18522,1.56461)
+P2: (3.15912,1.52642)
+P3: (3.13196,1.48643)
+P4: (3.10399,1.44505)
+P5: (3.07550,1.40270)
+P6: (3.04673,1.35982)
+P7: (3.01797,1.31684)
+P8: (2.98947,1.27418)
+P9: (2.96150,1.23226)
+P10: (2.93434,1.19152)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (2.96101,1.17373)
+P1: (2.88098,1.12038)
+P2: (2.90766,1.20930)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"qos" at (3.20554,1.35750);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Interface
+setfillval 0.000000
+box attrs1 wid 0.69357 ht 0.32011 at (3.52120,0.96033);
+{
+define attrs2 % %
+setfillval 0.000000
+"Interface" at (3.52120,0.95736);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Port -> Interface
+setfillval 0.000000
+setfillval 0.000000
+P0: (3.36115,1.60055)
+P1: (3.36941,1.56486)
+P2: (3.37815,1.52742)
+P3: (3.38732,1.48859)
+P4: (3.39686,1.44874)
+P5: (3.40672,1.40826)
+P6: (3.41685,1.36751)
+P7: (3.42719,1.32686)
+P8: (3.43769,1.28670)
+P9: (3.44830,1.24739)
+P10: (3.45896,1.20930)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (3.48564,1.20930)
+P1: (3.47674,1.12038)
+P2: (3.43228,1.20041)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"interfaces" at (3.75239,1.35750);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Queue
+setfillval 0.000000
+box attrs1 wid 0.55130 ht 0.32011 at (2.77428,0.16005);
+{
+define attrs2 % %
+setfillval 0.000000
+"Queue" at (2.77428,0.15709);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      QoS -> Queue
+setfillval 0.000000
+setfillval 0.000000
+P0: (2.77428,0.80027)
+P1: (2.77428,0.76483)
+P2: (2.77428,0.72800)
+P3: (2.77428,0.69000)
+P4: (2.77428,0.65103)
+P5: (2.77428,0.61132)
+P6: (2.77428,0.57108)
+P7: (2.77428,0.53051)
+P8: (2.77428,0.48984)
+P9: (2.77428,0.44927)
+P10: (2.77428,0.40903)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (2.80985,0.40903)
+P1: (2.77428,0.32011)
+P2: (2.74761,0.40903)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"queues value" at (3.18331,0.55723);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Open_vSwitch
+setfillval 0.000000
+box attrs1 wid 1.03146 ht 0.32011 at (4.49042,3.36115);
+{
+define attrs2 % %
+setfillval 0.000000
+"Open_vSwitch" at (4.49042,3.35819);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Open_vSwitch -> Bridge
+setfillval 0.000000
+setfillval 0.000000
+P0: (3.97469,3.20109)
+P1: (3.92643,3.18509)
+P2: (3.87773,3.16908)
+P3: (3.82872,3.15308)
+P4: (3.77950,3.13707)
+P5: (3.73016,3.12107)
+P6: (3.68083,3.10506)
+P7: (3.63161,3.08906)
+P8: (3.58259,3.07305)
+P9: (3.53390,3.05705)
+P10: (3.48564,3.04104)
+P11: (3.38867,3.00613)
+P12: (3.29037,2.97090)
+P13: (3.19154,2.93556)
+P14: (3.09297,2.90033)
+P15: (2.99547,2.86542)
+P16: (2.89984,2.83105)
+P17: (2.80687,2.79742)
+P18: (2.71737,2.76475)
+P19: (2.63214,2.73325)
+P20: (2.55198,2.70315)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (2.56088,2.66758)
+P1: (2.46306,2.66758)
+P2: (2.53420,2.72982)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"bridges" at (3.76129,2.95805);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Open_vSwitch -> Controller
+setfillval 0.000000
+setfillval 0.000000
+P0: (4.36594,3.20109)
+P1: (4.34122,3.16220)
+P2: (4.31543,3.12043)
+P3: (4.28911,3.07609)
+P4: (4.26279,3.02952)
+P5: (4.23700,2.98102)
+P6: (4.21228,2.93092)
+P7: (4.18917,2.87954)
+P8: (4.16818,2.82721)
+P9: (4.14986,2.77423)
+P10: (4.13475,2.72093)
+P11: (4.11548,2.64795)
+P12: (4.10010,2.57354)
+P13: (4.08825,2.49837)
+P14: (4.07955,2.42316)
+P15: (4.07361,2.34858)
+P16: (4.07008,2.27534)
+P17: (4.06858,2.20412)
+P18: (4.06873,2.13563)
+P19: (4.07016,2.07055)
+P20: (4.07250,2.00958)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (4.10807,2.00958)
+P1: (4.07250,1.92066)
+P2: (4.04583,2.00958)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"controller" at (4.42818,2.55791);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Capability
+setfillval 0.000000
+box attrs1 wid 0.74692 ht 0.32011 at (5.17510,2.56088);
+{
+define attrs2 % %
+setfillval 0.000000
+"Capability" at (5.17510,2.55791);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Open_vSwitch -> Capability
+setfillval 0.000000
+setfillval 0.000000
+P0: (4.63269,3.20109)
+P1: (4.66305,3.16515)
+P2: (4.69522,3.12697)
+P3: (4.72889,3.08698)
+P4: (4.76373,3.04559)
+P5: (4.79942,3.00325)
+P6: (4.83564,2.96037)
+P7: (4.87208,2.91739)
+P8: (4.90842,2.87473)
+P9: (4.94432,2.83281)
+P10: (4.97948,2.79207)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (5.00616,2.80985)
+P1: (5.03283,2.72093)
+P2: (4.95280,2.77428)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"capabilities value" at (5.41518,2.95805);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      SSL
+setfillval 0.000000
+box attrs1 wid 0.48016 ht 0.32011 at (6.18878,2.56088);
+{
+define attrs2 % %
+setfillval 0.000000
+"SSL" at (6.18878,2.55791);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+{
+define attrs1 % %
+#      Open_vSwitch -> SSL
+setfillval 0.000000
+setfillval 0.000000
+P0: (5.00616,3.29891)
+P1: (5.11780,3.28184)
+P2: (5.23244,3.26270)
+P3: (5.34771,3.24153)
+P4: (5.46128,3.21838)
+P5: (5.57079,3.19331)
+P6: (5.67390,3.16638)
+P7: (5.76827,3.13763)
+P8: (5.85153,3.10712)
+P9: (5.92135,3.07491)
+P10: (5.97538,3.04104)
+P11: (5.99617,3.02160)
+P12: (6.01585,3.00078)
+P13: (6.03436,2.97878)
+P14: (6.05163,2.95582)
+P15: (6.06763,2.93211)
+P16: (6.08229,2.90787)
+P17: (6.09557,2.88331)
+P18: (6.10740,2.85865)
+P19: (6.11774,2.83409)
+P20: (6.12654,2.80985)
+move to P0; line attrs1 to P1 then to P2
+move to P2; line attrs1 to P3 then to P4
+move to P4; line attrs1 to P5 then to P6
+move to P6; line attrs1 to P7 then to P8
+move to P8; line attrs1 to P9 then to P10
+move to P10; line attrs1 to P11 then to P12
+move to P12; line attrs1 to P13 then to P14
+move to P14; line attrs1 to P15 then to P16
+move to P16; line attrs1 to P17 then to P18
+move to P18; line attrs1 to P19 then to P20
+{
+define attrs2 % %
+define attrs2 % solid %
+oldlinethick = linethick;linethick = 1 * scalethickness / 10153
+P0: (6.15321,2.81874)
+P1: (6.15321,2.72093)
+P2: (6.09986,2.80096)
+move to P0; line attrs2 to P1
+move to P1; line attrs2 to P2
+move to P2; line attrs2 to P0
+}
+linethick = oldlinethick
+{
+define attrs2 % %
+setfillval 0.000000
+"ssl" at (6.14877,2.95805);
+}
+linethick = oldlinethick
+}
+linethick = oldlinethick
+]
+.PE
+.\"  restore point size and font
+.ps \n(.S
+.ft \n(DF