]>
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
['OF']:
304 # All standard OpenFlow errors have a type and a code.
306 fatal("%s: %s domain requires code" % (dst
, vendor_name
))
307 elif vendor
== vendor_map
['NX']:
308 # Before OpenFlow 1.2, OVS used a Nicira extension to
309 # define errors that included a type and a code.
311 # In OpenFlow 1.2 and later, Nicira extension errors
312 # are defined using the OpenFlow experimenter error
313 # mechanism that includes a type but not a code.
314 if v1
< version_map
['1.2'] or v2
< version_map
['1.2']:
316 fatal("%s: NX1.0 and NX1.1 domains require code"
317 % (dst
, vendor_name
))
318 if v1
>= version_map
['1.2'] or v2
>= version_map
['1.2']:
320 fatal("%s: NX1.2+ domains do not have codes" % dst
)
322 # Experimenter extension error for OF1.2+ only.
323 if v1
< version_map
['1.2']:
324 fatal("%s: %s domain not supported before OF1.2"
325 % (dst
, vendor_name
))
327 fatal("%s: %s domains do not have codes"
328 % (dst
, vendor_name
))
332 for version
in range(v1
, v2
+ 1):
333 domain
[version
].setdefault(vendor
, {})
334 domain
[version
][vendor
].setdefault(type_
, {})
335 if code
in domain
[version
][vendor
][type_
]:
336 msg
= "%#x,%d,%d in OF%s means both %s and %s" % (
337 vendor
, type_
, code
, version_reverse_map
[version
],
338 domain
[version
][vendor
][type_
][code
][0], enum
)
339 if msg
in expected_errors
:
340 del expected_errors
[msg
]
342 error("%s: %s." % (dst
, msg
))
343 sys
.stderr
.write("%s:%d: %s: Here is the location "
344 "of the previous definition.\n"
345 % (domain
[version
][vendor
][type_
][code
][1],
346 domain
[version
][vendor
][type_
][code
][2],
349 domain
[version
][vendor
][type_
][code
] = (enum
, fileName
,
352 assert enum
not in reverse
[version
]
353 reverse
[version
][enum
] = (vendor
, type_
, code
)
357 for fn
, ln
in expected_errors
.values():
358 sys
.stderr
.write("%s:%d: expected duplicate not used.\n" % (fn
, ln
))
365 /* Generated automatically; do not modify! -*- buffer-read-only: t -*- */
367 #define OFPERR_N_ERRORS %d
369 struct ofperr_domain {
372 enum ofperr (*decode)(uint32_t vendor, uint16_t type, uint16_t code);
373 struct triplet errors[OFPERR_N_ERRORS];
376 static const char *error_names[OFPERR_N_ERRORS] = {
380 static const char *error_comments[OFPERR_N_ERRORS] = {
384 '\n'.join(' "%s",' % name
for name
in names
),
385 '\n'.join(' "%s",' % re
.sub(r
'(["\\])', r
'\\\1', comment
)
386 for comment
in comments
)))
388 def output_domain(map, name
, description
, version
):
391 %s_decode(uint32_t vendor, uint16_t type, uint16_t code)
393 switch (((uint64_t) vendor << 32) | (type << 16) | code) {""" % name
)
398 vendor
, type_
, code
= map[enum
]
399 value
= (vendor
<< 32) |
(type_
<< 16) | code
404 vendor_s
= "(%#xULL << 32) | " % vendor
407 print (" case %s(%d << 16) | %d:" % (vendor_s
, type_
, code
))
408 print (" return OFPERR_%s;" % enum
)
416 static const struct ofperr_domain %s = {
420 {""" % (name
, description
, version
, name
))
423 vendor
, type_
, code
= map[enum
]
426 print " { %#8x, %2d, %3d }, /* %s */" % (vendor
, type_
, code
, enum
)
428 print (" { -1, -1, -1 }, /* %s */" % enum
)
433 for version_name
, id_
in version_map
.items():
434 var
= 'ofperr_of' + re
.sub('[^A-Za-z0-9_]', '', version_name
)
435 description
= "OpenFlow %s" % version_name
436 output_domain(reverse
[id_
], var
, description
, id_
)
438 if __name__
== '__main__':
439 if '--help' in sys
.argv
:
441 elif len(sys
.argv
) != 3:
442 sys
.stderr
.write("exactly two non-options arguments required; "
443 "use --help for help\n")
446 extract_vendor_ids(sys
.argv
[2])
447 extract_ofp_errors(sys
.argv
[1])