]>
Commit | Line | Data |
---|---|---|
f6783a7a | 1 | #! /usr/bin/env python |
29089a54 RL |
2 | # |
3 | # Copyright (C) 2012 Nicira, Inc. | |
4 | # | |
5 | # Copying and distribution of this file, with or without modification, | |
6 | # are permitted in any medium without royalty provided the copyright | |
7 | # notice and this notice are preserved. This file is offered as-is, | |
8 | # without warranty of any kind. | |
9 | ||
8ea171ab RB |
10 | from __future__ import print_function |
11 | ||
29089a54 RL |
12 | import getopt |
13 | import re | |
14 | import sys | |
15 | import xml.sax | |
16 | import xml.sax.handler | |
17 | ||
bdca6c4b | 18 | |
29089a54 RL |
19 | class IpfixEntityHandler(xml.sax.handler.ContentHandler): |
20 | ||
21 | RECORD_FIELDS = ['name', 'dataType', 'elementId', 'status'] | |
22 | ||
23 | # Cf. RFC 5101, Section 6. | |
24 | DATA_TYPE_SIZE = { | |
25 | 'unsigned8': 1, | |
26 | 'unsigned16': 2, | |
27 | 'unsigned32': 4, | |
28 | 'unsigned64': 8, | |
29 | 'signed8': 1, | |
30 | 'signed16': 2, | |
31 | 'signed32': 4, | |
32 | 'signed64': 8, | |
33 | 'float32': 4, | |
34 | 'float64': 8, | |
35 | 'boolean': 1, # Not clear. | |
36 | 'macAddress': 6, | |
37 | 'octetArray': 0, # Not clear. | |
38 | 'string': 0, # Not clear. | |
39 | 'dateTimeSeconds': 4, | |
40 | 'dateTimeMilliseconds': 8, | |
41 | 'dateTimeMicroseconds': 8, | |
42 | 'dateTimeNanoseconds': 8, | |
43 | 'ipv4Address': 4, | |
44 | 'ipv6Address': 16, | |
45 | } | |
46 | ||
47 | def __init__(self): | |
48 | self.current_field_name = None | |
49 | self.current_field_value = [] | |
50 | self.current_record = dict() | |
51 | ||
52 | def startDocument(self): | |
8ea171ab | 53 | print("""\ |
29089a54 RL |
54 | /* IPFIX entities. */ |
55 | #ifndef IPFIX_ENTITY | |
56 | #define IPFIX_ENTITY(ENUM, ID, SIZE, NAME) | |
57 | #endif | |
8ea171ab | 58 | """) |
29089a54 RL |
59 | |
60 | def endDocument(self): | |
8ea171ab RB |
61 | print(""" |
62 | #undef IPFIX_ENTITY""") | |
29089a54 RL |
63 | |
64 | def startElement(self, name, attrs): | |
65 | if name in self.RECORD_FIELDS: | |
66 | self.current_field_name = name | |
67 | else: | |
68 | self.current_field_name = None | |
69 | self.current_field_value = [] | |
70 | ||
71 | @staticmethod | |
72 | def camelcase_to_uppercase(s): | |
73 | return re.sub('(.)([A-Z]+)', r'\1_\2', s).upper() | |
74 | ||
75 | def endElement(self, name): | |
76 | if self.current_field_name is not None: | |
77 | self.current_record[self.current_field_name] = ''.join( | |
78 | self.current_field_value).strip() | |
79 | elif (name == 'record' | |
80 | and self.current_record.get('status') == 'current' | |
81 | and 'dataType' in self.current_record): | |
82 | ||
83 | self.current_record['enumName'] = self.camelcase_to_uppercase( | |
84 | self.current_record['name']) | |
85 | self.current_record['dataTypeSize'] = self.DATA_TYPE_SIZE.get( | |
86 | self.current_record['dataType'], 0) | |
87 | ||
8ea171ab RB |
88 | print('IPFIX_ENTITY(%(enumName)s, %(elementId)s, ' |
89 | '%(dataTypeSize)i, %(name)s)' % self.current_record) | |
29089a54 RL |
90 | self.current_record.clear() |
91 | ||
92 | def characters(self, content): | |
93 | if self.current_field_name is not None: | |
94 | self.current_field_value.append(content) | |
95 | ||
bdca6c4b | 96 | |
29089a54 RL |
97 | def print_ipfix_entity_macros(xml_file): |
98 | xml.sax.parse(xml_file, IpfixEntityHandler()) | |
99 | ||
bdca6c4b | 100 | |
29089a54 | 101 | def usage(name): |
8ea171ab | 102 | print("""\ |
29089a54 RL |
103 | %(name)s: IPFIX entity definition generator |
104 | Prints C macros defining IPFIX entities from the standard IANA file at | |
105 | <http://www.iana.org/assignments/ipfix/ipfix.xml> | |
106 | usage: %(name)s [OPTIONS] XML | |
107 | where XML is the standard IANA XML file defining IPFIX entities | |
108 | ||
109 | The following options are also available: | |
110 | -h, --help display this help message | |
111 | -V, --version display version information\ | |
8ea171ab | 112 | """ % {'name': name}) |
29089a54 RL |
113 | sys.exit(0) |
114 | ||
81a86b9a | 115 | |
29089a54 | 116 | if __name__ == '__main__': |
eda26d40 RB |
117 | try: |
118 | options, args = getopt.gnu_getopt(sys.argv[1:], 'hV', | |
119 | ['help', 'version']) | |
f3068bff | 120 | except getopt.GetoptError as geo: |
eda26d40 RB |
121 | sys.stderr.write('%s: %s\n' % (sys.argv[0], geo.msg)) |
122 | sys.exit(1) | |
123 | ||
124 | for key, value in options: | |
125 | if key in ['-h', '--help']: | |
126 | usage() | |
127 | elif key in ['-V', '--version']: | |
8ea171ab | 128 | print('ipfix-gen-entities (Open vSwitch)') |
eda26d40 RB |
129 | else: |
130 | sys.exit(0) | |
131 | ||
132 | if len(args) != 1: | |
133 | sys.stderr.write('%s: exactly 1 non-option arguments required ' | |
134 | '(use --help for help)\n' % sys.argv[0]) | |
135 | sys.exit(1) | |
136 | ||
137 | print_ipfix_entity_macros(args[0]) | |
29089a54 RL |
138 | |
139 | # Local variables: | |
140 | # mode: python | |
141 | # End: |