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)}
36 line = input_file.readline()
39 fatal("unexpected end of input")
44 sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
52 argv0 = os.path.basename(sys.argv[0])
54 %(argv0)s, for extracting OpenFlow message types from header files
55 usage: %(argv0)s INPUT OUTPUT
56 where INPUT is the name of the input header file
57 and OUTPUT is the output file name.
58 Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
59 only controls #line directives in the output.\
60 ''' % {"argv0": argv0}
64 m = re.match(r'(.*) up to (.*)', s)
66 struct, member = m.groups()
67 return "offsetof(%s, %s)" % (struct, member)
69 return "sizeof(%s)" % s
71 def extract_ofp_msgs(output_file_name):
80 if re.match('enum ofpraw', line):
85 first_line_number = line_number
86 here = '%s:%d' % (file_name, line_number)
87 if (line.startswith('/*')
88 or line.startswith(' *')
92 elif re.match('}', line):
95 if not line.lstrip().startswith('/*'):
96 fatal("unexpected syntax between ofpraw types")
98 comment = line.lstrip()[2:].strip()
99 while not comment.endswith('*/'):
101 if line.startswith('/*') or not line or line.isspace():
102 fatal("unexpected syntax within error")
103 comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
104 comment = comment[:-2].rstrip()
106 m = re.match(r'([A-Z]+) ([-.+\d]+) \((\d+)\): ([^.]+)\.$', comment)
108 fatal("unexpected syntax between messages")
109 type_, versions, number, contents = m.groups()
113 m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
116 fatal("syntax error expecting OFPRAW_ enum")
117 vinfix, name = m.groups()
118 rawname = 'OFPRAW_%s%s_%s' % (type_, vinfix, name)
120 min_version, max_version = version_map[versions]
122 human_name = '%s_%s' % (type_, name)
123 if type_.endswith('ST'):
124 if rawname.endswith('_REQUEST'):
125 human_name = human_name[:-8] + " request"
126 elif rawname.endswith('_REPLY'):
127 human_name = human_name[:-6] + " reply"
129 fatal("%s messages are statistics but %s doesn't end "
130 "in _REQUEST or _REPLY" % (type_, rawname))
133 for version in range(min_version, max_version + 1):
135 if number == OFPT_VENDOR:
136 fatal("OFPT (%d) is used for vendor extensions"
138 elif (version == OFP10_VERSION
139 and (number == OFPT10_STATS_REQUEST
140 or number == OFPT10_STATS_REPLY)):
141 fatal("OFPT 1.0 (%d) is used for stats messages"
143 elif (version != OFP10_VERSION
144 and (number == OFPT11_STATS_REQUEST
145 or number == OFPT11_STATS_REPLY)):
146 fatal("OFPT 1.1+ (%d) is used for stats messages"
148 hdrs = (version, number, 0, 0, 0)
149 elif type_ == 'OFPST' and name.endswith('_REQUEST'):
150 if version == OFP10_VERSION:
151 hdrs = (version, OFPT10_STATS_REQUEST, number, 0, 0)
153 hdrs = (version, OFPT11_STATS_REQUEST, number, 0, 0)
154 elif type_ == 'OFPST' and name.endswith('_REPLY'):
155 if version == OFP10_VERSION:
156 hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
158 hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
160 hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
161 elif type_ == 'NXST' and name.endswith('_REQUEST'):
162 if version == OFP10_VERSION:
163 hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
164 NX_VENDOR_ID, number)
166 hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
167 NX_VENDOR_ID, number)
168 elif type_ == 'NXST' and name.endswith('_REPLY'):
169 if version == OFP10_VERSION:
170 hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
171 NX_VENDOR_ID, number)
173 hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
174 NX_VENDOR_ID, number)
176 fatal("type '%s' unknown" % type_)
179 error("Duplicate message definition for %s." % str(hdrs))
180 sys.stderr.write("%s: Here is the location "
181 "of the previous definition.\n"
183 all_hdrs[hdrs] = here
184 these_hdrs.append(hdrs)
187 if contents == 'void':
191 for c in [s.strip() for s in contents.split(",")]:
193 if extra_multiple == '0':
194 extra_multiple = make_sizeof(c[:-2])
196 error("Cannot have multiple [] elements")
198 min_body_elem.append(c)
201 min_body = " + ".join([make_sizeof(s)
202 for s in min_body_elem])
204 if extra_multiple == '0':
205 error("Must specify contents (use 'void' if empty)")
208 if rawname in all_raws:
209 fatal("%s: Duplicate name" % rawname)
211 all_raws[rawname] = {"hdrs": these_hdrs,
212 "min_version": min_version,
213 "max_version": max_version,
214 "min_body": min_body,
215 "extra_multiple": extra_multiple,
217 "human_name": human_name,
218 "line": first_line_number}
219 all_raws_order.append(rawname)
225 if re.match('enum ofptype', line):
230 if re.match(r'\s*/?\*', line) or line.isspace():
232 elif re.match('}', line):
235 if not re.match(r'\s*OFPTYPE_.*/\*', line):
236 fatal("unexpected syntax between OFPTYPE_ definitions")
238 syntax = line.strip()
239 while not syntax.endswith('*/'):
241 if not line.strip().startswith('*'):
242 fatal("unexpected syntax within OFPTYPE_ definition")
243 syntax += ' %s' % line.strip().lstrip('* \t')
244 syntax = syntax.strip()
246 m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
248 fatal("syntax error in OFPTYPE_ definition")
250 ofptype, raws_ = m.groups()
251 raws = [s.rstrip('.') for s in raws_.split()]
253 if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
254 fatal("%s: invalid OFPRAW_* name syntax" % raw)
255 if raw not in all_raws:
256 fatal("%s: not a declared OFPRAW_* name" % raw)
257 if "ofptype" in all_raws[raw]:
258 fatal("%s: already part of %s"
259 % (raw, all_raws[raw]["ofptype"]))
260 all_raws[raw]["ofptype"] = ofptype
268 output.append("/* Generated automatically; do not modify! "
269 "-*- buffer-read-only: t -*- */")
272 for raw in all_raws_order:
274 output.append("static struct raw_instance %s_instances[] = {"
276 for hdrs in r['hdrs']:
277 output.append(" { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
284 output.append("static struct raw_info raw_infos[] = {")
285 for raw in all_raws_order:
287 if "ofptype" not in r:
288 error("%s: no defined OFPTYPE_" % raw)
291 output.append(" %s_instances," % raw.lower())
292 output.append(" %d, %d," % (r["min_version"], r["max_version"]))
293 output.append("#line %s \"%s\"" % (r["line"], file_name))
294 output.append(" %s," % r["min_body"])
295 output.append("#line %s \"%s\"" % (r["line"], file_name))
296 output.append(" %s," % r["extra_multiple"])
297 output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
298 output.append(" %s," % r["ofptype"])
299 output.append(" \"%s\"," % r["human_name"])
302 if r['type'].endswith("ST"):
303 for hdrs in r['hdrs']:
305 if hdrs[0] == OFP10_VERSION:
306 if hdrs[1] == OFPT10_STATS_REQUEST:
307 op_hdrs[1] = OFPT10_STATS_REPLY
308 elif hdrs[1] == OFPT10_STATS_REPLY:
309 op_hdrs[1] = OFPT10_STATS_REQUEST
313 if hdrs[1] == OFPT11_STATS_REQUEST:
314 op_hdrs[1] = OFPT11_STATS_REPLY
315 elif hdrs[1] == OFPT11_STATS_REPLY:
316 op_hdrs[1] = OFPT11_STATS_REQUEST
319 if tuple(op_hdrs) not in all_hdrs:
320 if r["human_name"].endswith("request"):
321 fatal("%s has no corresponding reply"
324 fatal("%s has no corresponding request"
334 if __name__ == '__main__':
335 if '--help' in sys.argv:
337 elif len(sys.argv) != 3:
338 sys.stderr.write("exactly one non-option arguments required; "
339 "use --help for help\n")
345 file_name = sys.argv[1]
346 input_file = open(file_name)
349 for line in extract_ofp_msgs(sys.argv[2]):