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)}
37 line = input_file.readline()
40 fatal("unexpected end of input")
45 sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
53 argv0 = os.path.basename(sys.argv[0])
55 %(argv0)s, for extracting OpenFlow message types from header files
56 usage: %(argv0)s INPUT OUTPUT
57 where INPUT is the name of the input header file
58 and OUTPUT is the output file name.
59 Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
60 only controls #line directives in the output.\
61 ''' % {"argv0": argv0}
65 m = re.match(r'(.*) up to (.*)', s)
67 struct, member = m.groups()
68 return "offsetof(%s, %s)" % (struct, member)
70 return "sizeof(%s)" % s
72 def extract_ofp_msgs(output_file_name):
81 if re.match('enum ofpraw', line):
86 first_line_number = line_number
87 here = '%s:%d' % (file_name, line_number)
88 if (line.startswith('/*')
89 or line.startswith(' *')
93 elif re.match('}', line):
96 if not line.lstrip().startswith('/*'):
97 fatal("unexpected syntax between ofpraw types")
99 comment = line.lstrip()[2:].strip()
100 while not comment.endswith('*/'):
102 if line.startswith('/*') or not line or line.isspace():
103 fatal("unexpected syntax within error")
104 comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
105 comment = comment[:-2].rstrip()
107 m = re.match(r'([A-Z]+) ([-.+\d]+) \((\d+)\): ([^.]+)\.$', comment)
109 fatal("unexpected syntax between messages")
110 type_, versions, number, contents = m.groups()
114 m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
117 fatal("syntax error expecting OFPRAW_ enum")
118 vinfix, name = m.groups()
119 rawname = 'OFPRAW_%s%s_%s' % (type_, vinfix, name)
121 min_version, max_version = version_map[versions]
123 human_name = '%s_%s' % (type_, name)
124 if type_.endswith('ST'):
125 if rawname.endswith('_REQUEST'):
126 human_name = human_name[:-8] + " request"
127 elif rawname.endswith('_REPLY'):
128 human_name = human_name[:-6] + " reply"
130 fatal("%s messages are statistics but %s doesn't end "
131 "in _REQUEST or _REPLY" % (type_, rawname))
134 for version in range(min_version, max_version + 1):
136 if number == OFPT_VENDOR:
137 fatal("OFPT (%d) is used for vendor extensions"
139 elif (version == OFP10_VERSION
140 and (number == OFPT10_STATS_REQUEST
141 or number == OFPT10_STATS_REPLY)):
142 fatal("OFPT 1.0 (%d) is used for stats messages"
144 elif (version != OFP10_VERSION
145 and (number == OFPT11_STATS_REQUEST
146 or number == OFPT11_STATS_REPLY)):
147 fatal("OFPT 1.1+ (%d) is used for stats messages"
149 hdrs = (version, number, 0, 0, 0)
150 elif type_ == 'OFPST' and name.endswith('_REQUEST'):
151 if version == OFP10_VERSION:
152 hdrs = (version, OFPT10_STATS_REQUEST, number, 0, 0)
154 hdrs = (version, OFPT11_STATS_REQUEST, number, 0, 0)
155 elif type_ == 'OFPST' and name.endswith('_REPLY'):
156 if version == OFP10_VERSION:
157 hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
159 hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
161 hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
162 elif type_ == 'NXST' and name.endswith('_REQUEST'):
163 if version == OFP10_VERSION:
164 hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
165 NX_VENDOR_ID, number)
167 hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
168 NX_VENDOR_ID, number)
169 elif type_ == 'NXST' and name.endswith('_REPLY'):
170 if version == OFP10_VERSION:
171 hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
172 NX_VENDOR_ID, number)
174 hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
175 NX_VENDOR_ID, number)
177 fatal("type '%s' unknown" % type_)
180 error("Duplicate message definition for %s." % str(hdrs))
181 sys.stderr.write("%s: Here is the location "
182 "of the previous definition.\n"
184 all_hdrs[hdrs] = here
185 these_hdrs.append(hdrs)
188 if contents == 'void':
192 for c in [s.strip() for s in contents.split(",")]:
194 if extra_multiple == '0':
195 extra_multiple = make_sizeof(c[:-2])
197 error("Cannot have multiple [] elements")
199 min_body_elem.append(c)
202 min_body = " + ".join([make_sizeof(s)
203 for s in min_body_elem])
205 if extra_multiple == '0':
206 error("Must specify contents (use 'void' if empty)")
209 if rawname in all_raws:
210 fatal("%s: Duplicate name" % rawname)
212 all_raws[rawname] = {"hdrs": these_hdrs,
213 "min_version": min_version,
214 "max_version": max_version,
215 "min_body": min_body,
216 "extra_multiple": extra_multiple,
218 "human_name": human_name,
219 "line": first_line_number}
220 all_raws_order.append(rawname)
226 if re.match('enum ofptype', line):
231 if re.match(r'\s*/?\*', line) or line.isspace():
233 elif re.match('}', line):
236 if not re.match(r'\s*OFPTYPE_.*/\*', line):
237 fatal("unexpected syntax between OFPTYPE_ definitions")
239 syntax = line.strip()
240 while not syntax.endswith('*/'):
242 if not line.strip().startswith('*'):
243 fatal("unexpected syntax within OFPTYPE_ definition")
244 syntax += ' %s' % line.strip().lstrip('* \t')
245 syntax = syntax.strip()
247 m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
249 fatal("syntax error in OFPTYPE_ definition")
251 ofptype, raws_ = m.groups()
252 raws = [s.rstrip('.') for s in raws_.split()]
254 if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
255 fatal("%s: invalid OFPRAW_* name syntax" % raw)
256 if raw not in all_raws:
257 fatal("%s: not a declared OFPRAW_* name" % raw)
258 if "ofptype" in all_raws[raw]:
259 fatal("%s: already part of %s"
260 % (raw, all_raws[raw]["ofptype"]))
261 all_raws[raw]["ofptype"] = ofptype
269 output.append("/* Generated automatically; do not modify! "
270 "-*- buffer-read-only: t -*- */")
273 for raw in all_raws_order:
275 output.append("static struct raw_instance %s_instances[] = {"
277 for hdrs in r['hdrs']:
278 output.append(" { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
285 output.append("static struct raw_info raw_infos[] = {")
286 for raw in all_raws_order:
288 if "ofptype" not in r:
289 error("%s: no defined OFPTYPE_" % raw)
292 output.append(" %s_instances," % raw.lower())
293 output.append(" %d, %d," % (r["min_version"], r["max_version"]))
294 output.append("#line %s \"%s\"" % (r["line"], file_name))
295 output.append(" %s," % r["min_body"])
296 output.append("#line %s \"%s\"" % (r["line"], file_name))
297 output.append(" %s," % r["extra_multiple"])
298 output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
299 output.append(" %s," % r["ofptype"])
300 output.append(" \"%s\"," % r["human_name"])
303 if r['type'].endswith("ST"):
304 for hdrs in r['hdrs']:
306 if hdrs[0] == OFP10_VERSION:
307 if hdrs[1] == OFPT10_STATS_REQUEST:
308 op_hdrs[1] = OFPT10_STATS_REPLY
309 elif hdrs[1] == OFPT10_STATS_REPLY:
310 op_hdrs[1] = OFPT10_STATS_REQUEST
314 if hdrs[1] == OFPT11_STATS_REQUEST:
315 op_hdrs[1] = OFPT11_STATS_REPLY
316 elif hdrs[1] == OFPT11_STATS_REPLY:
317 op_hdrs[1] = OFPT11_STATS_REQUEST
320 if tuple(op_hdrs) not in all_hdrs:
321 if r["human_name"].endswith("request"):
322 fatal("%s has no corresponding reply"
325 fatal("%s has no corresponding request"
335 if __name__ == '__main__':
336 if '--help' in sys.argv:
338 elif len(sys.argv) != 3:
339 sys.stderr.write("exactly one non-option arguments required; "
340 "use --help for help\n")
346 file_name = sys.argv[1]
347 input_file = open(file_name)
350 for line in extract_ofp_msgs(sys.argv[2]):