14 NX_VENDOR_ID = 0x00002320
17 OFPT10_STATS_REQUEST = 16
18 OFPT10_STATS_REPLY = 17
19 OFPT11_STATS_REQUEST = 18
20 OFPT11_STATS_REPLY = 19
23 version_map = {"1.0": (OFP10_VERSION, OFP10_VERSION),
24 "1.1": (OFP11_VERSION, OFP11_VERSION),
25 "1.2": (OFP12_VERSION, OFP12_VERSION),
26 "1.3": (OFP13_VERSION, OFP13_VERSION),
27 "1.0+": (OFP10_VERSION, OFP13_VERSION),
28 "1.1+": (OFP11_VERSION, OFP13_VERSION),
29 "1.2+": (OFP12_VERSION, OFP13_VERSION),
30 "1.3+": (OFP13_VERSION, OFP13_VERSION),
31 "1.0-1.1": (OFP10_VERSION, OFP11_VERSION),
32 "1.0-1.2": (OFP10_VERSION, OFP12_VERSION),
33 "1.1-1.2": (OFP11_VERSION, OFP12_VERSION),
34 "<all>": (0x01, 0xff)}
39 line = input_file.readline()
42 fatal("unexpected end of input")
47 sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
55 argv0 = os.path.basename(sys.argv[0])
57 %(argv0)s, for extracting OpenFlow message types from header files
58 usage: %(argv0)s INPUT OUTPUT
59 where INPUT is the name of the input header file
60 and OUTPUT is the output file name.
61 Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
62 only controls #line directives in the output.\
63 ''' % {"argv0": argv0}
67 m = re.match(r'(.*) up to (.*)', s)
69 struct, member = m.groups()
70 return "offsetof(%s, %s)" % (struct, member)
72 return "sizeof(%s)" % s
74 def extract_ofp_msgs(output_file_name):
83 if re.match('enum ofpraw', line):
88 first_line_number = line_number
89 here = '%s:%d' % (file_name, line_number)
90 if (line.startswith('/*')
91 or line.startswith(' *')
95 elif re.match('}', line):
98 if not line.lstrip().startswith('/*'):
99 fatal("unexpected syntax between ofpraw types")
101 comment = line.lstrip()[2:].strip()
102 while not comment.endswith('*/'):
104 if line.startswith('/*') or not line or line.isspace():
105 fatal("unexpected syntax within error")
106 comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
107 comment = comment[:-2].rstrip()
109 m = re.match(r'([A-Z]+) ([-.+\d]+|<all>) \((\d+)\): ([^.]+)\.$', comment)
111 fatal("unexpected syntax between messages")
112 type_, versions, number, contents = m.groups()
116 m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
119 fatal("syntax error expecting OFPRAW_ enum")
120 vinfix, name = m.groups()
121 rawname = 'OFPRAW_%s%s_%s' % (type_, vinfix, name)
123 min_version, max_version = version_map[versions]
125 human_name = '%s_%s' % (type_, name)
126 if type_.endswith('ST'):
127 if rawname.endswith('_REQUEST'):
128 human_name = human_name[:-8] + " request"
129 elif rawname.endswith('_REPLY'):
130 human_name = human_name[:-6] + " reply"
132 fatal("%s messages are statistics but %s doesn't end "
133 "in _REQUEST or _REPLY" % (type_, rawname))
136 for version in range(min_version, max_version + 1):
138 if number == OFPT_VENDOR:
139 fatal("OFPT (%d) is used for vendor extensions"
141 elif (version == OFP10_VERSION
142 and (number == OFPT10_STATS_REQUEST
143 or number == OFPT10_STATS_REPLY)):
144 fatal("OFPT 1.0 (%d) is used for stats messages"
146 elif (version != OFP10_VERSION
147 and (number == OFPT11_STATS_REQUEST
148 or number == OFPT11_STATS_REPLY)):
149 fatal("OFPT 1.1+ (%d) is used for stats messages"
151 hdrs = (version, number, 0, 0, 0)
152 elif type_ == 'OFPST' and name.endswith('_REQUEST'):
153 if version == OFP10_VERSION:
154 hdrs = (version, OFPT10_STATS_REQUEST, number, 0, 0)
156 hdrs = (version, OFPT11_STATS_REQUEST, number, 0, 0)
157 elif type_ == 'OFPST' and name.endswith('_REPLY'):
158 if version == OFP10_VERSION:
159 hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
161 hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
163 hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
164 elif type_ == 'NXST' and name.endswith('_REQUEST'):
165 if version == OFP10_VERSION:
166 hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
167 NX_VENDOR_ID, number)
169 hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
170 NX_VENDOR_ID, number)
171 elif type_ == 'NXST' and name.endswith('_REPLY'):
172 if version == OFP10_VERSION:
173 hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
174 NX_VENDOR_ID, number)
176 hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
177 NX_VENDOR_ID, number)
179 fatal("type '%s' unknown" % type_)
182 error("Duplicate message definition for %s." % str(hdrs))
183 sys.stderr.write("%s: Here is the location "
184 "of the previous definition.\n"
186 all_hdrs[hdrs] = here
187 these_hdrs.append(hdrs)
190 if contents == 'void':
194 for c in [s.strip() for s in contents.split(",")]:
196 if extra_multiple == '0':
197 extra_multiple = make_sizeof(c[:-2])
199 error("Cannot have multiple [] elements")
201 min_body_elem.append(c)
204 min_body = " + ".join([make_sizeof(s)
205 for s in min_body_elem])
207 if extra_multiple == '0':
208 error("Must specify contents (use 'void' if empty)")
211 if rawname in all_raws:
212 fatal("%s: Duplicate name" % rawname)
214 all_raws[rawname] = {"hdrs": these_hdrs,
215 "min_version": min_version,
216 "max_version": max_version,
217 "min_body": min_body,
218 "extra_multiple": extra_multiple,
220 "human_name": human_name,
221 "line": first_line_number}
222 all_raws_order.append(rawname)
228 if re.match('enum ofptype', line):
233 if re.match(r'\s*/?\*', line) or line.isspace():
235 elif re.match('}', line):
238 if not re.match(r'\s*OFPTYPE_.*/\*', line):
239 fatal("unexpected syntax between OFPTYPE_ definitions")
241 syntax = line.strip()
242 while not syntax.endswith('*/'):
244 if not line.strip().startswith('*'):
245 fatal("unexpected syntax within OFPTYPE_ definition")
246 syntax += ' %s' % line.strip().lstrip('* \t')
247 syntax = syntax.strip()
249 m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
251 fatal("syntax error in OFPTYPE_ definition")
253 ofptype, raws_ = m.groups()
254 raws = [s.rstrip('.') for s in raws_.split()]
256 if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
257 fatal("%s: invalid OFPRAW_* name syntax" % raw)
258 if raw not in all_raws:
259 fatal("%s: not a declared OFPRAW_* name" % raw)
260 if "ofptype" in all_raws[raw]:
261 fatal("%s: already part of %s"
262 % (raw, all_raws[raw]["ofptype"]))
263 all_raws[raw]["ofptype"] = ofptype
271 output.append("/* Generated automatically; do not modify! "
272 "-*- buffer-read-only: t -*- */")
275 for raw in all_raws_order:
277 output.append("static struct raw_instance %s_instances[] = {"
279 for hdrs in r['hdrs']:
280 output.append(" { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
287 output.append("static struct raw_info raw_infos[] = {")
288 for raw in all_raws_order:
290 if "ofptype" not in r:
291 error("%s: no defined OFPTYPE_" % raw)
294 output.append(" %s_instances," % raw.lower())
295 output.append(" %d, %d," % (r["min_version"], r["max_version"]))
296 output.append("#line %s \"%s\"" % (r["line"], file_name))
297 output.append(" %s," % r["min_body"])
298 output.append("#line %s \"%s\"" % (r["line"], file_name))
299 output.append(" %s," % r["extra_multiple"])
300 output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
301 output.append(" %s," % r["ofptype"])
302 output.append(" \"%s\"," % r["human_name"])
305 if r['type'].endswith("ST"):
306 for hdrs in r['hdrs']:
308 if hdrs[0] == OFP10_VERSION:
309 if hdrs[1] == OFPT10_STATS_REQUEST:
310 op_hdrs[1] = OFPT10_STATS_REPLY
311 elif hdrs[1] == OFPT10_STATS_REPLY:
312 op_hdrs[1] = OFPT10_STATS_REQUEST
316 if hdrs[1] == OFPT11_STATS_REQUEST:
317 op_hdrs[1] = OFPT11_STATS_REPLY
318 elif hdrs[1] == OFPT11_STATS_REPLY:
319 op_hdrs[1] = OFPT11_STATS_REQUEST
322 if tuple(op_hdrs) not in all_hdrs:
323 if r["human_name"].endswith("request"):
324 fatal("%s has no corresponding reply"
327 fatal("%s has no corresponding request"
337 if __name__ == '__main__':
338 if '--help' in sys.argv:
340 elif len(sys.argv) != 3:
341 sys.stderr.write("exactly one non-option arguments required; "
342 "use --help for help\n")
348 file_name = sys.argv[1]
349 input_file = open(file_name)
352 for line in extract_ofp_msgs(sys.argv[2]):