]>
git.proxmox.com Git - mirror_ovs.git/blob - build-aux/extract-ofp-errors
9642593d24581b96863ef00cf74e0ac19cd2c354
9 # Map from OpenFlow version number to version ID used in ofp_header.
10 version_map
= {"1.0": 0x01,
17 version_reverse_map
= dict((v
, k
) for (k
, v
) in version_map
.iteritems())
21 idRe
= "[a-zA-Z_][a-zA-Z_0-9]*"
22 tokenRe
= "#?" + idRe
+ "|[0-9]+|."
31 inputFile
= open(fileName
)
38 line
= inputFile
.readline()
44 fatal("unexpected end of input")
54 if line
.startswith("/*"):
58 commentEnd
= line
.find("*/")
63 line
= line
[commentEnd
+ 2:]
65 match
= re
.match(tokenRe
, line
)
66 token
= match
.group(0)
67 line
= line
[len(token
):]
68 if token
.startswith('#'):
70 elif token
in macros
and not inDirective
:
71 line
= macros
[token
] + line
80 line
= inputFile
.readline()
82 while line
.endswith("\\\n"):
83 line
= line
[:-2] + inputFile
.readline()
87 fatal("unexpected end of input")
94 sys
.stderr
.write("%s:%d: %s\n" % (fileName
, lineNumber
, msg
))
107 return re
.match(idRe
+ "$", s
) != None
111 fatal("identifier expected")
114 if not re
.match('[0-9]+$', token
):
115 fatal("integer expected")
126 fatal("%s expected" % t
)
128 def parseTaggedName():
129 assert token
in ('struct', 'union')
133 name
= "%s %s" % (name
, token
)
137 def print_enum(tag
, constants
, storage_class
):
139 %(storage_class)sconst char *
140 %(tag)s_to_string(uint16_t value)
144 "bufferlen": len(tag
) + 32,
145 "storage_class": storage_class
})
146 for constant
in constants
:
147 print (" case %s: return \"%s\";" % (constant
, constant
))
155 argv0
= os
.path
.basename(sys
.argv
[0])
157 %(argv0)s, for extracting OpenFlow error codes from header files
158 usage: %(argv0)s ERROR_HEADER VENDOR_HEADER
160 This program reads VENDOR_HEADER to obtain OpenFlow vendor (aka
161 experimenter IDs), then ERROR_HEADER to obtain OpenFlow error number.
162 It outputs a C source file for translating OpenFlow error codes into
165 ERROR_HEADER should point to include/openvswitch/ofp-errors.h.
166 VENDOR_HEADER should point to include/openflow/openflow-common.h.
167 The output is suitable for use as lib/ofp-errors.inc.\
168 ''' % {"argv0": argv0
})
171 def extract_vendor_ids(fn
):
178 m
= re
.match(r
'#define\s+([A-Z0-9_]+)_VENDOR_ID\s+(0x[0-9a-fA-F]+|[0-9]+)', line
)
183 id_
= int(m
.group(2), 0)
185 if name
in vendor_map
:
186 error("%s: duplicate definition of vendor" % name
)
187 sys
.stderr
.write("%s: Here is the location of the previous "
188 "definition.\n" % vendor_loc
[name
])
191 vendor_map
[name
] = id_
192 vendor_loc
[name
] = "%s:%d" % (fileName
, lineNumber
)
195 fatal("%s: no vendor definitions found" % fn
)
199 vendor_reverse_map
= {}
200 for name
, id_
in vendor_map
.items():
201 if id_
in vendor_reverse_map
:
202 fatal("%s: duplicate vendor id for vendors %s and %s"
203 % (id_
, vendor_reverse_map
[id_
], name
))
204 vendor_reverse_map
[id_
] = name
206 def extract_ofp_errors(fn
):
213 for domain_name
in version_map
.values():
214 domain
[domain_name
] = {}
215 reverse
[domain_name
] = {}
224 if re
.match('enum ofperr', line
):
229 if line
.startswith('/*') or not line
or line
.isspace():
231 elif re
.match('}', line
):
234 if not line
.lstrip().startswith('/*'):
235 fatal("unexpected syntax between errors")
237 comment
= line
.lstrip()[2:].strip()
238 while not comment
.endswith('*/'):
240 if line
.startswith('/*') or not line
or line
.isspace():
241 fatal("unexpected syntax within error")
242 comment
+= ' %s' % line
.lstrip('* \t').rstrip(' \t\r\n')
243 comment
= comment
[:-2].rstrip()
245 m
= re
.match('Expected: (.*)\.$', comment
)
247 expected_errors
[m
.group(1)] = (fileName
, lineNumber
)
250 m
= re
.match('((?:.(?!\. ))+.)\. (.*)$', comment
)
252 fatal("unexpected syntax between errors")
254 dsts
, comment
= m
.groups()
257 m
= re
.match('\s+(?:OFPERR_([A-Z0-9_]+))(\s*=\s*OFPERR_OFS)?,',
260 fatal("syntax error expecting enum value")
264 fatal("%s specified twice" % enum
)
266 comments
.append(re
.sub('\[[^]]*\]', '', comment
))
269 for dst
in dsts
.split(', '):
270 m
= re
.match(r
'([A-Z]+)([0-9.]+)(\+|-[0-9.]+)?\((\d+)(?:,(\d+))?\)$', dst
)
272 fatal("%r: syntax error in destination" % dst
)
273 vendor_name
= m
.group(1)
274 version1_name
= m
.group(2)
275 version2_name
= m
.group(3)
276 type_
= int(m
.group(4))
278 code
= int(m
.group(5))
282 if vendor_name
not in vendor_map
:
283 fatal("%s: unknown vendor" % vendor_name
)
284 vendor
= vendor_map
[vendor_name
]
286 if version1_name
not in version_map
:
287 fatal("%s: unknown OpenFlow version" % version1_name
)
288 v1
= version_map
[version1_name
]
290 if version2_name
is None:
292 elif version2_name
== "+":
293 v2
= max(version_map
.values())
294 elif version2_name
[1:] not in version_map
:
295 fatal("%s: unknown OpenFlow version" % version2_name
[1:])
297 v2
= version_map
[version2_name
[1:]]
300 fatal("%s%s: %s precedes %s"
301 % (version1_name
, version2_name
,
302 version2_name
, version1_name
))
304 if vendor
== vendor_map
['OF']:
305 # All standard OpenFlow errors have a type and a code.
307 fatal("%s: %s domain requires code" % (dst
, vendor_name
))
308 elif vendor
== vendor_map
['NX']:
309 # Before OpenFlow 1.2, OVS used a Nicira extension to
310 # define errors that included a type and a code.
312 # In OpenFlow 1.2 and later, Nicira extension errors
313 # are defined using the OpenFlow experimenter error
314 # mechanism that includes a type but not a code.
315 if v1
< version_map
['1.2'] or v2
< version_map
['1.2']:
317 fatal("%s: NX1.0 and NX1.1 domains require code"
318 % (dst
, vendor_name
))
319 if v1
>= version_map
['1.2'] or v2
>= version_map
['1.2']:
321 fatal("%s: NX1.2+ domains do not have codes" % dst
)
323 # Experimenter extension error for OF1.2+ only.
324 if v1
< version_map
['1.2']:
325 fatal("%s: %s domain not supported before OF1.2"
326 % (dst
, vendor_name
))
328 fatal("%s: %s domains do not have codes"
329 % (dst
, vendor_name
))
333 for version
in range(v1
, v2
+ 1):
334 domain
[version
].setdefault(vendor
, {})
335 domain
[version
][vendor
].setdefault(type_
, {})
336 if code
in domain
[version
][vendor
][type_
]:
337 msg
= "%#x,%d,%d in OF%s means both %s and %s" % (
338 vendor
, type_
, code
, version_reverse_map
[version
],
339 domain
[version
][vendor
][type_
][code
][0], enum
)
340 if msg
in expected_errors
:
341 del expected_errors
[msg
]
343 error("%s: %s." % (dst
, msg
))
344 sys
.stderr
.write("%s:%d: %s: Here is the location "
345 "of the previous definition.\n"
346 % (domain
[version
][vendor
][type_
][code
][1],
347 domain
[version
][vendor
][type_
][code
][2],
350 domain
[version
][vendor
][type_
][code
] = (enum
, fileName
,
353 assert enum
not in reverse
[version
]
354 reverse
[version
][enum
] = (vendor
, type_
, code
)
358 for fn
, ln
in expected_errors
.values():
359 sys
.stderr
.write("%s:%d: expected duplicate not used.\n" % (fn
, ln
))
366 /* Generated automatically; do not modify! -*- buffer-read-only: t -*- */
368 #define OFPERR_N_ERRORS %d
370 struct ofperr_domain {
373 enum ofperr (*decode)(uint32_t vendor, uint16_t type, uint16_t code);
374 struct triplet errors[OFPERR_N_ERRORS];
377 static const char *error_names[OFPERR_N_ERRORS] = {
381 static const char *error_comments[OFPERR_N_ERRORS] = {
385 '\n'.join(' "%s",' % name
for name
in names
),
386 '\n'.join(' "%s",' % re
.sub(r
'(["\\])', r
'\\\1', comment
)
387 for comment
in comments
)))
389 def output_domain(map, name
, description
, version
):
392 %s_decode(uint32_t vendor, uint16_t type, uint16_t code)
394 switch (((uint64_t) vendor << 32) | (type << 16) | code) {""" % name
)
399 vendor
, type_
, code
= map[enum
]
400 value
= (vendor
<< 32) |
(type_
<< 16) | code
405 vendor_s
= "(%#xULL << 32) | " % vendor
408 print (" case %s(%d << 16) | %d:" % (vendor_s
, type_
, code
))
409 print (" return OFPERR_%s;" % enum
)
417 static const struct ofperr_domain %s = {
421 {""" % (name
, description
, version
, name
))
424 vendor
, type_
, code
= map[enum
]
427 print " { %#8x, %2d, %3d }, /* %s */" % (vendor
, type_
, code
, enum
)
429 print (" { -1, -1, -1 }, /* %s */" % enum
)
434 for version_name
, id_
in version_map
.items():
435 var
= 'ofperr_of' + re
.sub('[^A-Za-z0-9_]', '', version_name
)
436 description
= "OpenFlow %s" % version_name
437 output_domain(reverse
[id_
], var
, description
, id_
)
439 if __name__
== '__main__':
440 if '--help' in sys
.argv
:
442 elif len(sys
.argv
) != 3:
443 sys
.stderr
.write("exactly two non-options arguments required; "
444 "use --help for help\n")
447 extract_vendor_ids(sys
.argv
[2])
448 extract_ofp_errors(sys
.argv
[1])