]> git.proxmox.com Git - ovs.git/blame - build-aux/extract-ofp-msgs
Merge branch 'dpdk_merge' of https://github.com/istokes/ovs into HEAD
[ovs.git] / build-aux / extract-ofp-msgs
CommitLineData
982697a4
BP
1#! /usr/bin/python
2
3import sys
4import os.path
5import re
6
7line = ""
8
42dccab5
BP
9# Maps from user-friendly version number to its protocol encoding.
10VERSION = {"1.0": 0x01,
11 "1.1": 0x02,
12 "1.2": 0x03,
13 "1.3": 0x04,
14 "1.4": 0x05,
b79d45a1
BP
15 "1.5": 0x06,
16 "1.6": 0x07}
982697a4
BP
17
18NX_VENDOR_ID = 0x00002320
90219696 19ONF_VENDOR_ID = 0x4f4e4600
982697a4
BP
20
21OFPT_VENDOR = 4
22OFPT10_STATS_REQUEST = 16
23OFPT10_STATS_REPLY = 17
24OFPT11_STATS_REQUEST = 18
25OFPT11_STATS_REPLY = 19
26OFPST_VENDOR = 0xffff
27
42dccab5
BP
28def decode_version_range(range):
29 if range in VERSION:
30 return (VERSION[range], VERSION[range])
31 elif range.endswith('+'):
32 return (VERSION[range[:-1]], max(VERSION.values()))
33 elif range == '<all>':
34 return (0x01, 0xff)
35 else:
36 a, b = re.match(r'^([^-]+)-([^-]+)$', range).groups()
37 return (VERSION[a], VERSION[b])
982697a4
BP
38
39def 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
47n_errors = 0
48def error(msg):
49 global n_errors
50 sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
51 n_errors += 1
52
53def fatal(msg):
54 error(msg)
55 sys.exit(1)
56
57def usage():
58 argv0 = os.path.basename(sys.argv[0])
d34a1cc0 59 print('''\
982697a4
BP
60%(argv0)s, for extracting OpenFlow message types from header files
61usage: %(argv0)s INPUT OUTPUT
62 where INPUT is the name of the input header file
63 and OUTPUT is the output file name.
64Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
65only controls #line directives in the output.\
d34a1cc0 66''' % {"argv0": argv0})
982697a4
BP
67 sys.exit(0)
68
69def 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
77def 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():
91148d4b 108 fatal("unexpected syntax within message")
982697a4
BP
109 comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
110 comment = comment[:-2].rstrip()
111
cf7cf630 112 m = re.match(r'([A-Z]+) ([-.+\d]+|<all>) \((\d+)\): ([^.]+)\.$', comment)
982697a4
BP
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
42dccab5 126 min_version, max_version = decode_version_range(versions)
982697a4
BP
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)
42dccab5 144 elif (version == VERSION["1.0"]
982697a4
BP
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)
42dccab5 149 elif (version != VERSION["1.0"]
982697a4
BP
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'):
42dccab5 156 if version == VERSION["1.0"]:
982697a4
BP
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'):
42dccab5 161 if version == VERSION["1.0"]:
982697a4
BP
162 hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
163 else:
164 hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
2123bc8c 165 elif type_ == 'ONFT':
90219696
SH
166 hdrs = (version, OFPT_VENDOR, 0, ONF_VENDOR_ID, number)
167 elif type_ == 'ONFST' and name.endswith('_REQUEST'):
168 if version == VERSION["1.0"]:
169 hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
170 ONF_VENDOR_ID, number)
171 else:
172 hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
173 ONF_VENDOR_ID, number)
174 elif type_ == 'ONFST' and name.endswith('_REPLY'):
175 if version == VERSION["1.0"]:
176 hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
177 ONF_VENDOR_ID, number)
178 else:
179 hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
180 ONF_VENDOR_ID, number)
982697a4
BP
181 elif type_ == 'NXT':
182 hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
183 elif type_ == 'NXST' and name.endswith('_REQUEST'):
42dccab5 184 if version == VERSION["1.0"]:
982697a4
BP
185 hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
186 NX_VENDOR_ID, number)
187 else:
188 hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
189 NX_VENDOR_ID, number)
190 elif type_ == 'NXST' and name.endswith('_REPLY'):
42dccab5 191 if version == VERSION["1.0"]:
982697a4
BP
192 hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
193 NX_VENDOR_ID, number)
194 else:
195 hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
196 NX_VENDOR_ID, number)
197 else:
198 fatal("type '%s' unknown" % type_)
199
200 if hdrs in all_hdrs:
201 error("Duplicate message definition for %s." % str(hdrs))
202 sys.stderr.write("%s: Here is the location "
203 "of the previous definition.\n"
204 % (all_hdrs[hdrs]))
205 all_hdrs[hdrs] = here
206 these_hdrs.append(hdrs)
207
208 extra_multiple = '0'
209 if contents == 'void':
210 min_body = '0'
211 else:
212 min_body_elem = []
213 for c in [s.strip() for s in contents.split(",")]:
214 if c.endswith('[]'):
215 if extra_multiple == '0':
216 extra_multiple = make_sizeof(c[:-2])
217 else:
218 error("Cannot have multiple [] elements")
219 else:
220 min_body_elem.append(c)
221
222 if min_body_elem:
223 min_body = " + ".join([make_sizeof(s)
224 for s in min_body_elem])
225 else:
226 if extra_multiple == '0':
227 error("Must specify contents (use 'void' if empty)")
228 min_body = 0
229
230 if rawname in all_raws:
231 fatal("%s: Duplicate name" % rawname)
232
233 all_raws[rawname] = {"hdrs": these_hdrs,
234 "min_version": min_version,
235 "max_version": max_version,
236 "min_body": min_body,
237 "extra_multiple": extra_multiple,
238 "type": type_,
239 "human_name": human_name,
240 "line": first_line_number}
241 all_raws_order.append(rawname)
242
243 continue
244
245 while True:
246 get_line()
247 if re.match('enum ofptype', line):
248 break
249
64795a0d 250 all_types = []
982697a4
BP
251 while True:
252 get_line()
253 if re.match(r'\s*/?\*', line) or line.isspace():
254 continue
255 elif re.match('}', line):
256 break
257
258 if not re.match(r'\s*OFPTYPE_.*/\*', line):
259 fatal("unexpected syntax between OFPTYPE_ definitions")
260
261 syntax = line.strip()
262 while not syntax.endswith('*/'):
263 get_line()
264 if not line.strip().startswith('*'):
265 fatal("unexpected syntax within OFPTYPE_ definition")
266 syntax += ' %s' % line.strip().lstrip('* \t')
267 syntax = syntax.strip()
268
269 m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
270 if not m:
271 fatal("syntax error in OFPTYPE_ definition")
272
273 ofptype, raws_ = m.groups()
274 raws = [s.rstrip('.') for s in raws_.split()]
275 for raw in raws:
276 if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
277 fatal("%s: invalid OFPRAW_* name syntax" % raw)
278 if raw not in all_raws:
279 fatal("%s: not a declared OFPRAW_* name" % raw)
280 if "ofptype" in all_raws[raw]:
281 fatal("%s: already part of %s"
282 % (raw, all_raws[raw]["ofptype"]))
283 all_raws[raw]["ofptype"] = ofptype
284
64795a0d
BP
285 all_types.append(all_raws[raws[0]]["human_name"])
286
982697a4
BP
287 input_file.close()
288
289 if n_errors:
290 sys.exit(1)
291
292 output = []
293 output.append("/* Generated automatically; do not modify! "
294 "-*- buffer-read-only: t -*- */")
295 output.append("")
296
297 for raw in all_raws_order:
298 r = all_raws[raw]
299 output.append("static struct raw_instance %s_instances[] = {"
300 % raw.lower())
301 for hdrs in r['hdrs']:
302 output.append(" { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
303 % (hdrs + (raw,)))
304
305 output.append("};")
306
307 output.append("")
308
309 output.append("static struct raw_info raw_infos[] = {")
310 for raw in all_raws_order:
311 r = all_raws[raw]
312 if "ofptype" not in r:
313 error("%s: no defined OFPTYPE_" % raw)
314 continue
315 output.append(" {")
316 output.append(" %s_instances," % raw.lower())
317 output.append(" %d, %d," % (r["min_version"], r["max_version"]))
318 output.append("#line %s \"%s\"" % (r["line"], file_name))
319 output.append(" %s," % r["min_body"])
320 output.append("#line %s \"%s\"" % (r["line"], file_name))
321 output.append(" %s," % r["extra_multiple"])
322 output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
323 output.append(" %s," % r["ofptype"])
324 output.append(" \"%s\"," % r["human_name"])
325 output.append(" },")
326
327 if r['type'].endswith("ST"):
328 for hdrs in r['hdrs']:
329 op_hdrs = list(hdrs)
42dccab5 330 if hdrs[0] == VERSION["1.0"]:
982697a4
BP
331 if hdrs[1] == OFPT10_STATS_REQUEST:
332 op_hdrs[1] = OFPT10_STATS_REPLY
333 elif hdrs[1] == OFPT10_STATS_REPLY:
334 op_hdrs[1] = OFPT10_STATS_REQUEST
335 else:
336 assert False
337 else:
338 if hdrs[1] == OFPT11_STATS_REQUEST:
339 op_hdrs[1] = OFPT11_STATS_REPLY
340 elif hdrs[1] == OFPT11_STATS_REPLY:
341 op_hdrs[1] = OFPT11_STATS_REQUEST
342 else:
343 assert False
344 if tuple(op_hdrs) not in all_hdrs:
345 if r["human_name"].endswith("request"):
346 fatal("%s has no corresponding reply"
347 % r["human_name"])
348 else:
349 fatal("%s has no corresponding request"
350 % r["human_name"])
351 output.append("};")
352
64795a0d
BP
353 output.append("");
354 output.append("static const char *type_names[] = {");
355 for t in all_types:
356 output.append(" \"%s\"," % t)
357 output.append("};")
358
982697a4
BP
359 if n_errors:
360 sys.exit(1)
361
362 return output
363
364
365if __name__ == '__main__':
366 if '--help' in sys.argv:
367 usage()
368 elif len(sys.argv) != 3:
91148d4b 369 sys.stderr.write("exactly two non-option arguments required; "
982697a4
BP
370 "use --help for help\n")
371 sys.exit(1)
372 else:
373 global file_name
374 global input_file
375 global line_number
376 file_name = sys.argv[1]
377 input_file = open(file_name)
378 line_number = 0
379
380 for line in extract_ofp_msgs(sys.argv[2]):
d34a1cc0 381 print(line)
982697a4 382