diff --git a/Makefile.am b/Makefile.am index ce0f70a1a2..8c7bde9d4c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -144,7 +144,6 @@ pkginclude_HEADERS = nodist_pkginclude_HEADERS = dist_yangmodels_DATA = man_MANS = -vtysh_scan = vtysh_daemons = clippy_scan = @@ -226,6 +225,7 @@ EXTRA_DIST += \ python/makefile.py \ python/tiabwarfo.py \ python/xrelfo.py \ + python/xref2vtysh.py \ python/test_xrelfo.py \ python/runtests.py \ \ diff --git a/babeld/subdir.am b/babeld/subdir.am index 856cbd13e3..4b9037283c 100644 --- a/babeld/subdir.am +++ b/babeld/subdir.am @@ -4,11 +4,6 @@ if BABELD sbin_PROGRAMS += babeld/babeld -vtysh_scan += \ - babeld/babel_interface.c \ - babeld/babel_zebra.c \ - babeld/babeld.c \ - # end vtysh_daemons += babeld endif diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 69424c45d9..52f2dd8fd3 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -26,9 +26,7 @@ #include "lib/log.h" #include "lib/northbound_cli.h" -#ifndef VTYSH_EXTRACT_PL #include "bfdd/bfdd_cli_clippy.c" -#endif /* VTYSH_EXTRACT_PL */ #include "bfd.h" #include "bfdd_nb.h" diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 4a2c5bf662..7b7a001e24 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -28,9 +28,7 @@ #include "bfd.h" -#ifndef VTYSH_EXTRACT_PL #include "bfdd/bfdd_vty_clippy.c" -#endif /* * Commands help string definitions. diff --git a/bfdd/subdir.am b/bfdd/subdir.am index 8d35b933d7..b86a18967e 100644 --- a/bfdd/subdir.am +++ b/bfdd/subdir.am @@ -5,8 +5,6 @@ if BFDD noinst_LIBRARIES += bfdd/libbfd.a sbin_PROGRAMS += bfdd/bfdd -vtysh_scan += bfdd/bfdd_vty.c -vtysh_scan += bfdd/bfdd_cli.c vtysh_daemons += bfdd man8 += $(MANBUILD)/frr-bfdd.8 endif diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 2e5c772679..2a65dbac80 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -2034,9 +2034,7 @@ static const struct cmd_variable_handler bmp_targets_var_handlers[] = { #define BMP_STR "BGP Monitoring Protocol\n" -#ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_bmp_clippy.c" -#endif DEFPY_NOSH(bmp_targets_main, bmp_targets_cmd, diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index a629695a3b..92a22d71b3 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -1415,9 +1415,7 @@ DEFUN (no_debug_bgp_update_direct_peer, return CMD_SUCCESS; } -#ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_debug_clippy.c" -#endif DEFPY (debug_bgp_update_prefix_afi_safi, debug_bgp_update_prefix_afi_safi_cmd, diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index c0ad72dc33..c74bd14b4e 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -3336,9 +3336,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn) } } -#ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_evpn_vty_clippy.c" -#endif DEFPY(bgp_evpn_flood_control, bgp_evpn_flood_control_cmd, diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index c227a5e41c..129878451d 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -39,9 +39,7 @@ #define BGP_LABELPOOL_ENABLE_TESTS 0 -#ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_labelpool_clippy.c" -#endif /* diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index a2deefbf67..1a2408adea 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -90,9 +90,7 @@ #include "bgpd/bgp_flowspec_util.h" #include "bgpd/bgp_pbr.h" -#ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_route_clippy.c" -#endif DEFINE_HOOK(bgp_snmp_update_stats, (struct bgp_node *rn, struct bgp_path_info *pi, bool added), diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 637f462e8d..aff09206e4 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -74,9 +74,7 @@ #include "bgpd/rfapi/bgp_rfapi_cfg.h" #endif -#ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_routemap_clippy.c" -#endif /* Memo of route-map commands. diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index cb7afd8967..2acf74c52b 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -52,16 +52,12 @@ #include "lib/network.h" #include "lib/thread.h" -#ifndef VTYSH_EXTRACT_PL #include "rtrlib/rtrlib.h" -#endif #include "hook.h" #include "libfrr.h" #include "lib/version.h" -#ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_rpki_clippy.c" -#endif DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server"); DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group"); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 73919ffab2..057f9ffc37 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1308,9 +1308,7 @@ void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi) bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL); } -#ifndef VTYSH_EXTRACT_PL #include "bgpd/bgp_vty_clippy.c" -#endif DEFUN_HIDDEN (bgp_local_mac, bgp_local_mac_cmd, diff --git a/bgpd/subdir.am b/bgpd/subdir.am index 765650313b..04fe1f1249 100644 --- a/bgpd/subdir.am +++ b/bgpd/subdir.am @@ -6,36 +6,9 @@ if BGPD noinst_LIBRARIES += bgpd/libbgp.a sbin_PROGRAMS += bgpd/bgpd noinst_PROGRAMS += bgpd/bgp_btoa -vtysh_scan += \ - bgpd/bgp_bfd.c \ - bgpd/bgp_debug.c \ - bgpd/bgp_dump.c \ - bgpd/bgp_evpn_mh.c \ - bgpd/bgp_evpn_vty.c \ - bgpd/bgp_filter.c \ - bgpd/bgp_labelpool.c \ - bgpd/bgp_mplsvpn.c \ - bgpd/bgp_nexthop.c \ - bgpd/bgp_route.c \ - bgpd/bgp_routemap.c \ - bgpd/bgp_vty.c \ - bgpd/bgp_flowspec_vty.c \ - # end - -# can be loaded as DSO - always include for vtysh -vtysh_scan += bgpd/bgp_rpki.c -vtysh_scan += bgpd/bgp_bmp.c vtysh_daemons += bgpd -if ENABLE_BGP_VNC -vtysh_scan += \ - bgpd/rfapi/bgp_rfapi_cfg.c \ - bgpd/rfapi/rfapi.c \ - bgpd/rfapi/rfapi_vty.c \ - bgpd/rfapi/vnc_debug.c \ - # end -endif if SNMP module_LTLIBRARIES += bgpd/bgpd_snmp.la endif diff --git a/configure.ac b/configure.ac index 4cbdfe0fcc..1a481ecd79 100644 --- a/configure.ac +++ b/configure.ac @@ -2747,7 +2747,6 @@ AC_CONFIG_FILES([ pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh pkgsrc/eigrpd.sh]) -AC_CONFIG_FILES([vtysh/extract.pl], [chmod +x vtysh/extract.pl]) AC_CONFIG_FILES([tools/frr], [chmod +x tools/frr]) AC_CONFIG_FILES([tools/watchfrr.sh], [chmod +x tools/watchfrr.sh]) AC_CONFIG_FILES([tools/frrinit.sh], [chmod +x tools/frrinit.sh]) diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index ff6c4f6e16..d51f06d118 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -453,9 +453,7 @@ all DEFPY statements**: /* GPL header */ #include ... ... - #ifndef VTYSH_EXTRACT_PL #include "daemon/filename_clippy.c" - #endif DEFPY(...) DEFPY(...) diff --git a/doc/developer/vtysh.rst b/doc/developer/vtysh.rst index 160676a7b1..323ea57c16 100644 --- a/doc/developer/vtysh.rst +++ b/doc/developer/vtysh.rst @@ -43,9 +43,14 @@ simplifying the output. This is discussed in :ref:`vtysh-configuration`. Command Extraction ------------------ -When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR -codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms -them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH`` +To build ``vtysh``, the :file:`python/xref2vtysh.py` script scans through the +:file:`frr.xref` file created earlier in the build process. This file contains +a list of all ``DEFUN`` and ``install_element`` sites in the code, generated +directly from the binaries (and therefore matching exactly what is really +available.) + +This list is collated and transformed into ``DEFSH`` (and ``install_element``) +statements, output to ``vtysh_cmd.c``. Each ``DEFSH`` contains the name of the command plus ``_vtysh``, as well as a flag that indicates which daemons the command was found in. When the command is executed in VTYSH, this flag is inspected to determine which daemons to send the command @@ -55,6 +60,12 @@ avoiding spurious errors from daemons that don't have the command defined. The extraction script contains lots of hardcoded knowledge about what sources to look at and what flags to use for certain commands. +.. note:: + + The ``vtysh_scan`` Makefile variable and ``#ifndef VTYSH_EXTRACT_PL`` + checks in source files are no longer used. Remove them when rebasing older + changes. + .. _vtysh-special-defuns: Special DEFUNs @@ -69,7 +80,7 @@ several VTYSH-specific ``DEFUN`` variants that each serve different purposes. simply forwarded to the daemons indicated in the daemon flag. ``DEFUN_NOSH`` - Used by daemons. Has the same expansion as a ``DEFUN``, but ``extract.pl`` + Used by daemons. Has the same expansion as a ``DEFUN``, but ``xref2vtysh.py`` will skip these definitions when extracting commands. This is typically used when VTYSH must take some special action upon receiving the command, and the programmer therefore needs to write VTYSH's copy of the command manually diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c index 744f5f9c7a..2afd9d5eaa 100644 --- a/eigrpd/eigrp_cli.c +++ b/eigrpd/eigrp_cli.c @@ -31,9 +31,7 @@ #include "eigrp_zebra.h" #include "eigrp_cli.h" -#ifndef VTYSH_EXTRACT_PL #include "eigrpd/eigrp_cli_clippy.c" -#endif /* VTYSH_EXTRACT_PL */ /* * XPath: /frr-eigrpd:eigrpd/instance diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c index 3d61294b22..137f9b028c 100644 --- a/eigrpd/eigrp_vty.c +++ b/eigrpd/eigrp_vty.c @@ -55,9 +55,7 @@ #include "eigrpd/eigrp_dump.h" #include "eigrpd/eigrp_const.h" -#ifndef VTYSH_EXTRACT_PL #include "eigrpd/eigrp_vty_clippy.c" -#endif static void eigrp_vty_display_prefix_entry(struct vty *vty, struct eigrp *eigrp, struct eigrp_prefix_descriptor *pe, diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index 3b647e060b..e417132b51 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -4,12 +4,6 @@ if EIGRPD sbin_PROGRAMS += eigrpd/eigrpd -vtysh_scan += \ - eigrpd/eigrp_cli.c \ - eigrpd/eigrp_dump.c \ - eigrpd/eigrp_vty.c \ - # end -# eigrpd/eigrp_routemap.c vtysh_daemons += eigrpd man8 += $(MANBUILD)/frr-eigrpd.8 endif diff --git a/grpc/subdir.am b/grpc/subdir.am index cbebd72323..06b37f91d6 100644 --- a/grpc/subdir.am +++ b/grpc/subdir.am @@ -28,6 +28,13 @@ am__v_PROTOC_1 = SUFFIXES += .pb.h .pb.cc .grpc.pb.cc +grpc/frr-northbound.grpc.pb.h: grpc/frr-northbound.grpc.pb.cc + @test -f $@ || rm -f $< || true + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $< +grpc/frr-northbound.pb.h: grpc/frr-northbound.pb.cc + @test -f $@ || rm -f $< || true + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $< + .proto.pb.cc: $(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --cpp_out=$(top_builddir) $^ .proto.grpc.pb.cc: diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index 9db867e2c0..3650984f1b 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -37,9 +37,7 @@ #include "isisd/isis_circuit.h" #include "isisd/isis_csm.h" -#ifndef VTYSH_EXTRACT_PL #include "isisd/isis_cli_clippy.c" -#endif #ifndef FABRICD diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index f70840a637..707bd162f5 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -1057,8 +1057,9 @@ static void show_node(struct vty *vty, struct isis_area *area, int level) } DEFUN(show_sr_node, show_sr_node_cmd, - "show isis segment-routing node", - SHOW_STR PROTO_HELP + "show " PROTO_NAME " segment-routing node", + SHOW_STR + PROTO_HELP "Segment-Routing\n" "Segment-Routing node\n") { diff --git a/isisd/subdir.am b/isisd/subdir.am index 3e5816c16b..dabf6a925e 100644 --- a/isisd/subdir.am +++ b/isisd/subdir.am @@ -5,16 +5,6 @@ if ISISD noinst_LIBRARIES += isisd/libisis.a sbin_PROGRAMS += isisd/isisd -vtysh_scan += \ - isisd/isis_cli.c \ - isisd/isis_ldp_sync.c \ - isisd/isis_redist.c \ - isisd/isis_spf.c \ - isisd/isis_te.c \ - isisd/isis_sr.c \ - isisd/isis_vty_fabricd.c \ - isisd/isisd.c \ - # end vtysh_daemons += isisd if SNMP module_LTLIBRARIES += isisd/isisd_snmp.la @@ -25,18 +15,6 @@ endif if FABRICD noinst_LIBRARIES += isisd/libfabric.a sbin_PROGRAMS += isisd/fabricd -if !ISISD -vtysh_scan += \ - isisd/isis_cli.c \ - isisd/isis_ldp_sync.c \ - isisd/isis_redist.c \ - isisd/isis_spf.c \ - isisd/isis_te.c \ - isisd/isis_sr.c \ - isisd/isis_vty_fabricd.c \ - isisd/isisd.c \ - # end -endif vtysh_daemons += fabricd endif diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index 3d11d3137a..33e6b297cb 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -25,9 +25,7 @@ #include "ldpd/ldpd.h" #include "ldpd/ldp_vty.h" -#ifndef VTYSH_EXTRACT_PL #include "ldpd/ldp_vty_cmds_clippy.c" -#endif DEFPY_NOSH(ldp_mpls_ldp, ldp_mpls_ldp_cmd, diff --git a/ldpd/subdir.am b/ldpd/subdir.am index 083effb703..0b948adb6f 100644 --- a/ldpd/subdir.am +++ b/ldpd/subdir.am @@ -5,7 +5,6 @@ if LDPD noinst_LIBRARIES += ldpd/libldp.a sbin_PROGRAMS += ldpd/ldpd -vtysh_scan += ldpd/ldp_vty_cmds.c vtysh_daemons += ldpd man8 += $(MANBUILD)/frr-ldpd.8 endif diff --git a/lib/command.h b/lib/command.h index f4168dedd7..31e5cad23f 100644 --- a/lib/command.h +++ b/lib/command.h @@ -251,9 +251,6 @@ struct cmd_node { /* Argc max counts. */ #define CMD_ARGC_MAX 256 -/* Turn off these macros when using cpp with extract.pl */ -#ifndef VTYSH_EXTRACT_PL - /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ static const struct cmd_element cmdname = { \ @@ -370,8 +367,6 @@ struct cmd_node { #define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) -#endif /* VTYSH_EXTRACT_PL */ - /* Some macroes */ /* @@ -511,7 +506,6 @@ struct xref_install_element { enum node_type node_type; }; -#ifndef VTYSH_EXTRACT_PL #define install_element(node_type_, cmd_element_) do { \ static const struct xref_install_element _xref \ __attribute__((used)) = { \ @@ -523,7 +517,6 @@ struct xref_install_element { XREF_LINK(_xref.xref); \ _install_element(node_type_, cmd_element_); \ } while (0) -#endif extern void _install_element(enum node_type, const struct cmd_element *); diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 9a877a5704..e0f0f177e5 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -31,9 +31,7 @@ #include "lib/plist_int.h" #include "lib/printfrr.h" -#ifndef VTYSH_EXTRACT_PL #include "lib/filter_cli_clippy.c" -#endif /* VTYSH_EXTRACT_PL */ #define ACCESS_LIST_STR "Access list entry\n" #define ACCESS_LIST_ZEBRA_STR "Access list name\n" diff --git a/lib/if.c b/lib/if.c index deb0690dcf..76568071ef 100644 --- a/lib/if.c +++ b/lib/if.c @@ -35,9 +35,7 @@ #include "buffer.h" #include "log.h" #include "northbound_cli.h" -#ifndef VTYSH_EXTRACT_PL #include "lib/if_clippy.c" -#endif DEFINE_MTYPE_STATIC(LIB, IF, "Interface"); DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected"); diff --git a/lib/log_vty.c b/lib/log_vty.c index c9268734c4..4091c92c73 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -29,9 +29,7 @@ #include "lib/printfrr.h" #include "lib/systemd.h" -#ifndef VTYSH_EXTRACT_PL #include "lib/log_vty_clippy.c" -#endif #define ZLOG_MAXLVL(a, b) MAX(a, b) diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 7284d6cea6..f342f50e8f 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -28,9 +28,7 @@ #include #include -#ifndef VTYSH_EXTRACT_PL #include "lib/nexthop_group_clippy.c" -#endif DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group"); diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 56eac9dc32..e0dcdb490f 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -32,9 +32,7 @@ #include "northbound.h" #include "northbound_cli.h" #include "northbound_db.h" -#ifndef VTYSH_EXTRACT_PL #include "lib/northbound_cli_clippy.c" -#endif struct debug nb_dbg_cbs_config = {0, "Northbound callbacks: configuration"}; struct debug nb_dbg_cbs_state = {0, "Northbound callbacks: state"}; diff --git a/lib/plist.c b/lib/plist.c index ff2a59ba2d..17e692d139 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -1193,9 +1193,7 @@ static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name, return CMD_SUCCESS; } -#ifndef VTYSH_EXTRACT_PL #include "lib/plist_clippy.c" -#endif DEFPY (show_ip_prefix_list, show_ip_prefix_list_cmd, diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index e3da29bd71..cedee83d82 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -26,9 +26,7 @@ #include "lib/northbound_cli.h" #include "lib/routemap.h" -#ifndef VTYSH_EXTRACT_PL #include "lib/routemap_cli_clippy.c" -#endif /* VTYSH_EXTRACT_PL */ #define ROUTE_MAP_CMD_STR \ "Create route-map or enter route-map command mode\n" \ diff --git a/lib/subdir.am b/lib/subdir.am index e04e700eb6..ea6cb9339a 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -139,27 +139,6 @@ nodist_lib_libfrr_la_SOURCES = \ yang/frr-module-translator.yang.c \ # end -vtysh_scan += \ - lib/distribute.c \ - lib/filter.c \ - lib/filter_cli.c \ - lib/if.c \ - lib/if_rmap.c \ - lib/keychain.c \ - lib/lib_vty.c \ - lib/log_vty.c \ - lib/nexthop_group.c \ - lib/plist.c \ - lib/routemap.c \ - lib/routemap_cli.c \ - lib/spf_backoff.c \ - lib/thread.c \ - lib/vrf.c \ - lib/vty.c \ - # end -# can be loaded as DSO - always include for vtysh -vtysh_scan += lib/agentx.c - if SQLITE3 lib_libfrr_la_LIBADD += $(SQLITE3_LIBS) lib_libfrr_la_SOURCES += lib/db.c @@ -347,7 +326,6 @@ lib_libfrrsnmp_la_SOURCES = \ if CARES lib_LTLIBRARIES += lib/libfrrcares.la pkginclude_HEADERS += lib/resolver.h -vtysh_scan += lib/resolver.c endif lib_libfrrcares_la_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS) @@ -478,13 +456,18 @@ SUFFIXES += .xref # dependencies added in python/makefile.py frr.xref: - $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^ + $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ -c vtysh/vtysh_cmd.c $^ all-am: frr.xref clean-xref: -rm -rf $(xrefs) frr.xref clean-local: clean-xref +CLEANFILES += vtysh/vtysh_cmd.c +vtysh/vtysh_cmd.c: frr.xref + @test -f $@ || rm -f frr.xref || true + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) frr.xref + ## automake's "ylwrap" is a great piece of GNU software... not. .l.c: $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< diff --git a/lib/thread.c b/lib/thread.c index 9eac9b410a..4078634f75 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -102,9 +102,7 @@ unsigned long cputime_threshold = CONSUMED_TIME_CHECK; unsigned long walltime_threshold = CONSUMED_TIME_CHECK; /* CLI start ---------------------------------------------------------------- */ -#ifndef VTYSH_EXTRACT_PL #include "lib/thread_clippy.c" -#endif static unsigned int cpu_record_hash_key(const struct cpu_thread_history *a) { diff --git a/lib/vty.c b/lib/vty.c index 92db07677a..d524ae53cb 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -53,9 +53,7 @@ #include #include -#ifndef VTYSH_EXTRACT_PL #include "lib/vty_clippy.c" -#endif DEFINE_MTYPE_STATIC(LIB, VTY, "VTY"); DEFINE_MTYPE_STATIC(LIB, VTY_SERV, "VTY server"); diff --git a/lib/zebra.h b/lib/zebra.h index 53ae5b4e9e..b2f5e5a848 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -202,9 +202,9 @@ #endif /* HAVE_GLIBC_BACKTRACE */ /* Local includes: */ -#if !(defined(__GNUC__) || defined(VTYSH_EXTRACT_PL)) +#if !defined(__GNUC__) #define __attribute__(x) -#endif /* !__GNUC__ || VTYSH_EXTRACT_PL */ +#endif /* !__GNUC__ */ #include diff --git a/lib/zlog_5424_cli.c b/lib/zlog_5424_cli.c index dd8dbfaffd..5eebda9deb 100644 --- a/lib/zlog_5424_cli.c +++ b/lib/zlog_5424_cli.c @@ -158,9 +158,7 @@ static int reconf_clear_dst(struct zlog_cfg_5424_user *cfg, struct vty *vty) return reconf_dst(cfg, vty); } -#ifndef VTYSH_EXTRACT_PL #include "lib/zlog_5424_cli_clippy.c" -#endif DEFPY_NOSH(log_5424_target, log_5424_target_cmd, diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index dc0c162c83..227ff6c678 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -4,7 +4,6 @@ if NHRPD sbin_PROGRAMS += nhrpd/nhrpd -vtysh_scan += nhrpd/nhrp_vty.c vtysh_daemons += nhrpd man8 += $(MANBUILD)/frr-nhrpd.8 endif diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 78b2ffbcf3..6a4236e717 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -49,9 +49,7 @@ #include "ospf6d.h" #include "lib/json.h" #include "ospf6_nssa.h" -#ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_area_clippy.c" -#endif DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name"); diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 924c2d6c5b..07061b6f57 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -65,9 +65,7 @@ static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type); static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6, struct ospf6_redist *red, int type); -#ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_asbr_clippy.c" -#endif unsigned char conf_debug_ospf6_asbr = 0; @@ -2206,10 +2204,10 @@ static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = { /* add "set metric-type" */ DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd, "set metric-type ", - "Set value\n" - "Type of metric\n" - "OSPF6 external type 1 metric\n" - "OSPF6 external type 2 metric\n") + SET_STR + "Type of metric for destination routing protocol\n" + "OSPF[6] external type 1 metric\n" + "OSPF[6] external type 2 metric\n") { char *ext = argv[2]->text; @@ -2228,10 +2226,10 @@ DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd, DEFUN_YANG (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd, "no set metric-type []", NO_STR - "Set value\n" - "Type of metric\n" - "OSPF6 external type 1 metric\n" - "OSPF6 external type 2 metric\n") + SET_STR + "Type of metric for destination routing protocol\n" + "OSPF[6] external type 1 metric\n" + "OSPF[6] external type 2 metric\n") { const char *xpath = "./set-action[action='frr-ospf-route-map:metric-type']"; diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c index d7de66c663..1f7fefa048 100644 --- a/ospf6d/ospf6_gr.c +++ b/ospf6d/ospf6_gr.c @@ -42,9 +42,7 @@ #include "ospf6d/ospf6_intra.h" #include "ospf6d/ospf6_spf.h" #include "ospf6d/ospf6_gr.h" -#ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_gr_clippy.c" -#endif static void ospf6_gr_nvm_delete(struct ospf6 *ospf6); diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index f352d35270..771a710240 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -49,9 +49,7 @@ #include "ospf6d.h" #include "ospf6_gr.h" #include "lib/json.h" -#ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_gr_helper_clippy.c" -#endif DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper"); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 779076f387..2792820a54 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -46,9 +46,7 @@ #include "ospf6_flood.h" #include "ospf6d.h" -#ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_lsa_clippy.c" -#endif DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header"); diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c index b1bff69f06..f35c9df4a5 100644 --- a/ospf6d/ospf6_nssa.c +++ b/ospf6d/ospf6_nssa.c @@ -49,9 +49,7 @@ #include "ospf6_asbr.h" #include "ospf6d.h" #include "ospf6_nssa.h" -#ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_nssa_clippy.c" -#endif DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA"); unsigned char config_debug_ospf6_nssa = 0; diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index fab0479d42..db94b85b1b 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -37,9 +37,7 @@ #include "ospf6_interface.h" #include "ospf6d.h" #include "ospf6_zebra.h" -#ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_route_clippy.c" -#endif DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE, "OSPF6 route"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE_TABLE, "OSPF6 route table"); diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index d48e85cedb..eb89a14cd3 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -65,9 +65,7 @@ FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES, { .val_bool = false }, ); -#ifndef VTYSH_EXTRACT_PL #include "ospf6d/ospf6_top_clippy.c" -#endif /* global ospf6d variable */ static struct ospf6_master ospf6_master; diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index cf863ff523..3dff03956c 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -5,27 +5,6 @@ if OSPF6D noinst_LIBRARIES += ospf6d/libospf6.a sbin_PROGRAMS += ospf6d/ospf6d -vtysh_scan += \ - ospf6d/ospf6_nssa.c \ - ospf6d/ospf6_abr.c \ - ospf6d/ospf6_asbr.c \ - ospf6d/ospf6_area.c \ - ospf6d/ospf6_bfd.c \ - ospf6d/ospf6_flood.c \ - ospf6d/ospf6_gr.c \ - ospf6d/ospf6_gr_helper.c \ - ospf6d/ospf6_interface.c \ - ospf6d/ospf6_intra.c \ - ospf6d/ospf6_lsa.c \ - ospf6d/ospf6_message.c \ - ospf6d/ospf6_neighbor.c \ - ospf6d/ospf6_route.c \ - ospf6d/ospf6_spf.c \ - ospf6d/ospf6_top.c \ - ospf6d/ospf6_zebra.c \ - ospf6d/ospf6d.c \ - ospf6d/ospf6_auth_trailer.c \ - # end vtysh_daemons += ospf6d if SNMP module_LTLIBRARIES += ospf6d/ospf6d_snmp.la diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 59f95c5da2..a47ed8d67a 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -42,9 +42,7 @@ #include "ospfd/ospf_dump.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_network.h" -#ifndef VTYSH_EXTRACT_PL #include "ospfd/ospf_dump_clippy.c" -#endif /* Configuration debug option variables. */ unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0}; diff --git a/ospfd/ospf_gr.c b/ospfd/ospf_gr.c index 66ef1d6564..6678d8c1f3 100644 --- a/ospfd/ospf_gr.c +++ b/ospfd/ospf_gr.c @@ -44,9 +44,7 @@ #include "ospfd/ospf_gr.h" #include "ospfd/ospf_errors.h" #include "ospfd/ospf_dump.h" -#ifndef VTYSH_EXTRACT_PL #include "ospfd/ospf_gr_clippy.c" -#endif static void ospf_gr_nvm_delete(struct ospf *ospf); diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index 77e96f1733..7b1fa6626f 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -751,9 +751,7 @@ void ospf_ldp_sync_if_write_config(struct vty *vty, /* * LDP-SYNC commands. */ -#ifndef VTYSH_EXTRACT_PL #include "ospfd/ospf_ldp_sync_clippy.c" -#endif DEFPY (ospf_mpls_ldp_sync, ospf_mpls_ldp_sync_cmd, diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 76dbc94c16..52a8dde1b5 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -185,9 +185,7 @@ static void ospf_show_vrf_name(struct ospf *ospf, struct vty *vty, } } -#ifndef VTYSH_EXTRACT_PL #include "ospfd/ospf_vty_clippy.c" -#endif DEFUN_NOSH (router_ospf, router_ospf_cmd, diff --git a/ospfd/subdir.am b/ospfd/subdir.am index 78688fac95..b67f942883 100644 --- a/ospfd/subdir.am +++ b/ospfd/subdir.am @@ -5,18 +5,6 @@ if OSPFD noinst_LIBRARIES += ospfd/libfrrospf.a sbin_PROGRAMS += ospfd/ospfd -vtysh_scan += \ - ospfd/ospf_bfd.c \ - ospfd/ospf_dump.c \ - ospfd/ospf_gr.c \ - ospfd/ospf_ldp_sync.c \ - ospfd/ospf_opaque.c \ - ospfd/ospf_ri.c \ - ospfd/ospf_routemap.c \ - ospfd/ospf_te.c \ - ospfd/ospf_sr.c \ - ospfd/ospf_vty.c \ - # end vtysh_daemons += ospfd if SNMP module_LTLIBRARIES += ospfd/ospfd_snmp.la diff --git a/pathd/path_cli.c b/pathd/path_cli.c index 13e52ac86b..a6540cc84a 100644 --- a/pathd/path_cli.c +++ b/pathd/path_cli.c @@ -31,9 +31,7 @@ #include "pathd/pathd.h" #include "pathd/path_nb.h" -#ifndef VTYSH_EXTRACT_PL #include "pathd/path_cli_clippy.c" -#endif #include "pathd/path_ted.h" #define XPATH_MAXATTRSIZE 64 diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c index d2b49a7d95..0f259f1dc7 100644 --- a/pathd/path_pcep_cli.c +++ b/pathd/path_pcep_cli.c @@ -40,9 +40,7 @@ #include "pathd/path_pcep_lib.h" #include "pathd/path_pcep_pcc.h" -#ifndef VTYSH_EXTRACT_PL #include "pathd/path_pcep_cli_clippy.c" -#endif #define DEFAULT_PCE_PRECEDENCE 255 #define DEFAULT_PCC_MSD 4 diff --git a/pathd/path_ted.c b/pathd/path_ted.c index bb04d285c9..68748af53e 100644 --- a/pathd/path_ted.c +++ b/pathd/path_ted.c @@ -29,9 +29,7 @@ #include "pathd/path_errors.h" #include "pathd/path_ted.h" -#ifndef VTYSH_EXTRACT_PL #include "pathd/path_ted_clippy.c" -#endif static struct ls_ted *path_ted_create_ted(void); static void path_ted_register_vty(void); diff --git a/pathd/subdir.am b/pathd/subdir.am index f339c79225..29be8f463d 100644 --- a/pathd/subdir.am +++ b/pathd/subdir.am @@ -5,16 +5,11 @@ if PATHD noinst_LIBRARIES += pathd/libpath.a sbin_PROGRAMS += pathd/pathd -vtysh_scan += \ - pathd/path_cli.c \ - pathd/path_ted.c \ - #end vtysh_daemons += pathd # TODO add man page #man8 += $(MANBUILD)/pathd.8 if PATHD_PCEP -vtysh_scan += pathd/path_pcep_cli.c module_LTLIBRARIES += pathd/pathd_pcep.la endif diff --git a/pbrd/pbr_debug.c b/pbrd/pbr_debug.c index 82f045c462..99489777eb 100644 --- a/pbrd/pbr_debug.c +++ b/pbrd/pbr_debug.c @@ -23,9 +23,7 @@ #include "command.h" #include "vector.h" -#ifndef VTYSH_EXTRACT_PL #include "pbrd/pbr_debug_clippy.c" -#endif #include "pbrd/pbr_debug.h" struct debug pbr_dbg_map = {0, "PBR map"}; diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index 6f53adb334..e8e5981ec5 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -36,9 +36,7 @@ #include "pbrd/pbr_zebra.h" #include "pbrd/pbr_vty.h" #include "pbrd/pbr_debug.h" -#ifndef VTYSH_EXTRACT_PL #include "pbrd/pbr_vty_clippy.c" -#endif DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)", "Create pbr-map or enter pbr-map command mode\n" diff --git a/pbrd/subdir.am b/pbrd/subdir.am index bbe3f2ab71..8a3bf31bf6 100644 --- a/pbrd/subdir.am +++ b/pbrd/subdir.am @@ -5,10 +5,6 @@ if PBRD noinst_LIBRARIES += pbrd/libpbr.a sbin_PROGRAMS += pbrd/pbrd -vtysh_scan += \ - pbrd/pbr_vty.c \ - pbrd/pbr_debug.c \ - # end vtysh_daemons += pbrd man8 += $(MANBUILD)/frr-pbrd.8 endif diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index ae272bbb92..bd6d229476 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -45,9 +45,7 @@ #include "pim_zebra.h" #include "pim_instance.h" -#ifndef VTYSH_EXTRACT_PL #include "pimd/pim6_cmd_clippy.c" -#endif static struct cmd_node debug_node = { .name = "debug", diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c index c34c782969..dc5e67e2c5 100644 --- a/pimd/pim6_mld.c +++ b/pimd/pim6_mld.c @@ -2319,9 +2319,7 @@ void gm_ifp_update(struct interface *ifp) #include "lib/command.h" -#ifndef VTYSH_EXTRACT_PL #include "pimd/pim6_mld_clippy.c" -#endif static struct vrf *gm_cmd_vrf_lookup(struct vty *vty, const char *vrf_str, int *err) diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index efa1382fc0..306891c0e0 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -70,9 +70,7 @@ #include "pim_addr.h" #include "pim_cmd_common.h" -#ifndef VTYSH_EXTRACT_PL #include "pimd/pim_cmd_clippy.c" -#endif static struct cmd_node debug_node = { .name = "debug", diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h index d6798c52ad..c409b9ed0a 100644 --- a/pimd/pim_mroute.h +++ b/pimd/pim_mroute.h @@ -39,10 +39,8 @@ #if defined(HAVE_LINUX_MROUTE_H) #include #else -#ifndef VTYSH_EXTRACT_PL #include "linux/mroute.h" #endif -#endif typedef struct vifctl pim_vifctl; typedef struct igmpmsg kernmsg; @@ -86,10 +84,8 @@ typedef struct sioc_sg_req pim_sioc_sg_req; #if defined(HAVE_LINUX_MROUTE6_H) #include #else -#ifndef VTYSH_EXTRACT_PL #include "linux/mroute6.h" #endif -#endif #ifndef MRT_INIT #define MRT_BASE MRT6_BASE diff --git a/pimd/subdir.am b/pimd/subdir.am index 54292bba24..fd7255cb87 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -6,11 +6,6 @@ if PIMD sbin_PROGRAMS += pimd/pimd bin_PROGRAMS += pimd/mtracebis noinst_PROGRAMS += pimd/test_igmpv3_join -vtysh_scan += \ - pimd/pim_cmd.c \ - pimd/pim6_cmd.c \ - pimd/pim6_mld.c \ - #end vtysh_daemons += pimd vtysh_daemons += pim6d man8 += $(MANBUILD)/frr-pimd.8 diff --git a/python/callgraph-dot.py b/python/callgraph-dot.py index f80766a080..7d9825bd10 100644 --- a/python/callgraph-dot.py +++ b/python/callgraph-dot.py @@ -321,15 +321,31 @@ extra_info = { "lsp_processq_complete", ], # zebra - main WQ - ("mq_add_handler", "work_queue_add"): ["meta_queue_process",], - ("meta_queue_process", "work_queue_add"): ["meta_queue_process",], + ("mq_add_handler", "work_queue_add"): [ + "meta_queue_process", + ], + ("meta_queue_process", "work_queue_add"): [ + "meta_queue_process", + ], # bgpd - label pool WQ - ("bgp_lp_get", "work_queue_add"): ["lp_cbq_docallback",], - ("bgp_lp_event_chunk", "work_queue_add"): ["lp_cbq_docallback",], - ("bgp_lp_event_zebra_up", "work_queue_add"): ["lp_cbq_docallback",], + ("bgp_lp_get", "work_queue_add"): [ + "lp_cbq_docallback", + ], + ("bgp_lp_event_chunk", "work_queue_add"): [ + "lp_cbq_docallback", + ], + ("bgp_lp_event_zebra_up", "work_queue_add"): [ + "lp_cbq_docallback", + ], # bgpd - main WQ - ("bgp_process", "work_queue_add"): ["bgp_process_wq", "bgp_processq_del",], - ("bgp_add_eoiu_mark", "work_queue_add"): ["bgp_process_wq", "bgp_processq_del",], + ("bgp_process", "work_queue_add"): [ + "bgp_process_wq", + "bgp_processq_del", + ], + ("bgp_add_eoiu_mark", "work_queue_add"): [ + "bgp_process_wq", + "bgp_processq_del", + ], # clear node WQ ("bgp_clear_route_table", "work_queue_add"): [ "bgp_clear_route_node", @@ -337,7 +353,9 @@ extra_info = { "bgp_clear_node_complete", ], # rfapi WQs - ("rfapi_close", "work_queue_add"): ["rfapi_deferred_close_workfunc",], + ("rfapi_close", "work_queue_add"): [ + "rfapi_deferred_close_workfunc", + ], ("rfapiRibUpdatePendingNode", "work_queue_add"): [ "rfapiRibDoQueuedCallback", "rfapiRibQueueItemDelete", diff --git a/python/clippy/__init__.py b/python/clippy/__init__.py index 281e2bb3c6..7c73598e5d 100644 --- a/python/clippy/__init__.py +++ b/python/clippy/__init__.py @@ -36,7 +36,10 @@ from _clippy import ( ) -frr_top_src = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) +frr_top_src = os.path.dirname( + os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +) + def graph_iterate(graph): """iterator yielding all nodes of a graph diff --git a/python/clippy/elf.py b/python/clippy/elf.py index 02cb2e38b3..d4d1f4cb8b 100644 --- a/python/clippy/elf.py +++ b/python/clippy/elf.py @@ -16,7 +16,7 @@ # with this program; see the file COPYING; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -''' +""" Wrapping layer and additional utility around _clippy.ELFFile. Essentially, the C bits have the low-level ELF access bits that should be @@ -28,7 +28,7 @@ across architecture, word size and even endianness boundaries. Both the C module (through GElf_*) and this code (cf. struct.unpack format mangling in ELFDissectStruct) will take appropriate measures to flip and resize fields as needed. -''' +""" import struct from collections import OrderedDict @@ -40,16 +40,18 @@ from _clippy import ELFFile, ELFAccessError # data access # + class ELFNull(object): - ''' + """ NULL pointer, returned instead of ELFData - ''' + """ + def __init__(self): self.symname = None self._dstsect = None def __repr__(self): - return '' + return "" def __hash__(self): return hash(None) @@ -57,33 +59,37 @@ class ELFNull(object): def get_string(self): return None + class ELFUnresolved(object): - ''' + """ Reference to an unresolved external symbol, returned instead of ELFData :param symname: name of the referenced symbol :param addend: offset added to the symbol, normally zero - ''' + """ + def __init__(self, symname, addend): self.addend = addend self.symname = symname self._dstsect = None def __repr__(self): - return '' % (self.symname, self.addend) + return "" % (self.symname, self.addend) def __hash__(self): return hash((self.symname, self.addend)) + class ELFData(object): - ''' + """ Actual data somewhere in the ELF file. :type dstsect: ELFSubset :param dstsect: container data area (section or entire file) :param dstoffs: byte offset into dstsect :param dstlen: byte size of object, or None if unknown, open-ended or string - ''' + """ + def __init__(self, dstsect, dstoffs, dstlen): self._dstsect = dstsect self._dstoffs = dstoffs @@ -91,62 +97,78 @@ class ELFData(object): self.symname = None def __repr__(self): - return '' % (self._dstsect.name, self._dstoffs, self._dstlen or -1) + return "" % ( + self._dstsect.name, + self._dstoffs, + self._dstlen or -1, + ) def __hash__(self): return hash((self._dstsect, self._dstoffs)) def get_string(self): - ''' + """ Interpret as C string / null terminated UTF-8 and get the actual text. - ''' + """ try: - return self._dstsect[self._dstoffs:str].decode('UTF-8') + return self._dstsect[self._dstoffs : str].decode("UTF-8") except: - import pdb; pdb.set_trace() + import pdb + + pdb.set_trace() def get_data(self, reflen): - ''' + """ Interpret as some structure (and check vs. expected length) :param reflen: expected size of the object, compared against actual size (which is only known in rare cases, mostly when directly accessing a symbol since symbols have their destination object size recorded) - ''' + """ if self._dstlen is not None and self._dstlen != reflen: - raise ValueError('symbol size mismatch (got %d, expected %d)' % (self._dstlen, reflen)) - return self._dstsect[self._dstoffs:self._dstoffs+reflen] + raise ValueError( + "symbol size mismatch (got %d, expected %d)" % (self._dstlen, reflen) + ) + return self._dstsect[self._dstoffs : self._dstoffs + reflen] def offset(self, offs, within_symbol=False): - ''' + """ Get another ELFData at an offset :param offs: byte offset, can be negative (e.g. in container_of) :param within_symbol: retain length information - ''' + """ if self._dstlen is None or not within_symbol: return ELFData(self._dstsect, self._dstoffs + offs, None) else: return ELFData(self._dstsect, self._dstoffs + offs, self._dstlen - offs) + # # dissection data items # + class ELFDissectData(object): - ''' + """ Common bits for ELFDissectStruct and ELFDissectUnion - ''' + """ + + def __init__(self): + self._data = None + self.elfclass = None def __len__(self): - ''' + """ Used for boolean evaluation, e.g. "if struct: ..." - ''' - return not (isinstance(self._data, ELFNull) or isinstance(self._data, ELFUnresolved)) + """ + return not ( + isinstance(self._data, ELFNull) or isinstance(self._data, ELFUnresolved) + ) def container_of(self, parent, fieldname): - ''' + """ Assume this struct is embedded in a larger struct and get at the larger Python ``self.container_of(a, b)`` = C ``container_of(self, a, b)`` @@ -154,25 +176,26 @@ class ELFDissectData(object): :param parent: class (not instance) of the larger struct :param fieldname: fieldname that refers back to this :returns: instance of parent, with fieldname set to this object - ''' + """ offset = 0 - if not hasattr(parent, '_efields'): + if not hasattr(parent, "_efields"): parent._setup_efields() for field in parent._efields[self.elfclass]: if field[0] == fieldname: break spec = field[1] - if spec == 'P': - spec = 'I' if self.elfclass == 32 else 'Q' + if spec == "P": + spec = "I" if self.elfclass == 32 else "Q" offset += struct.calcsize(spec) else: - raise AttributeError('%r not found in %r.fields' % (fieldname, parent)) + raise AttributeError("%r not found in %r.fields" % (fieldname, parent)) + + return parent(self._data.offset(-offset), replace={fieldname: self}) - return parent(self._data.offset(-offset), replace = {fieldname: self}) class ELFDissectStruct(ELFDissectData): - ''' + """ Decode and provide access to a struct somewhere in the ELF file Handles pointers and strings somewhat nicely. Create a subclass for each @@ -205,30 +228,31 @@ class ELFDissectStruct(ELFDissectData): .. attribute:: fieldrename Dictionary to rename fields, useful if fields comes from tiabwarfo.py. - ''' + """ class Pointer(object): - ''' + """ Quick wrapper for pointers to further structs This is just here to avoid going into infinite loops when loading structs that have pointers to each other (e.g. struct xref <--> struct xrefdata.) The pointer destination is only instantiated when actually accessed. - ''' + """ + def __init__(self, cls, ptr): self.cls = cls self.ptr = ptr def __repr__(self): - return '' % (self.cls.__name__, self.ptr) + return "" % (self.cls.__name__, self.ptr) def __call__(self): if isinstance(self.ptr, ELFNull): return None return self.cls(self.ptr) - def __new__(cls, dataptr, parent = None, replace = None): + def __new__(cls, dataptr, parent=None, replace=None): if dataptr._dstsect is None: return super().__new__(cls) @@ -239,19 +263,19 @@ class ELFDissectStruct(ELFDissectData): dataptr._dstsect._pointers[(cls, dataptr)] = obj return obj - replacements = 'lLnN' + replacements = "lLnN" @classmethod def _preproc_structspec(cls, elfclass, spec): elfbits = elfclass - if hasattr(spec, 'calcsize'): - spec = '%ds' % (spec.calcsize(elfclass),) + if hasattr(spec, "calcsize"): + spec = "%ds" % (spec.calcsize(elfclass),) if elfbits == 32: - repl = ['i', 'I'] + repl = ["i", "I"] else: - repl = ['q', 'Q'] + repl = ["q", "Q"] for c in cls.replacements: spec = spec.replace(c, repl[int(c.isupper())]) return spec @@ -269,8 +293,8 @@ class ELFDissectStruct(ELFDissectData): size += struct.calcsize(newf[1]) cls._esize[elfclass] = size - def __init__(self, dataptr, parent = None, replace = None): - if not hasattr(self.__class__, '_efields'): + def __init__(self, dataptr, parent=None, replace=None): + if not hasattr(self.__class__, "_efields"): self._setup_efields() self._fdata = None @@ -290,12 +314,12 @@ class ELFDissectStruct(ELFDissectData): # need to correlate output from struct.unpack with extra metadata # about the particular fields, so note down byte offsets (in locs) # and tuple indices of pointers (in ptrs) - pspec = '' + pspec = "" locs = {} ptrs = set() for idx, spec in enumerate(pspecl): - if spec == 'P': + if spec == "P": ptrs.add(idx) spec = self._elfsect.ptrtype @@ -326,7 +350,9 @@ class ELFDissectStruct(ELFDissectData): self._fdata[name] = replace[name] continue - if isinstance(self.fields[i][1], type) and issubclass(self.fields[i][1], ELFDissectData): + if isinstance(self.fields[i][1], type) and issubclass( + self.fields[i][1], ELFDissectData + ): dataobj = self.fields[i][1](dataptr.offset(locs[i]), self) self._fdata[name] = dataobj continue @@ -353,35 +379,41 @@ class ELFDissectStruct(ELFDissectData): def __repr__(self): if not isinstance(self._data, ELFData): - return '<%s: %r>' % (self.__class__.__name__, self._data) - return '<%s: %s>' % (self.__class__.__name__, - ', '.join(['%s=%r' % t for t in self._fdata.items()])) + return "<%s: %r>" % (self.__class__.__name__, self._data) + return "<%s: %s>" % ( + self.__class__.__name__, + ", ".join(["%s=%r" % t for t in self._fdata.items()]), + ) @classmethod def calcsize(cls, elfclass): - ''' + """ Sum up byte size of this struct Wraps struct.calcsize with some extra features. - ''' - if not hasattr(cls, '_efields'): + """ + if not hasattr(cls, "_efields"): cls._setup_efields() - pspec = ''.join([f[1] for f in cls._efields[elfclass]]) + pspec = "".join([f[1] for f in cls._efields[elfclass]]) - ptrtype = 'I' if elfclass == 32 else 'Q' - pspec = pspec.replace('P', ptrtype) + ptrtype = "I" if elfclass == 32 else "Q" + pspec = pspec.replace("P", ptrtype) return struct.calcsize(pspec) + class ELFDissectUnion(ELFDissectData): - ''' + """ Decode multiple structs in the same place. Not currently used (and hence not tested.) Worked at some point but not needed anymore and may be borked now. Remove this comment when using. - ''' - def __init__(self, dataptr, parent = None): + """ + + members = {} + + def __init__(self, dataptr, parent=None): self._dataptr = dataptr self._parent = parent self.members = [] @@ -391,31 +423,44 @@ class ELFDissectUnion(ELFDissectData): setattr(self, name, item) def __repr__(self): - return '<%s: %s>' % (self.__class__.__name__, ', '.join([repr(i) for i in self.members])) + return "<%s: %s>" % ( + self.__class__.__name__, + ", ".join([repr(i) for i in self.members]), + ) @classmethod def calcsize(cls, elfclass): return max([member.calcsize(elfclass) for name, member in cls.members]) + # # wrappers for spans of ELF data # + class ELFSubset(object): - ''' + """ Common abstract base for section-level and file-level access. - ''' + """ def __init__(self): super().__init__() + self.name = None + self._obj = None + self._elffile = None + self.ptrtype = None + self.endian = None self._pointers = WeakValueDictionary() + def _wrap_data(self, data, dstsect): + raise NotImplementedError() + def __hash__(self): return hash(self.name) def __getitem__(self, k): - ''' + """ Read data from slice Subscript **must** be a slice; a simple index will not return a byte @@ -425,22 +470,22 @@ class ELFSubset(object): - `this[123:456]` - extract specific range - `this[123:str]` - extract until null byte. The slice stop value is the `str` type (or, technically, `unicode`.) - ''' + """ return self._obj[k] def getreloc(self, offset): - ''' + """ Check for a relocation record at the specified offset. - ''' + """ return self._obj.getreloc(offset) - def iter_data(self, scls, slice_ = slice(None)): - ''' + def iter_data(self, scls, slice_=slice(None)): + """ Assume an array of structs present at a particular slice and decode :param scls: ELFDissectData subclass for the struct :param slice_: optional range specification - ''' + """ size = scls.calcsize(self._elffile.elfclass) offset = slice_.start or 0 @@ -453,7 +498,7 @@ class ELFSubset(object): offset += size def pointer(self, offset): - ''' + """ Try to dereference a pointer value This checks whether there's a relocation at the given offset and @@ -463,10 +508,12 @@ class ELFSubset(object): :param offset: byte offset from beginning of section, or virtual address in file :returns: ELFData wrapping pointed-to object - ''' + """ ptrsize = struct.calcsize(self.ptrtype) - data = struct.unpack(self.endian + self.ptrtype, self[offset:offset + ptrsize])[0] + data = struct.unpack( + self.endian + self.ptrtype, self[offset : offset + ptrsize] + )[0] reloc = self.getreloc(offset) dstsect = None @@ -497,14 +544,15 @@ class ELFSubset(object): # wrap_data is different between file & section return self._wrap_data(data, dstsect) + class ELFDissectSection(ELFSubset): - ''' + """ Access the contents of an ELF section like ``.text`` or ``.data`` :param elfwrap: ELFDissectFile wrapper for the file :param idx: section index in section header table :param section: section object from C module - ''' + """ def __init__(self, elfwrap, idx, section): super().__init__() @@ -524,8 +572,9 @@ class ELFDissectSection(ELFSubset): dstsect = self._elfwrap.get_section(dstsect.idx) return ELFData(dstsect, offs, None) + class ELFDissectFile(ELFSubset): - ''' + """ Access the contents of an ELF file. Note that offsets for array subscript and relocation/pointer access are @@ -537,7 +586,7 @@ class ELFDissectFile(ELFSubset): address like 0x400000 on x86. :param filename: ELF file to open - ''' + """ def __init__(self, filename): super().__init__() @@ -546,8 +595,8 @@ class ELFDissectFile(ELFSubset): self._elffile = self._obj = ELFFile(filename) self._sections = {} - self.ptrtype = 'I' if self._elffile.elfclass == 32 else 'Q' - self.endian = '>' if self._elffile.bigendian else '<' + self.ptrtype = "I" if self._elffile.elfclass == 32 else "Q" + self.endian = ">" if self._elffile.bigendian else "<" @property def _elfwrap(self): @@ -557,9 +606,9 @@ class ELFDissectFile(ELFSubset): return ELFData(self, data, None) def get_section(self, secname): - ''' + """ Look up section by name or index - ''' + """ if isinstance(secname, int): sh_idx = secname section = self._elffile.get_section_idx(secname) diff --git a/python/clippy/uidhash.py b/python/clippy/uidhash.py index bf994d389e..0fd886221a 100644 --- a/python/clippy/uidhash.py +++ b/python/clippy/uidhash.py @@ -19,13 +19,14 @@ import struct from hashlib import sha256 -def bititer(data, bits, startbit = True): - ''' + +def bititer(data, bits, startbit=True): + """ just iterate the individual bits out from a bytes object if startbit is True, an '1' bit is inserted at the very beginning goes at a time, starts at LSB. - ''' + """ bitavail, v = 0, 0 if startbit and len(data) > 0: v = data.pop(0) @@ -41,31 +42,33 @@ def bititer(data, bits, startbit = True): bitavail -= bits v >>= bits + def base32c(data): - ''' + """ Crockford base32 with extra dashes - ''' + """ chs = "0123456789ABCDEFGHJKMNPQRSTVWXYZ" - o = '' + o = "" if type(data) == str: data = [ord(v) for v in data] else: data = list(data) for i, bits in enumerate(bititer(data, 5)): if i == 5: - o = o + '-' + o = o + "-" elif i == 10: break o = o + chs[bits] return o -def uidhash(filename, hashstr, hashu32a, hashu32b): - ''' - xref Unique ID hash used in FRRouting - ''' - filename = '/'.join(filename.rsplit('/')[-2:]) - hdata = filename.encode('UTF-8') + hashstr.encode('UTF-8') - hdata += struct.pack('>II', hashu32a, hashu32b) +def uidhash(filename, hashstr, hashu32a, hashu32b): + """ + xref Unique ID hash used in FRRouting + """ + filename = "/".join(filename.rsplit("/")[-2:]) + + hdata = filename.encode("UTF-8") + hashstr.encode("UTF-8") + hdata += struct.pack(">II", hashu32a, hashu32b) i = sha256(hdata).digest() return base32c(i) diff --git a/python/makefile.py b/python/makefile.py index bd897b7508..573871fb68 100644 --- a/python/makefile.py +++ b/python/makefile.py @@ -161,7 +161,15 @@ for clippy_file in clippy_scan: # combine daemon .xref files into frr.xref out_lines.append("") xref_targets = [ - target for target in xref_targets if target not in ["tools/ssd", "vtysh/vtysh"] + target + for target in xref_targets + if target + not in [ + "bgpd/rfp-example/rfptest/rfptest", + "pimd/mtracebis", + "tools/ssd", + "vtysh/vtysh", + ] ] out_lines.append( "xrefs = %s" % (" ".join(["%s.xref" % target for target in xref_targets])) diff --git a/python/runtests.py b/python/runtests.py index bcf650b329..70deaa35d0 100644 --- a/python/runtests.py +++ b/python/runtests.py @@ -5,9 +5,11 @@ import os try: import _clippy except ImportError: - sys.stderr.write('''these tests need to be run with the _clippy C extension + sys.stderr.write( + """these tests need to be run with the _clippy C extension module available. Try running "clippy runtests.py ...". -''') +""" + ) sys.exit(1) os.chdir(os.path.dirname(os.path.abspath(__file__))) diff --git a/python/test_xrelfo.py b/python/test_xrelfo.py index 3ae24ea7b3..3379959dc1 100644 --- a/python/test_xrelfo.py +++ b/python/test_xrelfo.py @@ -22,20 +22,21 @@ import pytest from pprint import pprint root = os.path.dirname(os.path.dirname(__file__)) -sys.path.append(os.path.join(root, 'python')) +sys.path.append(os.path.join(root, "python")) import xrelfo from clippy import elf, uidhash + def test_uidhash(): - assert uidhash.uidhash("lib/test_xref.c", "logging call", 3, 0) \ - == 'H7KJB-67TBH' + assert uidhash.uidhash("lib/test_xref.c", "logging call", 3, 0) == "H7KJB-67TBH" + def test_xrelfo_other(): for data in [ - elf.ELFNull(), - elf.ELFUnresolved('somesym', 0), - ]: + elf.ELFNull(), + elf.ELFUnresolved("somesym", 0), + ]: dissect = xrelfo.XrefPtr(data) print(repr(dissect)) @@ -43,9 +44,10 @@ def test_xrelfo_other(): with pytest.raises(AttributeError): dissect.xref + def test_xrelfo_obj(): xrelfo_ = xrelfo.Xrelfo() - edf = xrelfo_.load_elf(os.path.join(root, 'lib/.libs/zclient.o'), 'zclient.lo') + edf = xrelfo_.load_elf(os.path.join(root, "lib/.libs/zclient.o"), "zclient.lo") xrefs = xrelfo_._xrefs with pytest.raises(elf.ELFAccessError): @@ -54,12 +56,13 @@ def test_xrelfo_obj(): pprint(xrefs[0]) pprint(xrefs[0]._data) + def test_xrelfo_bin(): xrelfo_ = xrelfo.Xrelfo() - edf = xrelfo_.load_elf(os.path.join(root, 'lib/.libs/libfrr.so'), 'libfrr.la') + edf = xrelfo_.load_elf(os.path.join(root, "lib/.libs/libfrr.so"), "libfrr.la") xrefs = xrelfo_._xrefs - assert edf[0:4] == b'\x7fELF' + assert edf[0:4] == b"\x7fELF" pprint(xrefs[0]) pprint(xrefs[0]._data) diff --git a/python/tiabwarfo.py b/python/tiabwarfo.py index 4a6cd6ad77..b19c756738 100644 --- a/python/tiabwarfo.py +++ b/python/tiabwarfo.py @@ -23,10 +23,19 @@ import re import argparse import json -structs = ['xref', 'xref_logmsg', 'xref_threadsched', 'xref_install_element', 'xrefdata', 'xrefdata_logmsg', 'cmd_element'] +structs = [ + "xref", + "xref_logmsg", + "xref_threadsched", + "xref_install_element", + "xrefdata", + "xrefdata_logmsg", + "cmd_element", +] -def extract(filename='lib/.libs/libfrr.so'): - ''' + +def extract(filename="lib/.libs/libfrr.so"): + """ Convert output from "pahole" to JSON. Example pahole output: @@ -41,26 +50,30 @@ def extract(filename='lib/.libs/libfrr.so'): /* size: 32, cachelines: 1, members: 5 */ /* last cacheline: 32 bytes */ }; - ''' - pahole = subprocess.check_output(['pahole', '-C', ','.join(structs), filename]).decode('UTF-8') + """ + pahole = subprocess.check_output( + ["pahole", "-C", ",".join(structs), filename] + ).decode("UTF-8") - struct_re = re.compile(r'^struct ([^ ]+) \{([^\}]+)};', flags=re.M | re.S) - field_re = re.compile(r'^\s*(?P[^;\(]+)\s+(?P[^;\[\]]+)(?:\[(?P\d+)\])?;\s*\/\*(?P.*)\*\/\s*$') - comment_re = re.compile(r'^\s*\/\*.*\*\/\s*$') + struct_re = re.compile(r"^struct ([^ ]+) \{([^\}]+)};", flags=re.M | re.S) + field_re = re.compile( + r"^\s*(?P[^;\(]+)\s+(?P[^;\[\]]+)(?:\[(?P\d+)\])?;\s*\/\*(?P.*)\*\/\s*$" + ) + comment_re = re.compile(r"^\s*\/\*.*\*\/\s*$") pastructs = struct_re.findall(pahole) out = {} for sname, data in pastructs: this = out.setdefault(sname, {}) - fields = this.setdefault('fields', []) + fields = this.setdefault("fields", []) lines = data.strip().splitlines() next_offs = 0 for line in lines: - if line.strip() == '': + if line.strip() == "": continue m = comment_re.match(line) if m is not None: @@ -68,51 +81,55 @@ def extract(filename='lib/.libs/libfrr.so'): m = field_re.match(line) if m is not None: - offs, size = m.group('comment').strip().split() + offs, size = m.group("comment").strip().split() offs = int(offs) size = int(size) - typ_ = m.group('type').strip() - name = m.group('name') + typ_ = m.group("type").strip() + name = m.group("name") - if name.startswith('(*'): + if name.startswith("(*"): # function pointer - typ_ = typ_ + ' *' - name = name[2:].split(')')[0] + typ_ = typ_ + " *" + name = name[2:].split(")")[0] data = { - 'name': name, - 'type': typ_, - # 'offset': offs, - # 'size': size, + "name": name, + "type": typ_, + # 'offset': offs, + # 'size': size, } - if m.group('array'): - data['array'] = int(m.group('array')) + if m.group("array"): + data["array"] = int(m.group("array")) fields.append(data) if offs != next_offs: - raise ValueError('%d padding bytes before struct %s.%s' % (offs - next_offs, sname, name)) + raise ValueError( + "%d padding bytes before struct %s.%s" + % (offs - next_offs, sname, name) + ) next_offs = offs + size continue - raise ValueError('cannot process line: %s' % line) + raise ValueError("cannot process line: %s" % line) return out + class FieldApplicator(object): - ''' + """ Fill ELFDissectStruct fields list from pahole/JSON Uses the JSON file created by the above code to fill in the struct fields in subclasses of ELFDissectStruct. - ''' + """ # only what we really need. add more as needed. packtypes = { - 'int': 'i', - 'uint8_t': 'B', - 'uint16_t': 'H', - 'uint32_t': 'I', - 'char': 's', + "int": "i", + "uint8_t": "B", + "uint16_t": "H", + "uint32_t": "I", + "char": "s", } def __init__(self, data): @@ -126,60 +143,65 @@ class FieldApplicator(object): def resolve(self, cls): out = [] - #offset = 0 + # offset = 0 + + fieldrename = getattr(cls, "fieldrename", {}) - fieldrename = getattr(cls, 'fieldrename', {}) def mkname(n): return (fieldrename.get(n, n),) - for field in self.data[cls.struct]['fields']: - typs = field['type'].split() - typs = [i for i in typs if i not in ['const']] + for field in self.data[cls.struct]["fields"]: + typs = field["type"].split() + typs = [i for i in typs if i not in ["const"]] # this will break reuse of xrefstructs.json across 32bit & 64bit # platforms - #if field['offset'] != offset: + # if field['offset'] != offset: # assert offset < field['offset'] # out.append(('_pad', '%ds' % (field['offset'] - offset,))) # pretty hacky C types handling, but covers what we need ptrlevel = 0 - while typs[-1] == '*': + while typs[-1] == "*": typs.pop(-1) ptrlevel += 1 if ptrlevel > 0: - packtype = ('P', None) + packtype = ("P", None) if ptrlevel == 1: - if typs[0] == 'char': - packtype = ('P', str) - elif typs[0] == 'struct' and typs[1] in self.clsmap: - packtype = ('P', self.clsmap[typs[1]]) - elif typs[0] == 'enum': - packtype = ('I',) + if typs[0] == "char": + packtype = ("P", str) + elif typs[0] == "struct" and typs[1] in self.clsmap: + packtype = ("P", self.clsmap[typs[1]]) + elif typs[0] == "enum": + packtype = ("I",) elif typs[0] in self.packtypes: packtype = (self.packtypes[typs[0]],) - elif typs[0] == 'struct': + elif typs[0] == "struct": if typs[1] in self.clsmap: packtype = (self.clsmap[typs[1]],) else: - raise ValueError('embedded struct %s not in extracted data' % (typs[1],)) + raise ValueError( + "embedded struct %s not in extracted data" % (typs[1],) + ) else: - raise ValueError('cannot decode field %s in struct %s (%s)' % ( - cls.struct, field['name'], field['type'])) + raise ValueError( + "cannot decode field %s in struct %s (%s)" + % (cls.struct, field["name"], field["type"]) + ) - if 'array' in field and typs[0] == 'char': - packtype = ('%ds' % field['array'],) - out.append(mkname(field['name']) + packtype) - elif 'array' in field: - for i in range(0, field['array']): - out.append(mkname('%s_%d' % (field['name'], i)) + packtype) + if "array" in field and typs[0] == "char": + packtype = ("%ds" % field["array"],) + out.append(mkname(field["name"]) + packtype) + elif "array" in field: + for i in range(0, field["array"]): + out.append(mkname("%s_%d" % (field["name"], i)) + packtype) else: - out.append(mkname(field['name']) + packtype) + out.append(mkname(field["name"]) + packtype) - #offset = field['offset'] + field['size'] + # offset = field['offset'] + field['size'] cls.fields = out @@ -187,16 +209,30 @@ class FieldApplicator(object): for cls in self.classes: self.resolve(cls) + def main(): - argp = argparse.ArgumentParser(description = 'FRR DWARF structure extractor') - argp.add_argument('-o', dest='output', type=str, help='write JSON output', default='python/xrefstructs.json') - argp.add_argument('-i', dest='input', type=str, help='ELF file to read', default='lib/.libs/libfrr.so') + argp = argparse.ArgumentParser(description="FRR DWARF structure extractor") + argp.add_argument( + "-o", + dest="output", + type=str, + help="write JSON output", + default="python/xrefstructs.json", + ) + argp.add_argument( + "-i", + dest="input", + type=str, + help="ELF file to read", + default="lib/.libs/libfrr.so", + ) args = argp.parse_args() out = extract(args.input) - with open(args.output + '.tmp', 'w') as fd: + with open(args.output + ".tmp", "w") as fd: json.dump(out, fd, indent=2, sort_keys=True) - os.rename(args.output + '.tmp', args.output) + os.rename(args.output + ".tmp", args.output) -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/python/vtysh-cmd-check.py b/python/vtysh-cmd-check.py deleted file mode 100644 index ef9eea41ad..0000000000 --- a/python/vtysh-cmd-check.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/env python3 -# -# Quick demo program that checks whether files define commands that aren't -# in vtysh. Execute after building. -# -# This is free and unencumbered software released into the public domain. -# -# Anyone is free to copy, modify, publish, use, compile, sell, or -# distribute this software, either in source code form or as a compiled -# binary, for any purpose, commercial or non-commercial, and by any -# means. -# -# In jurisdictions that recognize copyright laws, the author or authors -# of this software dedicate any and all copyright interest in the -# software to the public domain. We make this dedication for the benefit -# of the public at large and to the detriment of our heirs and -# successors. We intend this dedication to be an overt act of -# relinquishment in perpetuity of all present and future rights to this -# software under copyright law. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -# OTHER DEALINGS IN THE SOFTWARE. -# -# For more information, please refer to - -import os -import json -import subprocess - -os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - -with open("frr.xref", "r") as fd: - data = json.load(fd) - -vtysh_scan, _ = subprocess.Popen( - ["make", "var-vtysh_scan"], stdout=subprocess.PIPE -).communicate() -vtysh_scan = set(vtysh_scan.decode("US-ASCII").split()) - -check = set() -vtysh = {} - -for cmd, defs in data["cli"].items(): - for binary, clidef in defs.items(): - if clidef["defun"]["file"].startswith("vtysh/"): - vtysh[clidef["string"]] = clidef - -for cmd, defs in data["cli"].items(): - for binary, clidef in defs.items(): - if clidef["defun"]["file"].startswith("vtysh/"): - continue - - if clidef["defun"]["file"] not in vtysh_scan: - vtysh_def = vtysh.get(clidef["string"]) - if vtysh_def is not None: - print( - "\033[33m%s defines %s, has a custom define in vtysh %s\033[m" - % (clidef["defun"]["file"], cmd, vtysh_def["defun"]["file"]) - ) - else: - print( - "\033[31m%s defines %s, not in vtysh_scan\033[m" - % (clidef["defun"]["file"], cmd) - ) - check.add(clidef["defun"]["file"]) - -print("\nfiles to check:\n\t" + " ".join(sorted(check))) diff --git a/python/xref2vtysh.py b/python/xref2vtysh.py new file mode 100644 index 0000000000..f18aa20c92 --- /dev/null +++ b/python/xref2vtysh.py @@ -0,0 +1,389 @@ +# FRR xref vtysh command extraction +# +# Copyright (C) 2022 David Lamparter for NetDEF, Inc. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation; either version 2 of the License, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; see the file COPYING; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +""" +Generate vtysh_cmd.c from frr .xref file(s). + +This can run either standalone or as part of xrelfo. The latter saves a +non-negligible amount of time (0.5s on average systems, more on e.g. slow ARMs) +since serializing and deserializing JSON is a significant bottleneck in this. +""" + +import sys +import os +import re +import pathlib +import argparse +from collections import defaultdict +import difflib + +import json + +try: + import ujson as json # type: ignore +except ImportError: + pass + +frr_top_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + +# vtysh needs to know which daemon(s) to send commands to. For lib/, this is +# not quite obvious... + +daemon_flags = { + "lib/agentx.c": "VTYSH_ISISD|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA", + "lib/filter.c": "VTYSH_ACL", + "lib/filter_cli.c": "VTYSH_ACL", + "lib/if.c": "VTYSH_INTERFACE", + "lib/keychain.c": "VTYSH_RIPD|VTYSH_EIGRPD|VTYSH_OSPF6D", + "lib/lib_vty.c": "VTYSH_ALL", + "lib/log_vty.c": "VTYSH_ALL", + "lib/nexthop_group.c": "VTYSH_NH_GROUP", + "lib/resolver.c": "VTYSH_NHRPD|VTYSH_BGPD", + "lib/routemap.c": "VTYSH_RMAP", + "lib/routemap_cli.c": "VTYSH_RMAP", + "lib/spf_backoff.c": "VTYSH_ISISD", + "lib/thread.c": "VTYSH_ALL", + "lib/vrf.c": "VTYSH_VRF", + "lib/vty.c": "VTYSH_ALL", +} + +vtysh_cmd_head = """/* autogenerated file, DO NOT EDIT! */ +#include + +#include "command.h" +#include "linklist.h" + +#include "vtysh/vtysh.h" +""" + +if sys.stderr.isatty(): + _fmt_red = "\033[31m" + _fmt_green = "\033[32m" + _fmt_clear = "\033[m" +else: + _fmt_red = _fmt_green = _fmt_clear = "" + + +def c_escape(text: str) -> str: + """ + Escape string for output into C source code. + + Handles only what's needed here. CLI strings and help text don't contain + weird special characters. + """ + return text.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n") + + +class NodeDict(defaultdict): + """ + CLI node ID (integer) -> dict of commands in that node. + """ + + nodenames = {} # Dict[int, str] + + def __init__(self): + super().__init__(dict) + + def items_named(self): + for k, v in self.items(): + yield self.nodename(k), v + + @classmethod + def nodename(cls, nodeid: int) -> str: + return cls.nodenames.get(nodeid, str(nodeid)) + + @classmethod + def load_nodenames(cls): + with open(os.path.join(frr_top_src, "lib", "command.h"), "r") as fd: + command_h = fd.read() + + nodes = re.search(r"enum\s+node_type\s+\{(.*?)\}", command_h, re.S) + if nodes is None: + raise RuntimeError( + "regex failed to match on lib/command.h (to get CLI node names)" + ) + + text = nodes.group(1) + text = re.sub(r"/\*.*?\*/", "", text, flags=re.S) + text = re.sub(r"//.*?$", "", text, flags=re.M) + text = text.replace(",", " ") + text = text.split() + + for i, name in enumerate(text): + cls.nodenames[i] = name + + +class CommandEntry: + """ + CLI command definition. + + - one DEFUN creates at most one of these, even if the same command is + installed in multiple CLI nodes (e.g. BGP address-family nodes) + - for each CLI node, commands with the same CLI string are merged. This + is *almost* irrelevant - ospfd & ospf6d define some identical commands + in the route-map node. Those must be merged for things to work + correctly. + """ + + all_defs = [] # List[CommandEntry] + warn_counter = 0 + + def __init__(self, origin, name, spec): + self.origin = origin + self.name = name + self._spec = spec + self._registered = False + + self.cmd = spec["string"] + self._cmd_normalized = self.normalize_cmd(self.cmd) + + self.hidden = "hidden" in spec.get("attrs", []) + self.daemons = self._get_daemons() + + self.doclines = self._spec["doc"].splitlines(keepends=True) + if not self.doclines[-1].endswith("\n"): + self.warn_loc("docstring does not end with \\n") + + def warn_loc(self, wtext, nodename=None): + """ + Print warning with parseable (compiler style) location + + Matching the way compilers emit file/lineno means editors/IDE can + identify / jump to the error location. + """ + + if nodename: + prefix = ": [%s] %s:" % (nodename, self.name) + else: + prefix = ": %s:" % (self.name,) + + for line in wtext.rstrip("\n").split("\n"): + sys.stderr.write( + "%s:%d%s %s\n" + % ( + self._spec["defun"]["file"], + self._spec["defun"]["line"], + prefix, + line, + ) + ) + prefix = "- " + + CommandEntry.warn_counter += 1 + + def _get_daemons(self): + path = pathlib.Path(self.origin) + if path.name == "vtysh": + return {} + + defun_file = os.path.relpath(self._spec["defun"]["file"], frr_top_src) + defun_path = pathlib.Path(defun_file) + + if defun_path.parts[0] != "lib": + if "." not in path.name: + # daemons don't have dots in their filename + return {"VTYSH_" + path.name.upper()} + + # loadable modules - use directory name to determine daemon + return {"VTYSH_" + path.parts[-2].upper()} + + if defun_file in daemon_flags: + return {daemon_flags[defun_file]} + + v6_cmd = "ipv6" in self.name + if defun_file == "lib/plist.c": + if v6_cmd: + return { + "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIM6D|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD" + } + else: + return { + "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD" + } + + if defun_file == "lib/if_rmap.c": + if v6_cmd: + return {"VTYSH_RIPNGD"} + else: + return {"VTYSH_RIPD"} + + return {} + + def __repr__(self): + return "" % (self.name, self.cmd) + + def register(self): + """Track DEFUNs so each is only output once.""" + if not self._registered: + self.all_defs.append(self) + self._registered = True + return self + + def merge(self, other, nodename): + if self._cmd_normalized != other._cmd_normalized: + self.warn_loc( + "command definition mismatch, first definied as:\n%r" % (self.cmd,), + nodename=nodename, + ) + other.warn_loc("later defined as:\n%r" % (other.cmd,), nodename=nodename) + + if self._spec["doc"] != other._spec["doc"]: + self.warn_loc( + "help string mismatch, first defined here (-)", nodename=nodename + ) + other.warn_loc( + "later defined here (+)\nnote: both commands define %r in same node (%s)" + % (self.cmd, nodename), + nodename=nodename, + ) + + d = difflib.Differ() + for diffline in d.compare(self.doclines, other.doclines): + if diffline.startswith(" "): + continue + if diffline.startswith("+ "): + diffline = _fmt_green + diffline + elif diffline.startswith("- "): + diffline = _fmt_red + diffline + sys.stderr.write("\t" + diffline.rstrip("\n") + _fmt_clear + "\n") + + if self.hidden != other.hidden: + self.warn_loc( + "hidden flag mismatch, first %r here" % (self.hidden,), + nodename=nodename, + ) + other.warn_loc( + "later %r here (+)\nnote: both commands define %r in same node (%s)" + % (other.hidden, self.cmd, nodename), + nodename=nodename, + ) + + # ensure name is deterministic regardless of input DEFUN order + self.name = min([self.name, other.name], key=lambda i: (len(i), i)) + self.daemons.update(other.daemons) + + def get_def(self): + doc = "\n".join(['\t"%s"' % c_escape(line) for line in self.doclines]) + defsh = "DEFSH_HIDDEN" if self.hidden else "DEFSH" + + # make daemon list deterministic + daemons = set() + for daemon in self.daemons: + daemons.update(daemon.split("|")) + daemon_str = "|".join(sorted(daemons)) + + return """ +%s (%s, %s_vtysh, +\t"%s", +%s) +""" % ( + defsh, + daemon_str, + self.name, + c_escape(self.cmd), + doc, + ) + + # accept slightly different command definitions that result in the same command + re_collapse_ws = re.compile(r"\s+") + re_remove_varnames = re.compile(r"\$[a-z][a-z0-9_]*") + + @classmethod + def normalize_cmd(cls, cmd): + cmd = cmd.strip() + cmd = cls.re_collapse_ws.sub(" ", cmd) + cmd = cls.re_remove_varnames.sub("", cmd) + return cmd + + @classmethod + def process(cls, nodes, name, origin, spec): + if "nosh" in spec.get("attrs", []): + return + if origin == "vtysh/vtysh": + return + + if origin == "isisd/fabricd": + # dirty workaround :( + name = "fabricd_" + name + + entry = cls(origin, name, spec) + if not entry.daemons: + return + + for nodedata in spec.get("nodes", []): + node = nodes[nodedata["node"]] + if entry._cmd_normalized not in node: + node[entry._cmd_normalized] = entry.register() + else: + node[entry._cmd_normalized].merge( + entry, nodes.nodename(nodedata["node"]) + ) + + @classmethod + def load(cls, xref): + nodes = NodeDict() + + for cmd_name, origins in xref.get("cli", {}).items(): + for origin, spec in origins.items(): + CommandEntry.process(nodes, cmd_name, origin, spec) + return nodes + + @classmethod + def output_defs(cls, ofd): + for entry in sorted(cls.all_defs, key=lambda i: i.name): + ofd.write(entry.get_def()) + + @classmethod + def output_install(cls, ofd, nodes): + ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + + for name, items in sorted(nodes.items_named()): + for item in sorted(items.values(), key=lambda i: i.name): + ofd.write("\tinstall_element(%s, &%s_vtysh);\n" % (name, item.name)) + + ofd.write("}\n") + + @classmethod + def run(cls, xref, ofd): + ofd.write(vtysh_cmd_head) + + NodeDict.load_nodenames() + nodes = cls.load(xref) + cls.output_defs(ofd) + cls.output_install(ofd, nodes) + + +def main(): + argp = argparse.ArgumentParser(description="FRR xref to vtysh defs") + argp.add_argument( + "xreffile", metavar="XREFFILE", type=str, help=".xref file to read" + ) + argp.add_argument("-Werror", action="store_const", const=True) + args = argp.parse_args() + + with open(args.xreffile, "r") as fd: + data = json.load(fd) + + CommandEntry.run(data, sys.stdout) + + if args.Werror and CommandEntry.warn_counter: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/python/xrelfo.py b/python/xrelfo.py index 09455ea9b4..c75b4cb956 100644 --- a/python/xrelfo.py +++ b/python/xrelfo.py @@ -37,15 +37,18 @@ from clippy.uidhash import uidhash from clippy.elf import * from clippy import frr_top_src, CmdAttr from tiabwarfo import FieldApplicator +from xref2vtysh import CommandEntry try: - with open(os.path.join(frr_top_src, 'python', 'xrefstructs.json'), 'r') as fd: + with open(os.path.join(frr_top_src, "python", "xrefstructs.json"), "r") as fd: xrefstructs = json.load(fd) except FileNotFoundError: - sys.stderr.write(''' + sys.stderr.write( + """ The "xrefstructs.json" file (created by running tiabwarfo.py with the pahole tool available) could not be found. It should be included with the sources. -''') +""" + ) sys.exit(1) # constants, need to be kept in sync manually... @@ -57,7 +60,7 @@ XREFT_INSTALL_ELEMENT = 0x301 # LOG_* priovals = {} -prios = ['0', '1', '2', 'E', 'W', 'N', 'I', 'D'] +prios = ["0", "1", "2", "E", "W", "N", "I", "D"] class XrelfoJson(object): @@ -70,9 +73,10 @@ class XrelfoJson(object): def to_dict(self, refs): pass + class Xref(ELFDissectStruct, XrelfoJson): - struct = 'xref' - fieldrename = {'type': 'typ'} + struct = "xref" + fieldrename = {"type": "typ"} containers = {} def __init__(self, *args, **kwargs): @@ -85,7 +89,7 @@ class Xref(ELFDissectStruct, XrelfoJson): def container(self): if self._container is None: if self.typ in self.containers: - self._container = self.container_of(self.containers[self.typ], 'xref') + self._container = self.container_of(self.containers[self.typ], "xref") return self._container def check(self, *args, **kwargs): @@ -94,10 +98,10 @@ class Xref(ELFDissectStruct, XrelfoJson): class Xrefdata(ELFDissectStruct): - struct = 'xrefdata' + struct = "xrefdata" # uid is all zeroes in the data loaded from ELF - fieldrename = {'uid': '_uid'} + fieldrename = {"uid": "_uid"} def ref_from(self, xref, typ): self.xref = xref @@ -108,38 +112,84 @@ class Xrefdata(ELFDissectStruct): return None return uidhash(self.xref.file, self.hashstr, self.hashu32_0, self.hashu32_1) + class XrefPtr(ELFDissectStruct): fields = [ - ('xref', 'P', Xref), + ("xref", "P", Xref), ] + class XrefThreadSched(ELFDissectStruct, XrelfoJson): - struct = 'xref_threadsched' + struct = "xref_threadsched" + + Xref.containers[XREFT_THREADSCHED] = XrefThreadSched + class XrefLogmsg(ELFDissectStruct, XrelfoJson): - struct = 'xref_logmsg' + struct = "xref_logmsg" def _warn_fmt(self, text): - lines = text.split('\n') - yield ((self.xref.file, self.xref.line), '%s:%d: %s (in %s())%s\n' % (self.xref.file, self.xref.line, lines[0], self.xref.func, ''.join(['\n' + l for l in lines[1:]]))) + lines = text.split("\n") + yield ( + (self.xref.file, self.xref.line), + "%s:%d: %s (in %s())%s\n" + % ( + self.xref.file, + self.xref.line, + lines[0], + self.xref.func, + "".join(["\n" + l for l in lines[1:]]), + ), + ) fmt_regexes = [ - (re.compile(r'([\n\t]+)'), 'error: log message contains tab or newline'), - # (re.compile(r'^(\s+)'), 'warning: log message starts with whitespace'), - (re.compile(r'^((?:warn(?:ing)?|error):\s*)', re.I), 'warning: log message starts with severity'), + (re.compile(r"([\n\t]+)"), "error: log message contains tab or newline"), + # (re.compile(r'^(\s+)'), 'warning: log message starts with whitespace'), + ( + re.compile(r"^((?:warn(?:ing)?|error):\s*)", re.I), + "warning: log message starts with severity", + ), ] arg_regexes = [ - # the (?' if edf._elffile.bigendian else '<' + endian = ">" if edf._elffile.bigendian else "<" mem = edf._elffile[note] if edf._elffile.elfclass == 64: - start, end = struct.unpack(endian + 'QQ', mem) + start, end = struct.unpack(endian + "QQ", mem) start += note.start end += note.start + 8 else: - start, end = struct.unpack(endian + 'II', mem) + start, end = struct.unpack(endian + "II", mem) start += note.start end += note.start + 4 ptrs = edf.iter_data(XrefPtr, slice(start, end)) else: - xrefarray = edf.get_section('xref_array') + xrefarray = edf.get_section("xref_array") if xrefarray is None: - raise ValueError('file has neither xref note nor xref_array section') + raise ValueError("file has neither xref note nor xref_array section") ptrs = xrefarray.iter_data(XrefPtr) for ptr in ptrs: if ptr.xref is None: - print('NULL xref') + print("NULL xref") continue self._xrefs.append(ptr.xref) @@ -346,15 +429,15 @@ class Xrelfo(dict): def load_json(self, fd): data = json.load(fd) - for uid, items in data['refs'].items(): - myitems = self['refs'].setdefault(uid, []) + for uid, items in data["refs"].items(): + myitems = self["refs"].setdefault(uid, []) for item in items: if item in myitems: continue myitems.append(item) - for cmd, items in data['cli'].items(): - self['cli'].setdefault(cmd, {}).update(items) + for cmd, items in data["cli"].items(): + self["cli"].setdefault(cmd, {}).update(items) return data @@ -362,23 +445,33 @@ class Xrelfo(dict): for xref in self._xrefs: yield from xref.check(checks) + def main(): - argp = argparse.ArgumentParser(description = 'FRR xref ELF extractor') - argp.add_argument('-o', dest='output', type=str, help='write JSON output') - argp.add_argument('--out-by-file', type=str, help='write by-file JSON output') - argp.add_argument('-Wlog-format', action='store_const', const=True) - argp.add_argument('-Wlog-args', action='store_const', const=True) - argp.add_argument('-Werror', action='store_const', const=True) - argp.add_argument('--profile', action='store_const', const=True) - argp.add_argument('binaries', metavar='BINARY', nargs='+', type=str, help='files to read (ELF files or libtool objects)') + argp = argparse.ArgumentParser(description="FRR xref ELF extractor") + argp.add_argument("-o", dest="output", type=str, help="write JSON output") + argp.add_argument("--out-by-file", type=str, help="write by-file JSON output") + argp.add_argument("-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c") + argp.add_argument("-Wlog-format", action="store_const", const=True) + argp.add_argument("-Wlog-args", action="store_const", const=True) + argp.add_argument("-Werror", action="store_const", const=True) + argp.add_argument("--profile", action="store_const", const=True) + argp.add_argument( + "binaries", + metavar="BINARY", + nargs="+", + type=str, + help="files to read (ELF files or libtool objects)", + ) args = argp.parse_args() if args.profile: import cProfile - cProfile.runctx('_main(args)', globals(), {'args': args}, sort='cumtime') + + cProfile.runctx("_main(args)", globals(), {"args": args}, sort="cumtime") else: _main(args) + def _main(args): errors = 0 xrelfo = Xrelfo() @@ -388,52 +481,59 @@ def _main(args): xrelfo.load_file(fn) except: errors += 1 - sys.stderr.write('while processing %s:\n' % (fn)) + sys.stderr.write("while processing %s:\n" % (fn)) traceback.print_exc() for option in dir(args): - if option.startswith('W') and option != 'Werror': + if option.startswith("W") and option != "Werror": checks = sorted(xrelfo.check(args)) - sys.stderr.write(''.join([c[-1] for c in checks])) + sys.stderr.write("".join([c[-1] for c in checks])) if args.Werror and len(checks) > 0: errors += 1 break - - refs = xrelfo['refs'] + refs = xrelfo["refs"] counts = {} for k, v in refs.items(): - strs = set([i['fmtstring'] for i in v]) + strs = set([i["fmtstring"] for i in v]) if len(strs) != 1: - print('\033[31;1m%s\033[m' % k) + print("\033[31;1m%s\033[m" % k) counts[k] = len(v) out = xrelfo outbyfile = {} for uid, locs in refs.items(): for loc in locs: - filearray = outbyfile.setdefault(loc['file'], []) + filearray = outbyfile.setdefault(loc["file"], []) loc = dict(loc) - del loc['file'] + del loc["file"] filearray.append(loc) for k in outbyfile.keys(): - outbyfile[k] = sorted(outbyfile[k], key=lambda x: x['line']) + outbyfile[k] = sorted(outbyfile[k], key=lambda x: x["line"]) if errors: sys.exit(1) if args.output: - with open(args.output + '.tmp', 'w') as fd: + with open(args.output + ".tmp", "w") as fd: json.dump(out, fd, indent=2, sort_keys=True, **json_dump_args) - os.rename(args.output + '.tmp', args.output) + os.rename(args.output + ".tmp", args.output) if args.out_by_file: - with open(args.out_by_file + '.tmp', 'w') as fd: + with open(args.out_by_file + ".tmp", "w") as fd: json.dump(outbyfile, fd, indent=2, sort_keys=True, **json_dump_args) - os.rename(args.out_by_file + '.tmp', args.out_by_file) + os.rename(args.out_by_file + ".tmp", args.out_by_file) -if __name__ == '__main__': + if args.vtysh_cmds: + with open(args.vtysh_cmds + ".tmp", "w") as fd: + CommandEntry.run(out, fd) + os.rename(args.vtysh_cmds + ".tmp", args.vtysh_cmds) + if args.Werror and CommandEntry.warn_counter: + sys.exit(1) + + +if __name__ == "__main__": main() diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 73442bf16f..34ea216726 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -30,9 +30,7 @@ #include "ripd/ripd.h" #include "ripd/rip_nb.h" -#ifndef VTYSH_EXTRACT_PL #include "ripd/rip_cli_clippy.c" -#endif /* * XPath: /frr-ripd:ripd/instance diff --git a/ripd/subdir.am b/ripd/subdir.am index b00c375888..98cc765c91 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -4,11 +4,6 @@ if RIPD sbin_PROGRAMS += ripd/ripd -vtysh_scan += \ - ripd/rip_cli.c \ - ripd/rip_debug.c \ - ripd/ripd.c \ - # end vtysh_daemons += ripd if SNMP diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c index ded2f4358e..049a392ddb 100644 --- a/ripngd/ripng_cli.c +++ b/ripngd/ripng_cli.c @@ -30,9 +30,7 @@ #include "ripngd/ripngd.h" #include "ripngd/ripng_nb.h" -#ifndef VTYSH_EXTRACT_PL #include "ripngd/ripng_cli_clippy.c" -#endif /* * XPath: /frr-ripngd:ripngd/instance diff --git a/ripngd/subdir.am b/ripngd/subdir.am index a4db3e5a6b..162426c58c 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -4,11 +4,6 @@ if RIPNGD sbin_PROGRAMS += ripngd/ripngd -vtysh_scan += \ - ripngd/ripng_cli.c \ - ripngd/ripng_debug.c \ - ripngd/ripngd.c \ - # end vtysh_daemons += ripngd man8 += $(MANBUILD)/frr-ripngd.8 endif diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index ba2e599a5b..164a0fd218 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -37,9 +37,7 @@ #include "sharpd/sharp_zebra.h" #include "sharpd/sharp_nht.h" #include "sharpd/sharp_vty.h" -#ifndef VTYSH_EXTRACT_PL #include "sharpd/sharp_vty_clippy.c" -#endif DEFINE_MTYPE_STATIC(SHARPD, SRV6_LOCATOR, "SRv6 Locator"); diff --git a/sharpd/subdir.am b/sharpd/subdir.am index acf4fe5d00..3eb8d1d3b5 100644 --- a/sharpd/subdir.am +++ b/sharpd/subdir.am @@ -5,7 +5,6 @@ if SHARPD noinst_LIBRARIES += sharpd/libsharp.a sbin_PROGRAMS += sharpd/sharpd -vtysh_scan += sharpd/sharp_vty.c vtysh_daemons += sharpd man8 += $(MANBUILD)/frr-sharpd.8 endif diff --git a/staticd/static_vty.c b/staticd/static_vty.c index c0638f4bc4..94a3493477 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -36,9 +36,7 @@ #include "static_vty.h" #include "static_routes.h" #include "static_debug.h" -#ifndef VTYSH_EXTRACT_PL #include "staticd/static_vty_clippy.c" -#endif #include "static_nb.h" #define STATICD_STR "Static route daemon\n" diff --git a/staticd/subdir.am b/staticd/subdir.am index 62969a0a2a..bb0fc95bc2 100644 --- a/staticd/subdir.am +++ b/staticd/subdir.am @@ -5,7 +5,6 @@ if STATICD noinst_LIBRARIES += staticd/libstatic.a sbin_PROGRAMS += staticd/staticd -vtysh_scan += staticd/static_vty.c vtysh_daemons += staticd man8 += $(MANBUILD)/frr-staticd.8 endif diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am index 02e0497eef..03b4042611 100644 --- a/vrrpd/subdir.am +++ b/vrrpd/subdir.am @@ -4,7 +4,6 @@ if VRRPD sbin_PROGRAMS += vrrpd/vrrpd -vtysh_scan += vrrpd/vrrp_vty.c vtysh_daemons += vrrpd man8 += $(MANBUILD)/frr-vrrpd.8 endif diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index aea7d9abc7..f822b89854 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -33,9 +33,7 @@ #include "vrrp_debug.h" #include "vrrp_vty.h" #include "vrrp_zebra.h" -#ifndef VTYSH_EXTRACT_PL #include "vrrpd/vrrp_vty_clippy.c" -#endif #define VRRP_STR "Virtual Router Redundancy Protocol\n" diff --git a/vtysh/.gitignore b/vtysh/.gitignore index 118b84407b..09e90e51d2 100644 --- a/vtysh/.gitignore +++ b/vtysh/.gitignore @@ -1,4 +1,6 @@ vtysh vtysh_cmd.c -extract.pl vtysh_daemons.h + +# does not exist anymore - remove 2023-10-04 or so +extract.pl diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in deleted file mode 100755 index 228a136b71..0000000000 --- a/vtysh/extract.pl.in +++ /dev/null @@ -1,282 +0,0 @@ -#! @PERL@ -## -## @configure_input@ -## -## Virtual terminal interface shell command extractor. -## Copyright (C) 2000 Kunihiro Ishiguro -## -## This file is part of GNU Zebra. -## -## GNU Zebra is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by the -## Free Software Foundation; either version 2, or (at your option) any -## later version. -## -## GNU Zebra is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with GNU Zebra; see the file COPYING. If not, write to the Free -## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA -## 02111-1307, USA. -## - -use Getopt::Long; - -print < - -#include "command.h" -#include "linklist.h" - -#include "vtysh/vtysh.h" - -EOF - -my $cli_stomp = 0; - -sub scan_file { - my ( $file, $fabricd) = @_; - - $cppadd = $fabricd ? "-DFABRICD=1" : ""; - - $command_line = "@CPP@ -P -std=gnu11 -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ @LIBYANG_CFLAGS@ $cppadd $file |"; - open (FH, $command_line) - || die "Open to the pipeline failed: $!\n\nCommand Issued:\n$command_line"; - local $/; undef $/; - $line = ; - if (!close (FH)) { - die "File: $file failed to compile:\n$!\nwhen extracting cli from it please inspect\n" - } - - # ?: makes a group non-capturing - @defun = ($line =~ /((?:DEFUN|DEFUN_HIDDEN|DEFUN_YANG|ALIAS|ALIAS_HIDDEN|ALIAS_YANG|DEFPY|DEFPY_HIDDEN|DEFPY_YANG)\s*\(.+?\));?\s?\s?\n/sg); - @install = ($line =~ /install_element\s*\(\s*[0-9A-Z_]+,\s*&[^;]*;\s*\n/sg); - - # DEFUN process - foreach (@defun) { - # $_ will contain the entire string including the DEFUN, ALIAS, etc. - # We need to extract the DEFUN/ALIAS from everything in ()s. - # The /s at the end tells the regex to allow . to match newlines. - $_ =~ /^(.*?)\s*\((.*)\)$/s; - - my (@defun_array); - $defun_or_alias = $1; - @defun_array = split (/,/, $2); - - if ($defun_or_alias =~ /_HIDDEN/) { - $hidden = 1; - } else { - $hidden = 0; - } - - $defun_array[0] = ''; - - # Actual input command string. - $str = "$defun_array[2]"; - $str =~ s/^\s+//g; - $str =~ s/\s+$//g; - - # Get VTY command structure. This is needed for searching - # install_element() command. - $cmd = "$defun_array[1]"; - $cmd =~ s/^\s+//g; - $cmd =~ s/\s+$//g; - - if ($fabricd) { - $cmd = "fabricd_" . $cmd; - } - - # $protocol is VTYSH_PROTO format for redirection of user input - if ($file =~ /lib\/keychain\.c$/) { - $protocol = "VTYSH_RIPD|VTYSH_EIGRPD|VTYSH_OSPF6D"; - } - elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) { - $protocol = "VTYSH_RMAP"; - } - elsif ($file =~ /lib\/vrf\.c$/) { - $protocol = "VTYSH_VRF"; - } - elsif ($file =~ /lib\/if\.c$/) { - $protocol = "VTYSH_INTERFACE"; - } - elsif ($file =~ /lib\/(filter|filter_cli)\.c$/) { - $protocol = "VTYSH_ACL"; - } - elsif ($file =~ /lib\/(lib|log)_vty\.c$/) { - $protocol = "VTYSH_ALL"; - } - elsif ($file =~ /lib\/agentx\.c$/) { - $protocol = "VTYSH_ISISD|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA"; - } - elsif ($file =~ /lib\/nexthop_group\.c$/) { - $protocol = "VTYSH_NH_GROUP"; - } - elsif ($file =~ /lib\/plist\.c$/) { - if ($defun_array[1] =~ m/ipv6/) { - $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIM6D|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD"; - } else { - $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD"; - } - } - elsif ($file =~ /lib\/if_rmap\.c$/) { - if ($defun_array[1] =~ m/ipv6/) { - $protocol = "VTYSH_RIPNGD"; - } else { - $protocol = "VTYSH_RIPD"; - } - } - elsif ($file =~ /lib\/resolver\.c$/) { - $protocol = "VTYSH_NHRPD|VTYSH_BGPD"; - } - elsif ($file =~ /lib\/spf_backoff\.c$/) { - $protocol = "VTYSH_ISISD"; - } - elsif ($file =~ /lib\/(vty|thread)\.c$/) { - $protocol = "VTYSH_ALL"; - } - elsif ($file =~ /librfp\/.*\.c$/ || $file =~ /rfapi\/.*\.c$/) { - $protocol = "VTYSH_BGPD"; - } - elsif ($fabricd) { - $protocol = "VTYSH_FABRICD"; - } - elsif ($file =~ /pimd\/pim6_.*\.c$/) { - $protocol = "VTYSH_PIM6D"; - } - else { - ($protocol) = ($file =~ /^(?:.*\/)?([a-z0-9]+)\/[a-zA-Z0-9_\-]+\.c$/); - $protocol = "VTYSH_" . uc $protocol; - } - - # Append _vtysh to structure then build DEFUN again - $defun_array[1] = $cmd . "_vtysh"; - $defun_body = join (", ", @defun_array); - - # $cmd -> $str hash for lookup - if (exists($cmd2str{$cmd})) { - warn "Duplicate CLI Function: $cmd\n"; - warn "\tFrom cli: $cmd2str{$cmd} to New cli: $str\n"; - warn "\tOriginal Protocol: $cmd2proto{$cmd} to New Protocol: $protocol\n"; - $cli_stomp++; - } - $cmd2str{$cmd} = $str; - $cmd2defun{$cmd} = $defun_body; - $cmd2proto{$cmd} = $protocol; - $cmd2hidden{$cmd} = $hidden; - } - - # install_element() process - foreach (@install) { - my (@element_array); - @element_array = split (/,/); - - # Install node - $enode = $element_array[0]; - $enode =~ s/^\s+//g; - $enode =~ s/\s+$//g; - ($enode) = ($enode =~ /([0-9A-Z_]+)$/); - - # VTY command structure. - ($ecmd) = ($element_array[1] =~ /&([^\)]+)/); - $ecmd =~ s/^\s+//g; - $ecmd =~ s/\s+$//g; - - if ($fabricd) { - $ecmd = "fabricd_" . $ecmd; - } - - # Register $ecmd - if (defined ($cmd2str{$ecmd})) { - my ($key); - $key = $enode . "," . $cmd2str{$ecmd}; - $ocmd{$key} = $ecmd; - $odefun{$key} = $cmd2defun{$ecmd}; - - if ($cmd2hidden{$ecmd}) { - $defsh{$key} = "DEFSH_HIDDEN" - } else { - $defsh{$key} = "DEFSH" - } - push (@{$oproto{$key}}, $cmd2proto{$ecmd}); - } - } -} - -my $have_isisd = 0; -my $have_fabricd = 0; - -GetOptions('have-isisd' => \$have_isisd, 'have-fabricd' => \$have_fabricd); - -foreach (@ARGV) { - if (/(^|\/)isisd\//) { - # We scan all the IS-IS files twice, once for isisd, - # once for fabricd. Exceptions are made for the files - # that are not shared between the two. - if (/isis_vty_isisd.c/) { - if ( $have_isisd ) { - scan_file($_, 0); - } - } elsif (/isis_vty_fabricd.c/) { - if ( $have_fabricd ) { - scan_file($_, 1); - } - } else { - if ( $have_isisd ) { - scan_file($_, 0); - } - if ( $have_fabricd ) { - scan_file($_, 1); - } - } - } else { - scan_file($_, 0); - } -} - -# When we have cli commands that map to the same function name, we -# can introduce subtle bugs due to code not being called when -# we think it is. -# -# If extract.pl fails with a error message and you've been -# modifying the cli, then go back and fix your code to -# not have cli command function collisions. -# please fix your code before submittal -if ($cli_stomp) { - warn "There are $cli_stomp command line stomps\n"; -} - -# Check finaly alive $cmd; -foreach (keys %odefun) { - my ($node, $str) = (split (/,/)); - my ($cmd) = $ocmd{$_}; - $live{$cmd} = $_; -} - -# Output DEFSH -foreach (sort keys %live) { - my ($proto); - my ($key); - $key = $live{$_}; - $proto = join ("|", @{$oproto{$key}}); - printf "$defsh{$key} ($proto$odefun{$key})\n\n"; -} - -# Output install_element -print < vtysh/vtysh_daemons.h - -AM_V_EXTRACT = $(am__v_EXTRACT_$(V)) -am__v_EXTRACT_ = $(am__v_EXTRACT_$(AM_DEFAULT_VERBOSITY)) -am__v_EXTRACT_0 = @echo " EXTRACT " $@; -am__v_EXTRACT_1 = - -if ISISD -HAVE_ISISD = --have-isisd -else -HAVE_ISISD = -endif - -if FABRICD -HAVE_FABRICD = --have-fabricd -else -HAVE_FABRICD = -endif - -vtysh/vtysh_cmd.c: vtysh/extract.pl $(vtysh_scan) - $(AM_V_EXTRACT) $^ $(HAVE_ISISD) $(HAVE_FABRICD) > vtysh/vtysh_cmd.c diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am index e899b895e7..04a4aaf166 100644 --- a/watchfrr/subdir.am +++ b/watchfrr/subdir.am @@ -4,7 +4,6 @@ if WATCHFRR sbin_PROGRAMS += watchfrr/watchfrr -vtysh_scan += watchfrr/watchfrr_vty.c man8 += $(MANBUILD)/frr-watchfrr.8 endif diff --git a/watchfrr/watchfrr_vty.c b/watchfrr/watchfrr_vty.c index e5cc437542..742b474eab 100644 --- a/watchfrr/watchfrr_vty.c +++ b/watchfrr/watchfrr_vty.c @@ -153,9 +153,7 @@ DEFUN_NOSH (show_logging, return CMD_SUCCESS; } -#ifndef VTYSH_EXTRACT_PL #include "watchfrr/watchfrr_vty_clippy.c" -#endif DEFPY (watchfrr_ignore_daemon, watchfrr_ignore_daemon_cmd, diff --git a/zebra/debug.c b/zebra/debug.c index 25102145d7..16aac7909f 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -23,9 +23,7 @@ #include "command.h" #include "debug.h" -#ifndef VTYSH_EXTRACT_PL #include "zebra/debug_clippy.c" -#endif /* For debug statement. */ unsigned long zebra_debug_event; diff --git a/zebra/dpdk/zebra_dplane_dpdk_vty.c b/zebra/dpdk/zebra_dplane_dpdk_vty.c index 748bce9e34..d1814af3b7 100644 --- a/zebra/dpdk/zebra_dplane_dpdk_vty.c +++ b/zebra/dpdk/zebra_dplane_dpdk_vty.c @@ -23,9 +23,7 @@ #include "lib/json.h" #include "zebra/dpdk/zebra_dplane_dpdk.h" -#ifndef VTYSH_EXTRACT_PL #include "zebra/dpdk/zebra_dplane_dpdk_vty_clippy.c" -#endif #define ZD_STR "Zebra dataplane information\n" #define ZD_DPDK_STR "DPDK offload information\n" diff --git a/zebra/interface.c b/zebra/interface.c index 5d62ec071f..32703b59bc 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -2603,9 +2603,7 @@ static void interface_update_stats(void) #endif /* HAVE_NET_RT_IFLIST */ } -#ifndef VTYSH_EXTRACT_PL #include "zebra/interface_clippy.c" -#endif /* Show all interfaces to vty. */ DEFPY(show_interface, show_interface_cmd, "show interface vrf NAME$vrf_name [brief$brief] [json$uj]", diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 127888d655..a8ec60844c 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -51,9 +51,7 @@ static uint32_t interfaces_configured_for_ra_from_bgp; #if defined(HAVE_RTADV) -#ifndef VTYSH_EXTRACT_PL #include "zebra/rtadv_clippy.c" -#endif DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix"); DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface"); diff --git a/zebra/subdir.am b/zebra/subdir.am index 298b71598c..9842931496 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -4,29 +4,6 @@ if ZEBRA sbin_PROGRAMS += zebra/zebra -vtysh_scan += \ - zebra/debug.c \ - zebra/interface.c \ - zebra/router-id.c \ - zebra/rtadv.c \ - zebra/zebra_gr.c \ - zebra/zebra_mlag_vty.c \ - zebra/zebra_evpn_mh.c \ - zebra/zebra_mpls_vty.c \ - zebra/zebra_srv6_vty.c \ - zebra/zebra_ptm.c \ - zebra/zebra_pw.c \ - zebra/zebra_routemap.c \ - zebra/zebra_vty.c \ - zebra/zserv.c \ - zebra/zebra_vrf.c \ - zebra/dpdk/zebra_dplane_dpdk_vty.c \ - # end - -# can be loaded as DSO - always include for vtysh -vtysh_scan += zebra/irdp_interface.c -vtysh_scan += zebra/zebra_fpm.c - vtysh_daemons += zebra if IRDP @@ -255,8 +232,6 @@ module_LTLIBRARIES += zebra/dplane_fpm_nl.la zebra_dplane_fpm_nl_la_SOURCES = zebra/dplane_fpm_nl.c zebra_dplane_fpm_nl_la_LDFLAGS = $(MODULE_LDFLAGS) zebra_dplane_fpm_nl_la_LIBADD = - -vtysh_scan += zebra/dplane_fpm_nl.c endif if NETLINK_DEBUG diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 064c91b729..98120accfd 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -3252,9 +3252,7 @@ int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp) return 0; } -#ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_evpn_mh_clippy.c" -#endif /* CLI for setting an ES in bypass mode */ DEFPY_HIDDEN(zebra_evpn_es_bypass, zebra_evpn_es_bypass_cmd, "[no] evpn mh bypass", diff --git a/zebra/zebra_mlag_vty.c b/zebra/zebra_mlag_vty.c index ebaaf03dab..a1c544d5d8 100644 --- a/zebra/zebra_mlag_vty.c +++ b/zebra/zebra_mlag_vty.c @@ -29,9 +29,7 @@ #include "debug.h" #include "zapi_msg.h" -#ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_mlag_vty_clippy.c" -#endif DEFUN_HIDDEN (show_mlag, show_mlag_cmd, diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index 2cc84a1f7f..13d1995d58 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -40,9 +40,7 @@ #include "zebra/zebra_rnh.h" #include "zebra/zebra_routemap.h" -#ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_routemap_clippy.c" -#endif static uint32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER; static struct thread *zebra_t_rmap_update = NULL; diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index 9adfc6550a..e6810bdc56 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -40,9 +40,7 @@ #include "zebra/zebra_routemap.h" #include "zebra/zebra_dplane.h" -#ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_srv6_vty_clippy.c" -#endif static int zebra_sr_config(struct vty *vty); diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index a2844ca956..c99aa2e8ff 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -44,9 +44,7 @@ #include "zebra/zebra_vxlan.h" #include "zebra/zebra_netns_notify.h" #include "zebra/zebra_routemap.h" -#ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_vrf_clippy.c" -#endif #include "zebra/table_manager.h" static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 525e0366e7..f68a656710 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -46,9 +46,7 @@ #include "lib/route_opaque.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_evpn_mh.h" -#ifndef VTYSH_EXTRACT_PL #include "zebra/zebra_vty_clippy.c" -#endif #include "zebra/zserv.h" #include "zebra/router-id.h" #include "zebra/ipforward.h"