]> git.proxmox.com Git - ovs.git/blob - build-aux/extract-ofp-msgs
netdev-dpdk: Use multiple core for dpdk IO.
[ovs.git] / build-aux / extract-ofp-msgs
1 #! /usr/bin/python
2
3 import sys
4 import os.path
5 import re
6
7 line = ""
8
9 OFP10_VERSION = 0x01
10 OFP11_VERSION = 0x02
11 OFP12_VERSION = 0x03
12 OFP13_VERSION = 0x04
13 OFP14_VERSION = 0x05
14
15 NX_VENDOR_ID = 0x00002320
16
17 OFPT_VENDOR = 4
18 OFPT10_STATS_REQUEST = 16
19 OFPT10_STATS_REPLY = 17
20 OFPT11_STATS_REQUEST = 18
21 OFPT11_STATS_REPLY = 19
22 OFPST_VENDOR = 0xffff
23
24 version_map = {"1.0": (OFP10_VERSION, OFP10_VERSION),
25 "1.1": (OFP11_VERSION, OFP11_VERSION),
26 "1.2": (OFP12_VERSION, OFP12_VERSION),
27 "1.3": (OFP13_VERSION, OFP13_VERSION),
28 "1.4": (OFP14_VERSION, OFP14_VERSION),
29 "1.0+": (OFP10_VERSION, OFP14_VERSION),
30 "1.1+": (OFP11_VERSION, OFP14_VERSION),
31 "1.2+": (OFP12_VERSION, OFP14_VERSION),
32 "1.3+": (OFP13_VERSION, OFP14_VERSION),
33 "1.4+": (OFP14_VERSION, OFP14_VERSION),
34 "1.0-1.1": (OFP10_VERSION, OFP11_VERSION),
35 "1.0-1.2": (OFP10_VERSION, OFP12_VERSION),
36 "1.1-1.2": (OFP11_VERSION, OFP12_VERSION),
37 "<all>": (0x01, 0xff)}
38
39 def get_line():
40 global line
41 global line_number
42 line = input_file.readline()
43 line_number += 1
44 if line == "":
45 fatal("unexpected end of input")
46
47 n_errors = 0
48 def error(msg):
49 global n_errors
50 sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
51 n_errors += 1
52
53 def fatal(msg):
54 error(msg)
55 sys.exit(1)
56
57 def usage():
58 argv0 = os.path.basename(sys.argv[0])
59 print '''\
60 %(argv0)s, for extracting OpenFlow message types from header files
61 usage: %(argv0)s INPUT OUTPUT
62 where INPUT is the name of the input header file
63 and OUTPUT is the output file name.
64 Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
65 only controls #line directives in the output.\
66 ''' % {"argv0": argv0}
67 sys.exit(0)
68
69 def make_sizeof(s):
70 m = re.match(r'(.*) up to (.*)', s)
71 if m:
72 struct, member = m.groups()
73 return "offsetof(%s, %s)" % (struct, member)
74 else:
75 return "sizeof(%s)" % s
76
77 def extract_ofp_msgs(output_file_name):
78 raw_types = []
79
80 all_hdrs = {}
81 all_raws = {}
82 all_raws_order = []
83
84 while True:
85 get_line()
86 if re.match('enum ofpraw', line):
87 break
88
89 while True:
90 get_line()
91 first_line_number = line_number
92 here = '%s:%d' % (file_name, line_number)
93 if (line.startswith('/*')
94 or line.startswith(' *')
95 or not line
96 or line.isspace()):
97 continue
98 elif re.match('}', line):
99 break
100
101 if not line.lstrip().startswith('/*'):
102 fatal("unexpected syntax between ofpraw types")
103
104 comment = line.lstrip()[2:].strip()
105 while not comment.endswith('*/'):
106 get_line()
107 if line.startswith('/*') or not line or line.isspace():
108 fatal("unexpected syntax within error")
109 comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
110 comment = comment[:-2].rstrip()
111
112 m = re.match(r'([A-Z]+) ([-.+\d]+|<all>) \((\d+)\): ([^.]+)\.$', comment)
113 if not m:
114 fatal("unexpected syntax between messages")
115 type_, versions, number, contents = m.groups()
116 number = int(number)
117
118 get_line()
119 m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
120 line)
121 if not m:
122 fatal("syntax error expecting OFPRAW_ enum")
123 vinfix, name = m.groups()
124 rawname = 'OFPRAW_%s%s_%s' % (type_, vinfix, name)
125
126 min_version, max_version = version_map[versions]
127
128 human_name = '%s_%s' % (type_, name)
129 if type_.endswith('ST'):
130 if rawname.endswith('_REQUEST'):
131 human_name = human_name[:-8] + " request"
132 elif rawname.endswith('_REPLY'):
133 human_name = human_name[:-6] + " reply"
134 else:
135 fatal("%s messages are statistics but %s doesn't end "
136 "in _REQUEST or _REPLY" % (type_, rawname))
137
138 these_hdrs = []
139 for version in range(min_version, max_version + 1):
140 if type_ == 'OFPT':
141 if number == OFPT_VENDOR:
142 fatal("OFPT (%d) is used for vendor extensions"
143 % number)
144 elif (version == OFP10_VERSION
145 and (number == OFPT10_STATS_REQUEST
146 or number == OFPT10_STATS_REPLY)):
147 fatal("OFPT 1.0 (%d) is used for stats messages"
148 % number)
149 elif (version != OFP10_VERSION
150 and (number == OFPT11_STATS_REQUEST
151 or number == OFPT11_STATS_REPLY)):
152 fatal("OFPT 1.1+ (%d) is used for stats messages"
153 % number)
154 hdrs = (version, number, 0, 0, 0)
155 elif type_ == 'OFPST' and name.endswith('_REQUEST'):
156 if version == OFP10_VERSION:
157 hdrs = (version, OFPT10_STATS_REQUEST, number, 0, 0)
158 else:
159 hdrs = (version, OFPT11_STATS_REQUEST, number, 0, 0)
160 elif type_ == 'OFPST' and name.endswith('_REPLY'):
161 if version == OFP10_VERSION:
162 hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
163 else:
164 hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
165 elif type_ == 'NXT':
166 hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
167 elif type_ == 'NXST' and name.endswith('_REQUEST'):
168 if version == OFP10_VERSION:
169 hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
170 NX_VENDOR_ID, number)
171 else:
172 hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
173 NX_VENDOR_ID, number)
174 elif type_ == 'NXST' and name.endswith('_REPLY'):
175 if version == OFP10_VERSION:
176 hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
177 NX_VENDOR_ID, number)
178 else:
179 hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
180 NX_VENDOR_ID, number)
181 else:
182 fatal("type '%s' unknown" % type_)
183
184 if hdrs in all_hdrs:
185 error("Duplicate message definition for %s." % str(hdrs))
186 sys.stderr.write("%s: Here is the location "
187 "of the previous definition.\n"
188 % (all_hdrs[hdrs]))
189 all_hdrs[hdrs] = here
190 these_hdrs.append(hdrs)
191
192 extra_multiple = '0'
193 if contents == 'void':
194 min_body = '0'
195 else:
196 min_body_elem = []
197 for c in [s.strip() for s in contents.split(",")]:
198 if c.endswith('[]'):
199 if extra_multiple == '0':
200 extra_multiple = make_sizeof(c[:-2])
201 else:
202 error("Cannot have multiple [] elements")
203 else:
204 min_body_elem.append(c)
205
206 if min_body_elem:
207 min_body = " + ".join([make_sizeof(s)
208 for s in min_body_elem])
209 else:
210 if extra_multiple == '0':
211 error("Must specify contents (use 'void' if empty)")
212 min_body = 0
213
214 if rawname in all_raws:
215 fatal("%s: Duplicate name" % rawname)
216
217 all_raws[rawname] = {"hdrs": these_hdrs,
218 "min_version": min_version,
219 "max_version": max_version,
220 "min_body": min_body,
221 "extra_multiple": extra_multiple,
222 "type": type_,
223 "human_name": human_name,
224 "line": first_line_number}
225 all_raws_order.append(rawname)
226
227 continue
228
229 while True:
230 get_line()
231 if re.match('enum ofptype', line):
232 break
233
234 while True:
235 get_line()
236 if re.match(r'\s*/?\*', line) or line.isspace():
237 continue
238 elif re.match('}', line):
239 break
240
241 if not re.match(r'\s*OFPTYPE_.*/\*', line):
242 fatal("unexpected syntax between OFPTYPE_ definitions")
243
244 syntax = line.strip()
245 while not syntax.endswith('*/'):
246 get_line()
247 if not line.strip().startswith('*'):
248 fatal("unexpected syntax within OFPTYPE_ definition")
249 syntax += ' %s' % line.strip().lstrip('* \t')
250 syntax = syntax.strip()
251
252 m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
253 if not m:
254 fatal("syntax error in OFPTYPE_ definition")
255
256 ofptype, raws_ = m.groups()
257 raws = [s.rstrip('.') for s in raws_.split()]
258 for raw in raws:
259 if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
260 fatal("%s: invalid OFPRAW_* name syntax" % raw)
261 if raw not in all_raws:
262 fatal("%s: not a declared OFPRAW_* name" % raw)
263 if "ofptype" in all_raws[raw]:
264 fatal("%s: already part of %s"
265 % (raw, all_raws[raw]["ofptype"]))
266 all_raws[raw]["ofptype"] = ofptype
267
268 input_file.close()
269
270 if n_errors:
271 sys.exit(1)
272
273 output = []
274 output.append("/* Generated automatically; do not modify! "
275 "-*- buffer-read-only: t -*- */")
276 output.append("")
277
278 for raw in all_raws_order:
279 r = all_raws[raw]
280 output.append("static struct raw_instance %s_instances[] = {"
281 % raw.lower())
282 for hdrs in r['hdrs']:
283 output.append(" { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
284 % (hdrs + (raw,)))
285
286 output.append("};")
287
288 output.append("")
289
290 output.append("static struct raw_info raw_infos[] = {")
291 for raw in all_raws_order:
292 r = all_raws[raw]
293 if "ofptype" not in r:
294 error("%s: no defined OFPTYPE_" % raw)
295 continue
296 output.append(" {")
297 output.append(" %s_instances," % raw.lower())
298 output.append(" %d, %d," % (r["min_version"], r["max_version"]))
299 output.append("#line %s \"%s\"" % (r["line"], file_name))
300 output.append(" %s," % r["min_body"])
301 output.append("#line %s \"%s\"" % (r["line"], file_name))
302 output.append(" %s," % r["extra_multiple"])
303 output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
304 output.append(" %s," % r["ofptype"])
305 output.append(" \"%s\"," % r["human_name"])
306 output.append(" },")
307
308 if r['type'].endswith("ST"):
309 for hdrs in r['hdrs']:
310 op_hdrs = list(hdrs)
311 if hdrs[0] == OFP10_VERSION:
312 if hdrs[1] == OFPT10_STATS_REQUEST:
313 op_hdrs[1] = OFPT10_STATS_REPLY
314 elif hdrs[1] == OFPT10_STATS_REPLY:
315 op_hdrs[1] = OFPT10_STATS_REQUEST
316 else:
317 assert False
318 else:
319 if hdrs[1] == OFPT11_STATS_REQUEST:
320 op_hdrs[1] = OFPT11_STATS_REPLY
321 elif hdrs[1] == OFPT11_STATS_REPLY:
322 op_hdrs[1] = OFPT11_STATS_REQUEST
323 else:
324 assert False
325 if tuple(op_hdrs) not in all_hdrs:
326 if r["human_name"].endswith("request"):
327 fatal("%s has no corresponding reply"
328 % r["human_name"])
329 else:
330 fatal("%s has no corresponding request"
331 % r["human_name"])
332 output.append("};")
333
334 if n_errors:
335 sys.exit(1)
336
337 return output
338
339
340 if __name__ == '__main__':
341 if '--help' in sys.argv:
342 usage()
343 elif len(sys.argv) != 3:
344 sys.stderr.write("exactly one non-option arguments required; "
345 "use --help for help\n")
346 sys.exit(1)
347 else:
348 global file_name
349 global input_file
350 global line_number
351 file_name = sys.argv[1]
352 input_file = open(file_name)
353 line_number = 0
354
355 for line in extract_ofp_msgs(sys.argv[2]):
356 print line
357