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 "<all>": (0x01, 0xff)}
38 line = input_file.readline()
41 fatal("unexpected end of input")
46 sys.stderr.write("%s:%d: %s\n" % (file_name, line_number, msg))
54 argv0 = os.path.basename(sys.argv[0])
56 %(argv0)s, for extracting OpenFlow message types from header files
57 usage: %(argv0)s INPUT OUTPUT
58 where INPUT is the name of the input header file
59 and OUTPUT is the output file name.
60 Despite OUTPUT, the output is written to stdout, and the OUTPUT argument
61 only controls #line directives in the output.\
62 ''' % {"argv0": argv0}
66 m = re.match(r'(.*) up to (.*)', s)
68 struct, member = m.groups()
69 return "offsetof(%s, %s)" % (struct, member)
71 return "sizeof(%s)" % s
73 def extract_ofp_msgs(output_file_name):
82 if re.match('enum ofpraw', line):
87 first_line_number = line_number
88 here = '%s:%d' % (file_name, line_number)
89 if (line.startswith('/*')
90 or line.startswith(' *')
94 elif re.match('}', line):
97 if not line.lstrip().startswith('/*'):
98 fatal("unexpected syntax between ofpraw types")
100 comment = line.lstrip()[2:].strip()
101 while not comment.endswith('*/'):
103 if line.startswith('/*') or not line or line.isspace():
104 fatal("unexpected syntax within error")
105 comment += ' %s' % line.lstrip('* \t').rstrip(' \t\r\n')
106 comment = comment[:-2].rstrip()
108 m = re.match(r'([A-Z]+) ([-.+\d]+|<all>) \((\d+)\): ([^.]+)\.$', comment)
110 fatal("unexpected syntax between messages")
111 type_, versions, number, contents = m.groups()
115 m = re.match('\s+(?:OFPRAW_%s)(\d*)_([A-Z0-9_]+),?$' % type_,
118 fatal("syntax error expecting OFPRAW_ enum")
119 vinfix, name = m.groups()
120 rawname = 'OFPRAW_%s%s_%s' % (type_, vinfix, name)
122 min_version, max_version = version_map[versions]
124 human_name = '%s_%s' % (type_, name)
125 if type_.endswith('ST'):
126 if rawname.endswith('_REQUEST'):
127 human_name = human_name[:-8] + " request"
128 elif rawname.endswith('_REPLY'):
129 human_name = human_name[:-6] + " reply"
131 fatal("%s messages are statistics but %s doesn't end "
132 "in _REQUEST or _REPLY" % (type_, rawname))
135 for version in range(min_version, max_version + 1):
137 if number == OFPT_VENDOR:
138 fatal("OFPT (%d) is used for vendor extensions"
140 elif (version == OFP10_VERSION
141 and (number == OFPT10_STATS_REQUEST
142 or number == OFPT10_STATS_REPLY)):
143 fatal("OFPT 1.0 (%d) is used for stats messages"
145 elif (version != OFP10_VERSION
146 and (number == OFPT11_STATS_REQUEST
147 or number == OFPT11_STATS_REPLY)):
148 fatal("OFPT 1.1+ (%d) is used for stats messages"
150 hdrs = (version, number, 0, 0, 0)
151 elif type_ == 'OFPST' and name.endswith('_REQUEST'):
152 if version == OFP10_VERSION:
153 hdrs = (version, OFPT10_STATS_REQUEST, number, 0, 0)
155 hdrs = (version, OFPT11_STATS_REQUEST, number, 0, 0)
156 elif type_ == 'OFPST' and name.endswith('_REPLY'):
157 if version == OFP10_VERSION:
158 hdrs = (version, OFPT10_STATS_REPLY, number, 0, 0)
160 hdrs = (version, OFPT11_STATS_REPLY, number, 0, 0)
162 hdrs = (version, OFPT_VENDOR, 0, NX_VENDOR_ID, number)
163 elif type_ == 'NXST' and name.endswith('_REQUEST'):
164 if version == OFP10_VERSION:
165 hdrs = (version, OFPT10_STATS_REQUEST, OFPST_VENDOR,
166 NX_VENDOR_ID, number)
168 hdrs = (version, OFPT11_STATS_REQUEST, OFPST_VENDOR,
169 NX_VENDOR_ID, number)
170 elif type_ == 'NXST' and name.endswith('_REPLY'):
171 if version == OFP10_VERSION:
172 hdrs = (version, OFPT10_STATS_REPLY, OFPST_VENDOR,
173 NX_VENDOR_ID, number)
175 hdrs = (version, OFPT11_STATS_REPLY, OFPST_VENDOR,
176 NX_VENDOR_ID, number)
178 fatal("type '%s' unknown" % type_)
181 error("Duplicate message definition for %s." % str(hdrs))
182 sys.stderr.write("%s: Here is the location "
183 "of the previous definition.\n"
185 all_hdrs[hdrs] = here
186 these_hdrs.append(hdrs)
189 if contents == 'void':
193 for c in [s.strip() for s in contents.split(",")]:
195 if extra_multiple == '0':
196 extra_multiple = make_sizeof(c[:-2])
198 error("Cannot have multiple [] elements")
200 min_body_elem.append(c)
203 min_body = " + ".join([make_sizeof(s)
204 for s in min_body_elem])
206 if extra_multiple == '0':
207 error("Must specify contents (use 'void' if empty)")
210 if rawname in all_raws:
211 fatal("%s: Duplicate name" % rawname)
213 all_raws[rawname] = {"hdrs": these_hdrs,
214 "min_version": min_version,
215 "max_version": max_version,
216 "min_body": min_body,
217 "extra_multiple": extra_multiple,
219 "human_name": human_name,
220 "line": first_line_number}
221 all_raws_order.append(rawname)
227 if re.match('enum ofptype', line):
232 if re.match(r'\s*/?\*', line) or line.isspace():
234 elif re.match('}', line):
237 if not re.match(r'\s*OFPTYPE_.*/\*', line):
238 fatal("unexpected syntax between OFPTYPE_ definitions")
240 syntax = line.strip()
241 while not syntax.endswith('*/'):
243 if not line.strip().startswith('*'):
244 fatal("unexpected syntax within OFPTYPE_ definition")
245 syntax += ' %s' % line.strip().lstrip('* \t')
246 syntax = syntax.strip()
248 m = re.match(r'(OFPTYPE_[A-Z0-9_]+),\s*/\* (.*) \*/', syntax)
250 fatal("syntax error in OFPTYPE_ definition")
252 ofptype, raws_ = m.groups()
253 raws = [s.rstrip('.') for s in raws_.split()]
255 if not re.match('OFPRAW_[A-Z0-9_]+$', raw):
256 fatal("%s: invalid OFPRAW_* name syntax" % raw)
257 if raw not in all_raws:
258 fatal("%s: not a declared OFPRAW_* name" % raw)
259 if "ofptype" in all_raws[raw]:
260 fatal("%s: already part of %s"
261 % (raw, all_raws[raw]["ofptype"]))
262 all_raws[raw]["ofptype"] = ofptype
270 output.append("/* Generated automatically; do not modify! "
271 "-*- buffer-read-only: t -*- */")
274 for raw in all_raws_order:
276 output.append("static struct raw_instance %s_instances[] = {"
278 for hdrs in r['hdrs']:
279 output.append(" { {0, NULL}, {%d, %d, %d, 0x%x, %d}, %s, 0 },"
286 output.append("static struct raw_info raw_infos[] = {")
287 for raw in all_raws_order:
289 if "ofptype" not in r:
290 error("%s: no defined OFPTYPE_" % raw)
293 output.append(" %s_instances," % raw.lower())
294 output.append(" %d, %d," % (r["min_version"], r["max_version"]))
295 output.append("#line %s \"%s\"" % (r["line"], file_name))
296 output.append(" %s," % r["min_body"])
297 output.append("#line %s \"%s\"" % (r["line"], file_name))
298 output.append(" %s," % r["extra_multiple"])
299 output.append("#line %s \"%s\"" % (len(output) + 2, output_file_name))
300 output.append(" %s," % r["ofptype"])
301 output.append(" \"%s\"," % r["human_name"])
304 if r['type'].endswith("ST"):
305 for hdrs in r['hdrs']:
307 if hdrs[0] == OFP10_VERSION:
308 if hdrs[1] == OFPT10_STATS_REQUEST:
309 op_hdrs[1] = OFPT10_STATS_REPLY
310 elif hdrs[1] == OFPT10_STATS_REPLY:
311 op_hdrs[1] = OFPT10_STATS_REQUEST
315 if hdrs[1] == OFPT11_STATS_REQUEST:
316 op_hdrs[1] = OFPT11_STATS_REPLY
317 elif hdrs[1] == OFPT11_STATS_REPLY:
318 op_hdrs[1] = OFPT11_STATS_REQUEST
321 if tuple(op_hdrs) not in all_hdrs:
322 if r["human_name"].endswith("request"):
323 fatal("%s has no corresponding reply"
326 fatal("%s has no corresponding request"
336 if __name__ == '__main__':
337 if '--help' in sys.argv:
339 elif len(sys.argv) != 3:
340 sys.stderr.write("exactly one non-option arguments required; "
341 "use --help for help\n")
347 file_name = sys.argv[1]
348 input_file = open(file_name)
351 for line in extract_ofp_msgs(sys.argv[2]):