]>
git.proxmox.com Git - mirror_ovs.git/blob - build-aux/extract-ofp-errors
9 # Map from OpenFlow version number to version ID used in ofp_header.
10 version_map
= {"1.0": 0x01,
16 version_reverse_map
= dict((v
, k
) for (k
, v
) in version_map
.iteritems())
20 idRe
= "[a-zA-Z_][a-zA-Z_0-9]*"
21 tokenRe
= "#?" + idRe
+ "|[0-9]+|."
30 inputFile
= open(fileName
)
37 line
= inputFile
.readline()
43 fatal("unexpected end of input")
53 if line
.startswith("/*"):
57 commentEnd
= line
.find("*/")
62 line
= line
[commentEnd
+ 2:]
64 match
= re
.match(tokenRe
, line
)
65 token
= match
.group(0)
66 line
= line
[len(token
):]
67 if token
.startswith('#'):
69 elif token
in macros
and not inDirective
:
70 line
= macros
[token
] + line
79 line
= inputFile
.readline()
81 while line
.endswith("\\\n"):
82 line
= line
[:-2] + inputFile
.readline()
86 fatal("unexpected end of input")
93 sys
.stderr
.write("%s:%d: %s\n" % (fileName
, lineNumber
, msg
))
106 return re
.match(idRe
+ "$", s
) != None
110 fatal("identifier expected")
113 if not re
.match('[0-9]+$', token
):
114 fatal("integer expected")
125 fatal("%s expected" % t
)
127 def parseTaggedName():
128 assert token
in ('struct', 'union')
132 name
= "%s %s" % (name
, token
)
136 def print_enum(tag
, constants
, storage_class
):
138 %(storage_class)sconst char *
139 %(tag)s_to_string(uint16_t value)
143 "bufferlen": len(tag
) + 32,
144 "storage_class": storage_class
})
145 for constant
in constants
:
146 print (" case %s: return \"%s\";" % (constant
, constant
))
154 argv0
= os
.path
.basename(sys
.argv
[0])
156 %(argv0)s, for extracting OpenFlow error codes from header files
157 usage: %(argv0)s ERROR_HEADER VENDOR_HEADER
159 This program reads VENDOR_HEADER to obtain OpenFlow vendor (aka
160 experimenter IDs), then ERROR_HEADER to obtain OpenFlow error number.
161 It outputs a C source file for translating OpenFlow error codes into
164 ERROR_HEADER should point to lib/ofp-errors.h.
165 VENDOR_HEADER should point to include/openflow/openflow-common.h.
166 The output is suitable for use as lib/ofp-errors.inc.\
167 ''' % {"argv0": argv0
})
170 def extract_vendor_ids(fn
):
177 m
= re
.match(r
'#define\s+([A-Z0-9_]+)_VENDOR_ID\s+(0x[0-9a-fA-F]+|[0-9]+)', line
)
182 id_
= int(m
.group(2), 0)
184 if name
in vendor_map
:
185 error("%s: duplicate definition of vendor" % name
)
186 sys
.stderr
.write("%s: Here is the location of the previous "
187 "definition.\n" % vendor_loc
[name
])
190 vendor_map
[name
] = id_
191 vendor_loc
[name
] = "%s:%d" % (fileName
, lineNumber
)
194 fatal("%s: no vendor definitions found" % fn
)
198 vendor_reverse_map
= {}
199 for name
, id_
in vendor_map
.items():
200 if id_
in vendor_reverse_map
:
201 fatal("%s: duplicate vendor id for vendors %s and %s"
202 % (id_
, vendor_reverse_map
[id_
], name
))
203 vendor_reverse_map
[id_
] = name
205 def extract_ofp_errors(fn
):
212 for domain_name
in version_map
.values():
213 domain
[domain_name
] = {}
214 reverse
[domain_name
] = {}
223 if re
.match('enum ofperr', line
):
228 if line
.startswith('/*') or not line
or line
.isspace():
230 elif re
.match('}', line
):
233 if not line
.lstrip().startswith('/*'):
234 fatal("unexpected syntax between errors")
236 comment
= line
.lstrip()[2:].strip()
237 while not comment
.endswith('*/'):
239 if line
.startswith('/*') or not line
or line
.isspace():
240 fatal("unexpected syntax within error")
241 comment
+= ' %s' % line
.lstrip('* \t').rstrip(' \t\r\n')
242 comment
= comment
[:-2].rstrip()
244 m
= re
.match('Expected: (.*)\.$', comment
)
246 expected_errors
[m
.group(1)] = (fileName
, lineNumber
)
249 m
= re
.match('((?:.(?!\. ))+.)\. (.*)$', comment
)
251 fatal("unexpected syntax between errors")
253 dsts
, comment
= m
.groups()
256 m
= re
.match('\s+(?:OFPERR_([A-Z0-9_]+))(\s*=\s*OFPERR_OFS)?,',
259 fatal("syntax error expecting enum value")
263 fatal("%s specified twice" % enum
)
265 comments
.append(re
.sub('\[[^]]*\]', '', comment
))
268 for dst
in dsts
.split(', '):
269 m
= re
.match(r
'([A-Z]+)([0-9.]+)(\+|-[0-9.]+)?\((\d+)(?:,(\d+))?\)$', dst
)
271 fatal("%r: syntax error in destination" % dst
)
272 vendor_name
= m
.group(1)
273 version1_name
= m
.group(2)
274 version2_name
= m
.group(3)
275 type_
= int(m
.group(4))
277 code
= int(m
.group(5))
281 if vendor_name
not in vendor_map
:
282 fatal("%s: unknown vendor" % vendor_name
)
283 vendor
= vendor_map
[vendor_name
]
285 if version1_name
not in version_map
:
286 fatal("%s: unknown OpenFlow version" % version1_name
)
287 v1
= version_map
[version1_name
]
289 if version2_name
is None:
291 elif version2_name
== "+":
292 v2
= max(version_map
.values())
293 elif version2_name
[1:] not in version_map
:
294 fatal("%s: unknown OpenFlow version" % version2_name
[1:])
296 v2
= version_map
[version2_name
[1:]]
299 fatal("%s%s: %s precedes %s"
300 % (version1_name
, version2_name
,
301 version2_name
, version1_name
))
303 if vendor
== vendor_map
['NX']:
304 if v1
>= version_map
['1.2'] or v2
>= version_map
['1.2']:
306 fatal("%s: NX1.2+ domains do not have codes" % dst
)
308 elif vendor
!= vendor_map
['OF']:
310 fatal("%s: %s domains do not have codes" % vendor_name
)
312 for version
in range(v1
, v2
+ 1):
313 domain
[version
].setdefault(vendor
, {})
314 domain
[version
][vendor
].setdefault(type_
, {})
315 if code
in domain
[version
][vendor
][type_
]:
316 msg
= "%#x,%d,%d in OF%s means both %s and %s" % (
317 vendor
, type_
, code
, version_reverse_map
[version
],
318 domain
[version
][vendor
][type_
][code
][0], enum
)
319 if msg
in expected_errors
:
320 del expected_errors
[msg
]
322 error("%s: %s." % (dst
, msg
))
323 sys
.stderr
.write("%s:%d: %s: Here is the location "
324 "of the previous definition.\n"
325 % (domain
[version
][vendor
][type_
][code
][1],
326 domain
[version
][vendor
][type_
][code
][2],
329 domain
[version
][vendor
][type_
][code
] = (enum
, fileName
,
332 assert enum
not in reverse
[version
]
333 reverse
[version
][enum
] = (vendor
, type_
, code
)
337 for fn
, ln
in expected_errors
.values():
338 sys
.stderr
.write("%s:%d: expected duplicate not used.\n" % (fn
, ln
))
345 /* Generated automatically; do not modify! -*- buffer-read-only: t -*- */
347 #define OFPERR_N_ERRORS %d
349 struct ofperr_domain {
352 enum ofperr (*decode)(uint32_t vendor, uint16_t type, uint16_t code);
353 struct triplet errors[OFPERR_N_ERRORS];
356 static const char *error_names[OFPERR_N_ERRORS] = {
360 static const char *error_comments[OFPERR_N_ERRORS] = {
364 '\n'.join(' "%s",' % name
for name
in names
),
365 '\n'.join(' "%s",' % re
.sub(r
'(["\\])', r
'\\\1', comment
)
366 for comment
in comments
)))
368 def output_domain(map, name
, description
, version
):
371 %s_decode(uint32_t vendor, uint16_t type, uint16_t code)
373 switch (((uint64_t) vendor << 32) | (type << 16) | code) {""" % name
)
378 vendor
, type_
, code
= map[enum
]
381 value
= (vendor
<< 32) |
(type_
<< 16) | code
386 vendor_s
= "(%#xULL << 32) | " % vendor
389 print (" case %s(%d << 16) | %d:" % (vendor_s
, type_
, code
))
390 print (" return OFPERR_%s;" % enum
)
398 static const struct ofperr_domain %s = {
402 {""" % (name
, description
, version
, name
))
405 vendor
, type_
, code
= map[enum
]
408 print " { %#8x, %2d, %3d }, /* %s */" % (vendor
, type_
, code
, enum
)
410 print (" { -1, -1, -1 }, /* %s */" % enum
)
415 for version_name
, id_
in version_map
.items():
416 var
= 'ofperr_of' + re
.sub('[^A-Za-z0-9_]', '', version_name
)
417 description
= "OpenFlow %s" % version_name
418 output_domain(reverse
[id_
], var
, description
, id_
)
420 if __name__
== '__main__':
421 if '--help' in sys
.argv
:
423 elif len(sys
.argv
) != 3:
424 sys
.stderr
.write("exactly two non-options arguments required; "
425 "use --help for help\n")
428 extract_vendor_ids(sys
.argv
[2])
429 extract_ofp_errors(sys
.argv
[1])