summaryrefslogtreecommitdiff
path: root/build-aux/extract-ofp-actions
diff options
context:
space:
mode:
authorBen Pfaff <blp@ovn.org>2018-11-08 21:39:55 -0800
committerBen Pfaff <blp@ovn.org>2019-01-10 15:52:05 -0800
commitbe51cd41734336f3569bd7e18768123799b42a13 (patch)
tree17482ddf4fd5f0eb0a8c4150df55e8fcf94634b3 /build-aux/extract-ofp-actions
parenta31c38ad0baeb6672c7c264a2b69ce198f4a75dd (diff)
downloadopenvswitch-be51cd41734336f3569bd7e18768123799b42a13.tar.gz
ovs-actions: New document describing OVS actions in detail.
Acked-by: Mark Michelson <mmichels@redhat.com> Signed-off-by: Ben Pfaff <blp@ovn.org>
Diffstat (limited to 'build-aux/extract-ofp-actions')
-rwxr-xr-xbuild-aux/extract-ofp-actions201
1 files changed, 184 insertions, 17 deletions
diff --git a/build-aux/extract-ofp-actions b/build-aux/extract-ofp-actions
index bd7131f1a..64de0f31f 100755
--- a/build-aux/extract-ofp-actions
+++ b/build-aux/extract-ofp-actions
@@ -1,8 +1,11 @@
#! /usr/bin/python
+import getopt
import sys
import os.path
import re
+import xml.dom.minidom
+import build.nroff
OFP_ACTION_ALIGN = 8
@@ -69,14 +72,21 @@ def usage():
argv0 = os.path.basename(sys.argv[0])
print('''\
%(argv0)s, for extracting OpenFlow action data
-usage: %(argv0)s OFP_ACTIONS.C [--prototypes | --definitions]
+usage: %(argv0)s [prototypes | definitions] OFP-ACTIONS.c
+usage: %(argv0)s ovs-actions OVS-ACTIONS.XML
-This program reads ofp-actions.c to obtain information about OpenFlow
-actions. With --prototypes, it outputs on stdout a set of prototypes to
-#include early in ofp-actions.c. With --definitions, it outputs on stdout
-a set of definitions to #include late in ofp-actions.c
+Commands:
-OFP_ACTIONS.C should point to lib/ofp-actions.c.\
+ prototypes OFP-ACTIONS.C
+ Reads ofp-actions.c and prints a set of prototypes to #include early in
+ ofp-actions.c.
+
+ definitions OFP-ACTIONS.C
+ Reads ofp-actions.c and prints a set of definitions to #include late in
+ ofp-actions.c.
+
+ ovs-actions OVS-ACTIONS.XML
+ Reads ovs-actions.xml and prints documentation in troff format.\
''' % {"argv0": argv0})
sys.exit(0)
@@ -377,19 +387,176 @@ static enum ofperr ofpact_decode(const struct ofp_action_header *,
uint64_t arg, const struct vl_mff_map *vl_mff_map,
uint64_t *tlv_bitmap, struct ofpbuf *out);
""")
+
+## ------------------------ ##
+## Documentation Generation ##
+## ------------------------ ##
+
+def action_to_xml(action_node, body):
+ syntax = 0
+ for node in action_node.childNodes:
+ if node.nodeType == node.ELEMENT_NODE and node.tagName == 'syntax':
+ if body[-1].strip() == '.PP':
+ del body[-1]
+ if syntax:
+ body += ['.IQ\n']
+ else:
+ body += ['.IP "\\fBSyntax:\\fR"\n']
+ body += [build.nroff.inline_xml_to_nroff(x, r'\fR')
+ for x in node.childNodes] + ['\n']
+ syntax += 1
+ elif (node.nodeType == node.ELEMENT_NODE
+ and node.tagName == 'conformance'):
+ body += ['.IP "\\fBConformance:\\fR"\n']
+ body += [build.nroff.block_xml_to_nroff(node.childNodes)]
+ else:
+ body += [build.nroff.block_xml_to_nroff([node])]
+
+def group_xml_to_nroff(group_node):
+ title = group_node.attributes['title'].nodeValue
+
+ body = []
+ for node in group_node.childNodes:
+ if node.nodeType == node.ELEMENT_NODE and node.tagName == 'action':
+ action_to_xml(node, body)
+ else:
+ body += [build.nroff.block_xml_to_nroff([node])]
+
+ content = [
+ '.bp\n',
+ '.SH \"%s\"\n' % build.nroff.text_to_nroff(title.upper())]
+ content += body
+ return ''.join(content)
+
+def make_ovs_actions(ovs_actions_xml):
+ document = xml.dom.minidom.parse(ovs_actions_xml)
+ doc = document.documentElement
+
+ global version
+ if version == None:
+ version = "UNKNOWN"
+
+ print('''\
+'\\" tp
+.\\" -*- mode: troff; coding: utf-8 -*-
+.TH "ovs\-actions" 7 "%s" "Open vSwitch" "Open vSwitch Manual"
+.fp 5 L CR \\" Make fixed-width font available as \\fL.
+.de ST
+. PP
+. RS -0.15in
+. I "\\\\$1"
+. RE
+..
+
+.de SU
+. PP
+. I "\\\\$1"
+..
+
+.de IQ
+. br
+. ns
+. IP "\\\\$1"
+..
+
+.de TQ
+. br
+. ns
+. TP "\\\\$1"
+..
+.de URL
+\\\\$2 \\(laURL: \\\\$1 \\(ra\\\\$3
+..
+.if \\n[.g] .mso www.tmac
+.SH NAME
+ovs\-actions \- OpenFlow actions and instructions with Open vSwitch extensions
+.
+.PP
+''' % version)
+
+ s = ''
+ for node in doc.childNodes:
+ if node.nodeType == node.ELEMENT_NODE and node.tagName == "group":
+ s += group_xml_to_nroff(node)
+ elif node.nodeType == node.TEXT_NODE:
+ assert node.data.isspace()
+ elif node.nodeType == node.COMMENT_NODE:
+ pass
+ else:
+ s += build.nroff.block_xml_to_nroff([node])
+
+ if n_errors:
+ sys.exit(1)
+
+ output = []
+ for oline in s.split("\n"):
+ oline = oline.strip()
+
+ # Life is easier with nroff if we don't try to feed it Unicode.
+ # Fortunately, we only use a few characters outside the ASCII range.
+ oline = oline.replace(u'\u2208', r'\[mo]')
+ oline = oline.replace(u'\u2260', r'\[!=]')
+ oline = oline.replace(u'\u2264', r'\[<=]')
+ oline = oline.replace(u'\u2265', r'\[>=]')
+ oline = oline.replace(u'\u00d7', r'\[mu]')
+ if len(oline):
+ output += [oline]
+
+ # nroff tends to ignore .bp requests if they come after .PP requests,
+ # so remove .PPs that precede .bp.
+ for i in range(len(output)):
+ if output[i] == '.bp':
+ j = i - 1
+ while j >= 0 and output[j] == '.PP':
+ output[j] = None
+ j -= 1
+ for i in range(len(output)):
+ if output[i] is not None:
+ print(output[i])
+
+
+## ------------ ##
+## Main Program ##
+## ------------ ##
if __name__ == '__main__':
- if '--help' in sys.argv:
- usage()
- elif len(sys.argv) != 3:
- sys.stderr.write("exactly two arguments required; "
- "use --help for help\n")
+ argv0 = sys.argv[0]
+ try:
+ options, args = getopt.gnu_getopt(sys.argv[1:], 'h',
+ ['help', 'ovs-version='])
+ except getopt.GetoptError as geo:
+ sys.stderr.write("%s: %s\n" % (argv0, geo.msg))
sys.exit(1)
- elif sys.argv[2] == '--prototypes':
- extract_ofp_actions(sys.argv[1], False)
- elif sys.argv[2] == '--definitions':
- extract_ofp_actions(sys.argv[1], True)
- else:
- sys.stderr.write("invalid arguments; use --help for help\n")
+
+ global version
+ version = None
+ for key, value in options:
+ if key in ['-h', '--help']:
+ usage()
+ elif key == '--ovs-version':
+ version = value
+ else:
+ sys.exit(0)
+
+ if not args:
+ sys.stderr.write("%s: missing command argument "
+ "(use --help for help)\n" % argv0)
+ sys.exit(1)
+
+ commands = {"prototypes": (lambda fn: extract_ofp_actions(fn, False), 1),
+ "definitions": (lambda fn: extract_ofp_actions(fn, True), 1),
+ "ovs-actions": (make_ovs_actions, 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:])