nodist_pkginclude_HEADERS =
dist_yangmodels_DATA =
man_MANS =
-vtysh_scan =
vtysh_daemons =
clippy_scan =
python/makefile.py \
python/tiabwarfo.py \
python/xrelfo.py \
+ python/xref2vtysh.py \
python/test_xrelfo.py \
python/runtests.py \
\
if BABELD
sbin_PROGRAMS += babeld/babeld
-vtysh_scan += \
- babeld/babel_interface.c \
- babeld/babel_zebra.c \
- babeld/babeld.c \
- # end
vtysh_daemons += babeld
endif
#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"
#include "bfd.h"
-#ifndef VTYSH_EXTRACT_PL
#include "bfdd/bfdd_vty_clippy.c"
-#endif
/*
* Commands help string definitions.
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
#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,
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,
}
}
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_evpn_vty_clippy.c"
-#endif
DEFPY(bgp_evpn_flood_control,
bgp_evpn_flood_control_cmd,
#define BGP_LABELPOOL_ENABLE_TESTS 0
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_labelpool_clippy.c"
-#endif
/*
#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),
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#endif
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_routemap_clippy.c"
-#endif
/* Memo of route-map commands.
#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");
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,
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
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])
/* GPL header */
#include ...
...
- #ifndef VTYSH_EXTRACT_PL
#include "daemon/filename_clippy.c"
- #endif
DEFPY(...)
DEFPY(...)
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
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
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
#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
#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,
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
#include "isisd/isis_circuit.h"
#include "isisd/isis_csm.h"
-#ifndef VTYSH_EXTRACT_PL
#include "isisd/isis_cli_clippy.c"
-#endif
#ifndef FABRICD
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
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
#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,
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
/* 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 = { \
#define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \
ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG)
-#endif /* VTYSH_EXTRACT_PL */
-
/* Some macroes */
/*
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)) = { \
XREF_LINK(_xref.xref); \
_install_element(node_type_, cmd_element_); \
} while (0)
-#endif
extern void _install_element(enum node_type, const struct cmd_element *);
#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"
#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");
#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)
#include <command.h>
#include <jhash.h>
-#ifndef VTYSH_EXTRACT_PL
#include "lib/nexthop_group_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group");
#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"};
return CMD_SUCCESS;
}
-#ifndef VTYSH_EXTRACT_PL
#include "lib/plist_clippy.c"
-#endif
DEFPY (show_ip_prefix_list,
show_ip_prefix_list_cmd,
#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" \
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
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)
# 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) $<
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)
{
#include <arpa/telnet.h>
#include <termios.h>
-#ifndef VTYSH_EXTRACT_PL
#include "lib/vty_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(LIB, VTY, "VTY");
DEFINE_MTYPE_STATIC(LIB, VTY_SERV, "VTY server");
#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 <assert.h>
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,
if NHRPD
sbin_PROGRAMS += nhrpd/nhrpd
-vtysh_scan += nhrpd/nhrp_vty.c
vtysh_daemons += nhrpd
man8 += $(MANBUILD)/frr-nhrpd.8
endif
#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");
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;
#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);
#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");
#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");
#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;
#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");
{ .val_bool = false },
);
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_top_clippy.c"
-#endif
/* global ospf6d variable */
static struct ospf6_master ospf6_master;
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
#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};
#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);
/*
* 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,
}
}
-#ifndef VTYSH_EXTRACT_PL
#include "ospfd/ospf_vty_clippy.c"
-#endif
DEFUN_NOSH (router_ospf,
router_ospf_cmd,
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
#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
#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
#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);
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
#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"};
#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"
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
#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",
#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)
#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",
#if defined(HAVE_LINUX_MROUTE_H)
#include <linux/mroute.h>
#else
-#ifndef VTYSH_EXTRACT_PL
#include "linux/mroute.h"
#endif
-#endif
typedef struct vifctl pim_vifctl;
typedef struct igmpmsg kernmsg;
#if defined(HAVE_LINUX_MROUTE6_H)
#include <linux/mroute6.h>
#else
-#ifndef VTYSH_EXTRACT_PL
#include "linux/mroute6.h"
#endif
-#endif
#ifndef MRT_INIT
#define MRT_BASE MRT6_BASE
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
+++ /dev/null
-#!/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 <http://unlicense.org/>
-
-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)))
--- /dev/null
+# 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 typing
+from typing import (
+ Dict,
+ List,
+)
+
+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 <zebra.h>
+
+#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 f"<CommandEntry {self.name}: {self.cmd!r}>"
+
+ 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(
+ f"command definition mismatch, first definied as:\n{self.cmd!r}",
+ nodename=nodename,
+ )
+ other.warn_loc(f"later defined as:\n{other.cmd!r}", nodename=nodename)
+
+ if self._spec["doc"] != other._spec["doc"]:
+ self.warn_loc(
+ f"help string mismatch, first defined here (-)", nodename=nodename
+ )
+ other.warn_loc(
+ f"later defined here (+)\nnote: both commands define {self.cmd!r} in same node ({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(
+ f"hidden flag mismatch, first {self.hidden!r} here", nodename=nodename
+ )
+ other.warn_loc(
+ f"later {other.hidden!r} here (+)\nnote: both commands define {self.cmd!r} in same node ({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 f"""
+{defsh} ({daemon_str}, {self.name}_vtysh,
+\t"{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(f"\tinstall_element({name}, &{item.name}_vtysh);\n")
+
+ 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()
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:
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)
json.dump(outbyfile, fd, indent=2, sort_keys=True, **json_dump_args)
os.rename(args.out_by_file + '.tmp', args.out_by_file)
+ 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()
#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
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
#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
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
#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");
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
#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"
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
if VRRPD
sbin_PROGRAMS += vrrpd/vrrpd
-vtysh_scan += vrrpd/vrrp_vty.c
vtysh_daemons += vrrpd
man8 += $(MANBUILD)/frr-vrrpd.8
endif
#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"
vtysh
vtysh_cmd.c
-extract.pl
vtysh_daemons.h
+
+# does not exist anymore - remove 2023-10-04 or so
+extract.pl
+++ /dev/null
-#! @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 <<EOF;
-#include <zebra.h>
-
-#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 = <FH>;
- 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 <<EOF;
-void vtysh_init_cmd(void)
-{
-EOF
-
-foreach (sort keys %odefun) {
- my ($node, $str) = (split (/,/));
- $cmd = $ocmd{$_};
- $cmd =~ s/_cmd$/_cmd_vtysh/;
- printf " install_element ($node, &$cmd);\n";
-}
-
-print <<EOF
-}
-EOF
nodist_vtysh_vtysh_SOURCES = \
vtysh/vtysh_cmd.c \
# end
-CLEANFILES += vtysh/vtysh_cmd.c
noinst_HEADERS += \
vtysh/vtysh.h \
CLEANFILES += vtysh/vtysh_daemons.h
vtysh/vtysh_daemons.h:
$(PERL) $(top_srcdir)/vtysh/daemons.pl $(vtysh_daemons) > 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
if WATCHFRR
sbin_PROGRAMS += watchfrr/watchfrr
-vtysh_scan += watchfrr/watchfrr_vty.c
man8 += $(MANBUILD)/frr-watchfrr.8
endif
return CMD_SUCCESS;
}
-#ifndef VTYSH_EXTRACT_PL
#include "watchfrr/watchfrr_vty_clippy.c"
-#endif
DEFPY (watchfrr_ignore_daemon,
watchfrr_ignore_daemon_cmd,
#include "command.h"
#include "debug.h"
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/debug_clippy.c"
-#endif
/* For debug statement. */
unsigned long zebra_debug_event;
#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"
#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]",
#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");
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
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
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",
#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,
#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;
#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);
#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,
#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"