Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Update bpftool's consistency script for checking options

Update the script responsible for checking that the different types used
at various places in bpftool are synchronised, and extend it to check
the consistency of options between the help messages in the source code
and the manual pages.

Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20210730215435.7095-6-quentin@isovalent.com

authored by

Quentin Monnet and committed by
Andrii Nakryiko
da87772f c07ba629

+111 -11
+111 -11
tools/testing/selftests/bpf/test_bpftool_synctypes.py
··· 200 200 @block_name: name of the blog to parse, 'TYPE' in the example 201 201 """ 202 202 start_marker = re.compile(f'\*{block_name}\* := {{') 203 - pattern = re.compile('\*\*([\w/]+)\*\*') 203 + pattern = re.compile('\*\*([\w/-]+)\*\*') 204 204 end_marker = re.compile('}\n') 205 205 return self.__get_description_list(start_marker, pattern, end_marker) 206 206 ··· 223 223 end_marker = re.compile('}') 224 224 return self.__get_description_list(start_marker, pattern, end_marker) 225 225 226 + def get_help_list_macro(self, macro): 227 + """ 228 + Search for and parse a list of values from a help message starting with 229 + a macro in bpftool, for example: 230 + 231 + " " HELP_SPEC_OPTIONS " |\\n" 232 + " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} }\\n" 233 + 234 + Return a set containing all item names, for example: 235 + 236 + {'-f', '--bpffs', '-m', '--mapcompat', '-n', '--nomount'} 237 + 238 + @macro: macro starting the block, 'HELP_SPEC_OPTIONS' in the example 239 + """ 240 + start_marker = re.compile(f'"\s*{macro}\s*" [|}}]') 241 + pattern = re.compile('([\w-]+) ?(?:\||}[ }\]])') 242 + end_marker = re.compile('}\\\\n') 243 + return self.__get_description_list(start_marker, pattern, end_marker) 244 + 245 + def default_options(self): 246 + """ 247 + Return the default options contained in HELP_SPEC_OPTIONS 248 + """ 249 + return { '-j', '--json', '-p', '--pretty', '-d', '--debug' } 250 + 226 251 def get_bashcomp_list(self, block_name): 227 252 """ 228 253 Search for and parse a list of type names from a variable in bash ··· 267 242 end_marker = re.compile('\'$') 268 243 return self.__get_description_list(start_marker, pattern, end_marker) 269 244 270 - class ProgFileExtractor(FileExtractor): 245 + class SourceFileExtractor(FileExtractor): 246 + """ 247 + An abstract extractor for a source file with usage message. 248 + This class does not offer a way to set a filename, which is expected to be 249 + defined in children classes. 250 + """ 251 + def get_options(self): 252 + return self.default_options().union(self.get_help_list_macro('HELP_SPEC_OPTIONS')) 253 + 254 + class ProgFileExtractor(SourceFileExtractor): 271 255 """ 272 256 An extractor for bpftool's prog.c. 273 257 """ ··· 291 257 def get_prog_attach_help(self): 292 258 return self.get_help_list('ATTACH_TYPE') 293 259 294 - class MapFileExtractor(FileExtractor): 260 + class MapFileExtractor(SourceFileExtractor): 295 261 """ 296 262 An extractor for bpftool's map.c. 297 263 """ ··· 303 269 def get_map_help(self): 304 270 return self.get_help_list('TYPE') 305 271 306 - class CgroupFileExtractor(FileExtractor): 272 + class CgroupFileExtractor(SourceFileExtractor): 307 273 """ 308 274 An extractor for bpftool's cgroup.c. 309 275 """ ··· 312 278 def get_prog_attach_help(self): 313 279 return self.get_help_list('ATTACH_TYPE') 314 280 315 - class CommonFileExtractor(FileExtractor): 281 + class CommonFileExtractor(SourceFileExtractor): 316 282 """ 317 283 An extractor for bpftool's common.c. 318 284 """ ··· 336 302 cgroup_types[key] = value 337 303 return cgroup_types 338 304 305 + class GenericSourceExtractor(SourceFileExtractor): 306 + """ 307 + An extractor for generic source code files. 308 + """ 309 + filename = "" 310 + 311 + def __init__(self, filename): 312 + self.filename = os.path.join(BPFTOOL_DIR, filename) 313 + super().__init__() 314 + 339 315 class BpfHeaderExtractor(FileExtractor): 340 316 """ 341 317 An extractor for the UAPI BPF header. ··· 361 317 def get_attach_types(self): 362 318 return self.get_enum('bpf_attach_type') 363 319 364 - class ManProgExtractor(FileExtractor): 320 + class ManPageExtractor(FileExtractor): 321 + """ 322 + An abstract extractor for an RST documentation page. 323 + This class does not offer a way to set a filename, which is expected to be 324 + defined in children classes. 325 + """ 326 + def get_options(self): 327 + return self.get_rst_list('OPTIONS') 328 + 329 + class ManProgExtractor(ManPageExtractor): 365 330 """ 366 331 An extractor for bpftool-prog.rst. 367 332 """ ··· 379 326 def get_attach_types(self): 380 327 return self.get_rst_list('ATTACH_TYPE') 381 328 382 - class ManMapExtractor(FileExtractor): 329 + class ManMapExtractor(ManPageExtractor): 383 330 """ 384 331 An extractor for bpftool-map.rst. 385 332 """ ··· 388 335 def get_map_types(self): 389 336 return self.get_rst_list('TYPE') 390 337 391 - class ManCgroupExtractor(FileExtractor): 338 + class ManCgroupExtractor(ManPageExtractor): 392 339 """ 393 340 An extractor for bpftool-cgroup.rst. 394 341 """ ··· 396 343 397 344 def get_attach_types(self): 398 345 return self.get_rst_list('ATTACH_TYPE') 346 + 347 + class ManGenericExtractor(ManPageExtractor): 348 + """ 349 + An extractor for generic RST documentation pages. 350 + """ 351 + filename = "" 352 + 353 + def __init__(self, filename): 354 + self.filename = os.path.join(BPFTOOL_DIR, filename) 355 + super().__init__() 399 356 400 357 class BashcompExtractor(FileExtractor): 401 358 """ ··· 438 375 def main(): 439 376 # No arguments supported at this time, but print usage for -h|--help 440 377 argParser = argparse.ArgumentParser(description=""" 441 - Verify that bpftool's code, help messages, documentation and bash completion 442 - are all in sync on program types, map types and attach types. Also check that 443 - bpftool is in sync with the UAPI BPF header. 378 + Verify that bpftool's code, help messages, documentation and bash 379 + completion are all in sync on program types, map types, attach types, and 380 + options. Also check that bpftool is in sync with the UAPI BPF header. 444 381 """) 445 382 args = argParser.parse_args() 446 383 ··· 462 399 source_map_types.discard('unspec') 463 400 464 401 help_map_types = map_info.get_map_help() 402 + help_map_options = map_info.get_options() 465 403 map_info.close() 466 404 467 405 man_map_info = ManMapExtractor() 406 + man_map_options = man_map_info.get_options() 468 407 man_map_types = man_map_info.get_map_types() 469 408 man_map_info.close() 470 409 ··· 477 412 f'Comparing {MapFileExtractor.filename} (map_type_name) and {MapFileExtractor.filename} (do_help() TYPE):') 478 413 verify(source_map_types, man_map_types, 479 414 f'Comparing {MapFileExtractor.filename} (map_type_name) and {ManMapExtractor.filename} (TYPE):') 415 + verify(help_map_options, man_map_options, 416 + f'Comparing {MapFileExtractor.filename} (do_help() OPTIONS) and {ManMapExtractor.filename} (OPTIONS):') 480 417 verify(source_map_types, bashcomp_map_types, 481 418 f'Comparing {MapFileExtractor.filename} (map_type_name) and {BashcompExtractor.filename} (BPFTOOL_MAP_CREATE_TYPES):') 482 419 ··· 508 441 source_prog_attach_types = set(prog_info.get_attach_types().values()) 509 442 510 443 help_prog_attach_types = prog_info.get_prog_attach_help() 444 + help_prog_options = prog_info.get_options() 511 445 prog_info.close() 512 446 513 447 man_prog_info = ManProgExtractor() 448 + man_prog_options = man_prog_info.get_options() 514 449 man_prog_attach_types = man_prog_info.get_attach_types() 515 450 man_prog_info.close() 516 451 ··· 523 454 f'Comparing {ProgFileExtractor.filename} (attach_type_strings) and {ProgFileExtractor.filename} (do_help() ATTACH_TYPE):') 524 455 verify(source_prog_attach_types, man_prog_attach_types, 525 456 f'Comparing {ProgFileExtractor.filename} (attach_type_strings) and {ManProgExtractor.filename} (ATTACH_TYPE):') 457 + verify(help_prog_options, man_prog_options, 458 + f'Comparing {ProgFileExtractor.filename} (do_help() OPTIONS) and {ManProgExtractor.filename} (OPTIONS):') 526 459 verify(source_prog_attach_types, bashcomp_prog_attach_types, 527 460 f'Comparing {ProgFileExtractor.filename} (attach_type_strings) and {BashcompExtractor.filename} (BPFTOOL_PROG_ATTACH_TYPES):') 528 461 ··· 535 464 536 465 cgroup_info = CgroupFileExtractor() 537 466 help_cgroup_attach_types = cgroup_info.get_prog_attach_help() 467 + help_cgroup_options = cgroup_info.get_options() 538 468 cgroup_info.close() 539 469 540 470 man_cgroup_info = ManCgroupExtractor() 471 + man_cgroup_options = man_cgroup_info.get_options() 541 472 man_cgroup_attach_types = man_cgroup_info.get_attach_types() 542 473 man_cgroup_info.close() 543 474 ··· 550 477 f'Comparing {CommonFileExtractor.filename} (attach_type_strings) and {CgroupFileExtractor.filename} (do_help() ATTACH_TYPE):') 551 478 verify(source_cgroup_attach_types, man_cgroup_attach_types, 552 479 f'Comparing {CommonFileExtractor.filename} (attach_type_strings) and {ManCgroupExtractor.filename} (ATTACH_TYPE):') 480 + verify(help_cgroup_options, man_cgroup_options, 481 + f'Comparing {CgroupFileExtractor.filename} (do_help() OPTIONS) and {ManCgroupExtractor.filename} (OPTIONS):') 553 482 verify(source_cgroup_attach_types, bashcomp_cgroup_attach_types, 554 483 f'Comparing {CommonFileExtractor.filename} (attach_type_strings) and {BashcompExtractor.filename} (BPFTOOL_CGROUP_ATTACH_TYPES):') 484 + 485 + # Options for remaining commands 486 + 487 + for cmd in [ 'btf', 'feature', 'gen', 'iter', 'link', 'net', 'perf', 'struct_ops', ]: 488 + source_info = GenericSourceExtractor(cmd + '.c') 489 + help_cmd_options = source_info.get_options() 490 + source_info.close() 491 + 492 + man_cmd_info = ManGenericExtractor(os.path.join('Documentation', 'bpftool-' + cmd + '.rst')) 493 + man_cmd_options = man_cmd_info.get_options() 494 + man_cmd_info.close() 495 + 496 + verify(help_cmd_options, man_cmd_options, 497 + f'Comparing {source_info.filename} (do_help() OPTIONS) and {man_cmd_info.filename} (OPTIONS):') 498 + 499 + source_main_info = GenericSourceExtractor('main.c') 500 + help_main_options = source_main_info.get_options() 501 + source_main_info.close() 502 + 503 + man_main_info = ManGenericExtractor(os.path.join('Documentation', 'bpftool.rst')) 504 + man_main_options = man_main_info.get_options() 505 + man_main_info.close() 506 + 507 + verify(help_main_options, man_main_options, 508 + f'Comparing {source_main_info.filename} (do_help() OPTIONS) and {man_main_info.filename} (OPTIONS):') 555 509 556 510 sys.exit(retval) 557 511