15 NX_VENDOR_ID = 0x00002320
18 OFPT10_STATS_REQUEST = 16
19 OFPT10_STATS_REPLY = 17
20 OFPT11_STATS_REQUEST = 18
21 OFPT11_STATS_REPLY = 19
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 "1.1-1.3": (OFP11_VERSION, OFP13_VERSION),
38 "<all>": (0x01, 0xff)}
43 line = input_file.readline()
46 fatal("unexpected end of input")
51 sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
59 argv0 = os.path.basename(sys.argv[0])
61 %(argv0)s, for extracting OpenFlow message types from header files
62 usage: %(argv0)s INPUT OUTPUT
63 where INPUT is the name of the input header file
64 and OUTPUT is the output file name.
65 Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
66 only controls #line directives in the output.\
67 ''' % {"argv0": argv0}
71 m = re.match(r'(.*) up to (.*)', s)
73 struct, member = m.groups()
74 return "offsetof(%s, %s)" % (struct, member)
76 return "sizeof(%s)" % s
78 def extract_ofp_msgs(output_file_name):
87 if re.match('enum ofpraw', line):
92 first_line_number = line_number
93 here = '%s:%d' % (file_name, line_number)
94 if (line.startswith('/*')
95 or line.startswith(' *')
99 elif re.match('}', line):
102 if not line.lstrip().startswith('/*'):
103 fatal("unexpected syntax between ofpraw types")
105 comment = line.lstrip()[2:].strip()
106 while not comment.endswith('*/'):
108 if line.startswith('/*') or not line or line.isspace():
109 fatal("unexpected syntax within error")
110 comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
111 comment = comment[:-2].rstrip()
113 m = re.match(r'([A-Z]+) ([-.+\d]+|<all>) \((\d+)\): ([^.]+)\.$', comment)
115 fatal("unexpected syntax between messages")
116 type_, versions, number, contents = m.groups()
120 m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
123 fatal("syntax error expecting OFPRAW_ enum")
124 vinfix, name = m.groups()
125 rawname = 'OFPRAW_%s%s_%s' % (type_, vinfix, name)
127 min_version, max_version = version_map[versions]
129 human_name = '%s_%s' % (type_, name)
130 if type_.endswith('ST'):
131 if rawname.endswith('_REQUEST'):
132 human_name = human_name[:-8] + " request"
133 elif rawname.endswith('_REPLY'):
134 human_name = human_name[:-6] + " reply"
136 fatal("%s messages are statistics but %s doesn't end "
137 "in _REQUEST or _REPLY" % (type_, rawname))
140 for version in range(min_version, max_version + 1):
142 if number == OFPT_VENDOR:
143 fatal("OFPT (%d) is used for vendor extensions"
145 elif (version == OFP10_VERSION
146 and (number == OFPT10_STATS_REQUEST
147 or number == OFPT10_STATS_REPLY)):
148 fatal("OFPT 1.0 (%d) is used for stats messages"
150 elif (version != OFP10_VERSION
151 and (number == OFPT11_STATS_REQUEST
152 or number == OFPT11_STATS_REPLY)):
153 fatal("OFPT 1.1+ (%d) is used for stats messages"
155 hdrs = (version, number, 0, 0, 0)
156 elif type_ == 'OFPST' and name.endswith('_REQUEST'):
157 if version == OFP10_VERSION:
158 hdrs = (version, OFPT10_STATS_REQUEST, number, 0, 0)
160 hdrs = (version, OFPT11_STATS_REQUEST, number, 0, 0)
161 elif type_ == 'OFPST' and name.endswith('_REPLY'):
162 if version == OFP10_VERSION:
163 hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
165 hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
167 hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
168 elif type_ == 'NXST' and name.endswith('_REQUEST'):
169 if version == OFP10_VERSION:
170 hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
171 NX_VENDOR_ID, number)
173 hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
174 NX_VENDOR_ID, number)
175 elif type_ == 'NXST' and name.endswith('_REPLY'):
176 if version == OFP10_VERSION:
177 hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
178 NX_VENDOR_ID, number)
180 hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
181 NX_VENDOR_ID, number)
183 fatal("type '%s' unknown" % type_)
186 error("Duplicate message definition for %s." % str(hdrs))
187 sys.stderr.write("%s: Here is the location "
188 "of the previous definition.\n"
190 all_hdrs[hdrs] = here
191 these_hdrs.append(hdrs)
194 if contents == 'void':
198 for c in [s.strip() for s in contents.split(",")]:
200 if extra_multiple == '0':
201 extra_multiple = make_sizeof(c[:-2])
203 error("Cannot have multiple [] elements")
205 min_body_elem.append(c)
208 min_body = " + ".join([make_sizeof(s)
209 for s in min_body_elem])
211 if extra_multiple == '0':
212 error("Must specify contents (use 'void' if empty)")
215 if rawname in all_raws:
216 fatal("%s: Duplicate name" % rawname)
218 all_raws[rawname] = {"hdrs": these_hdrs,
219 "min_version": min_version,
220 "max_version": max_version,
221 "min_body": min_body,
222 "extra_multiple": extra_multiple,
224 "human_name": human_name,
225 "line": first_line_number}
226 all_raws_order.append(rawname)
232 if re.match('enum ofptype', line):
237 if re.match(r'\s*/?\*', line) or line.isspace():
239 elif re.match('}', line):
242 if not re.match(r'\s*OFPTYPE_.*/\*', line):
243 fatal("unexpected syntax between OFPTYPE_ definitions")
245 syntax = line.strip()
246 while not syntax.endswith('*/'):
248 if not line.strip().startswith('*'):
249 fatal("unexpected syntax within OFPTYPE_ definition")
250 syntax += ' %s' % line.strip().lstrip('* \t')
251 syntax = syntax.strip()
253 m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
255 fatal("syntax error in OFPTYPE_ definition")
257 ofptype, raws_ = m.groups()
258 raws = [s.rstrip('.') for s in raws_.split()]
260 if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
261 fatal("%s: invalid OFPRAW_* name syntax" % raw)
262 if raw not in all_raws:
263 fatal("%s: not a declared OFPRAW_* name" % raw)
264 if "ofptype" in all_raws[raw]:
265 fatal("%s: already part of %s"
266 % (raw, all_raws[raw]["ofptype"]))
267 all_raws[raw]["ofptype"] = ofptype
275 output.append("/* Generated automatically; do not modify! "
276 "-*- buffer-read-only: t -*- */")
279 for raw in all_raws_order:
281 output.append("static struct raw_instance %s_instances[] = {"
283 for hdrs in r['hdrs']:
284 output.append(" { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
291 output.append("static struct raw_info raw_infos[] = {")
292 for raw in all_raws_order:
294 if "ofptype" not in r:
295 error("%s: no defined OFPTYPE_" % raw)
298 output.append(" %s_instances," % raw.lower())
299 output.append(" %d, %d," % (r["min_version"], r["max_version"]))
300 output.append("#line %s \"%s\"" % (r["line"], file_name))
301 output.append(" %s," % r["min_body"])
302 output.append("#line %s \"%s\"" % (r["line"], file_name))
303 output.append(" %s," % r["extra_multiple"])
304 output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
305 output.append(" %s," % r["ofptype"])
306 output.append(" \"%s\"," % r["human_name"])
309 if r['type'].endswith("ST"):
310 for hdrs in r['hdrs']:
312 if hdrs[0] == OFP10_VERSION:
313 if hdrs[1] == OFPT10_STATS_REQUEST:
314 op_hdrs[1] = OFPT10_STATS_REPLY
315 elif hdrs[1] == OFPT10_STATS_REPLY:
316 op_hdrs[1] = OFPT10_STATS_REQUEST
320 if hdrs[1] == OFPT11_STATS_REQUEST:
321 op_hdrs[1] = OFPT11_STATS_REPLY
322 elif hdrs[1] == OFPT11_STATS_REPLY:
323 op_hdrs[1] = OFPT11_STATS_REQUEST
326 if tuple(op_hdrs) not in all_hdrs:
327 if r["human_name"].endswith("request"):
328 fatal("%s has no corresponding reply"
331 fatal("%s has no corresponding request"
341 if __name__ == '__main__':
342 if '--help' in sys.argv:
344 elif len(sys.argv) != 3:
345 sys.stderr.write("exactly one non-option arguments required; "
346 "use --help for help\n")
352 file_name = sys.argv[1]
353 input_file = open(file_name)
356 for line in extract_ofp_msgs(sys.argv[2]):