From 06587903917e53ea4affef7e44c8e4c2db8a2409 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Fri, 8 Mar 2024 17:06:04 -0500 Subject: [PATCH] libs: add cli for interface lib debugs Add cli, handlers, and yang model for 'debug interface'. This was a little awkward; had to put the actual cli in one lib module and offer some support apis from the interface module. Signed-off-by: Mark Stapp --- lib/command.c | 1 + lib/command.h | 1 + lib/if.c | 93 +++++++++++++++++++++++++++++++++++++---- lib/if.h | 8 +++- lib/vty.c | 31 ++++++++++++++ vtysh/vtysh_config.c | 6 ++- yang/frr-interface.yang | 7 ++++ 7 files changed, 136 insertions(+), 11 deletions(-) diff --git a/lib/command.c b/lib/command.c index 25c9ee9a7395..7a0b56a29232 100644 --- a/lib/command.c +++ b/lib/command.c @@ -2465,6 +2465,7 @@ void cmd_show_lib_debugs(struct vty *vty) { route_map_show_debug(vty); debug_status_write(vty); + lib_if_show_debug(vty); } void install_default(enum node_type node) diff --git a/lib/command.h b/lib/command.h index c60751789f66..d6ed3bd783ed 100644 --- a/lib/command.h +++ b/lib/command.h @@ -180,6 +180,7 @@ enum node_type { RPKI_VRF_NODE, /* RPKI node for VRF */ PIM_NODE, /* PIM protocol mode */ PIM6_NODE, /* PIM protocol for IPv6 mode */ + INTF_DEBUG_NODE, /* Interface Lib Debug node. */ NODE_TYPE_MAX, /* maximum */ }; /* clang-format on */ diff --git a/lib/if.c b/lib/if.c index 5cbd782cc79e..b5ba8cce53a4 100644 --- a/lib/if.c +++ b/lib/if.c @@ -62,7 +62,7 @@ DEFINE_HOOK(if_up, (struct interface *ifp), (ifp)); DEFINE_KOOH(if_down, (struct interface *ifp), (ifp)); /* Control debug output for the lib module */ -static bool ifp_debug; +static bool intf_lib_debug; /* Compare interface names, returning an integer greater than, equal to, or * less than 0, (following the strcmp convention), according to the @@ -191,7 +191,7 @@ static struct interface *if_new(struct vrf *vrf) void if_new_via_zapi(struct interface *ifp) { - if (ifp_debug) + if (intf_lib_debug) zlog_debug("%s: ifp %s, vrf %u", __func__, ifp->name, ifp->vrf->vrf_id); @@ -200,7 +200,7 @@ void if_new_via_zapi(struct interface *ifp) void if_destroy_via_zapi(struct interface *ifp) { - if (ifp_debug) + if (intf_lib_debug) zlog_debug("%s: ifp %s, vrf %u", __func__, ifp->name, ifp->vrf->vrf_id); @@ -215,7 +215,7 @@ void if_destroy_via_zapi(struct interface *ifp) void if_up_via_zapi(struct interface *ifp) { - if (ifp_debug) + if (intf_lib_debug) zlog_debug("%s: ifp %s, vrf %u", __func__, ifp->name, ifp->vrf->vrf_id); @@ -224,7 +224,7 @@ void if_up_via_zapi(struct interface *ifp) void if_down_via_zapi(struct interface *ifp) { - if (ifp_debug) + if (intf_lib_debug) zlog_debug("%s: ifp %s, vrf %u", __func__, ifp->name, ifp->vrf->vrf_id); @@ -337,7 +337,7 @@ static struct interface *if_create_name(const char *name, struct vrf *vrf) if_set_name(ifp, name); - if (ifp_debug) + if (intf_lib_debug) zlog_debug("%s: ifp %s, vrf %u", __func__, ifp->name, ifp->vrf->vrf_id); @@ -357,7 +357,7 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) /* remove interface from old master vrf list */ old_vrf = ifp->vrf; - if (ifp_debug) + if (intf_lib_debug) zlog_debug("%s: ifp %s, old vrf %u -> new vrf %u", __func__, ifp->name, old_vrf->vrf_id, vrf_id); @@ -405,7 +405,7 @@ void if_delete(struct interface **ifp) struct interface *ptr = *ifp; struct vrf *vrf = ptr->vrf; - if (ifp_debug) + if (intf_lib_debug) zlog_debug("%s: ifp %s, vrf %u", __func__, ptr->name, vrf->vrf_id); @@ -735,7 +735,7 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id, break; case VRF_BACKEND_VRF_LITE: - if (ifp_debug) + if (intf_lib_debug) zlog_debug("%s: ifname %s, vrf_id %i, vrf_name %s", __func__, name, vrf_id, vrf_name); @@ -1523,6 +1523,50 @@ static void if_autocomplete(vector comps, struct cmd_token *token) } } +/* Enable, disable lib debugging. The controlling CLI handlers are in another + * lib module... + */ +void lib_if_enable_debug(struct vty *vty, bool enable, bool config) +{ + char xpath[XPATH_MAXLEN]; + + intf_lib_debug = enable; + if (config) { + /* Update northbound */ + strlcpy(xpath, "/frr-interface:lib/debug-enable", sizeof(xpath)); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + enable ? "true" : "false"); + + nb_cli_apply_changes(vty, NULL); + } +} + +int lib_if_debug_write_config(struct vty *vty) +{ + int written = 0; + const struct lyd_node *dnode; + bool enabled; + + dnode = yang_dnode_get(running_config->dnode, + "/frr-interface:lib/debug-enable"); + if (dnode) { + enabled = yang_dnode_get_bool(dnode, NULL); + if (enabled) { + vty_out(vty, "debug interface\n"); + written++; + } + } + + return written; +} + +/* Show lib debugging */ +void lib_if_show_debug(struct vty *vty) +{ + if (intf_lib_debug) + vty_out(vty, " Interface library debugging is on\n"); +} + static const struct cmd_variable_handler if_var_handlers[] = { {/* "interface NAME" */ .varname = "interface", @@ -1863,12 +1907,43 @@ lib_interface_state_phy_address_get_elem(struct nb_cb_get_elem_args *args) return yang_data_new_mac(args->xpath, &macaddr); } +/* + * XPath: /frr-interface:lib/debug-enable + */ +static int lib_debug_enable_modify(struct nb_cb_modify_args *args) +{ + bool enable; + + if (args->event != NB_EV_APPLY) + return NB_OK; + + /* Apply begins here */ + enable = yang_dnode_get_bool(args->dnode, NULL); + intf_lib_debug = enable; + + return NB_OK; +} + +static void lib_debug_enable_cli_write(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) +{ + lib_if_debug_write_config(vty); +} + /* clang-format off */ /* cli_show callbacks are kept here for daemons not yet converted to mgmtd */ const struct frr_yang_module_info frr_interface_info = { .name = "frr-interface", .nodes = { + { + .xpath = "/frr-interface:lib/debug-enable", + .cbs = { + .modify = lib_debug_enable_modify, + .cli_show = lib_debug_enable_cli_write, + } + }, { .xpath = "/frr-interface:lib/interface", .cbs = { diff --git a/lib/if.h b/lib/if.h index 1e52020b640b..c2626fb567a1 100644 --- a/lib/if.h +++ b/lib/if.h @@ -623,8 +623,14 @@ struct if_link_params *if_link_params_enable(struct interface *ifp); struct if_link_params *if_link_params_init(struct interface *ifp); void if_link_params_free(struct interface *ifp); -/* Northbound. */ +/* Forward declaration */ struct vty; + +void lib_if_show_debug(struct vty *vty); +void lib_if_enable_debug(struct vty *vty, bool enable, bool config); +int lib_if_debug_write_config(struct vty *vty); + +/* Northbound. */ extern void if_vty_config_start(struct vty *vty, struct interface *ifp); extern void if_vty_config_end(struct vty *vty); extern void if_cmd_init(int (*config_write)(struct vty *)); diff --git a/lib/vty.c b/lib/vty.c index 1d04e75bf445..35ab6998c6fa 100644 --- a/lib/vty.c +++ b/lib/vty.c @@ -3512,6 +3512,32 @@ void vty_init_vtysh(void) /* currently nothing to do, but likely to have future use */ } +/* Control interface lib-level debugs */ +DEFPY (intf_lib_debug_s, + intf_lib_debug_cmd, + "[no] debug interface", + NO_STR + DEBUG_STR + "Interface Library Debugging\n") +{ + lib_if_enable_debug(vty, no == NULL, vty->node == CONFIG_NODE); + + return CMD_SUCCESS; +} + +/* Config write for interface lib debugs */ +static int intf_lib_write_cfg(struct vty *vty) +{ + return lib_if_debug_write_config(vty); +} + +/* Config node for interface lib debugs */ +static struct cmd_node intf_lib_debug_node = { + .name = "intf debug", + .node = INTF_DEBUG_NODE, + .prompt = "", + .config_write = intf_lib_write_cfg, +}; /* * These functions allow for CLI handling to be placed inside daemons; however, @@ -4306,6 +4332,11 @@ void vty_init(struct event_loop *master_thread, bool do_command_logging) install_element(VTY_NODE, &no_vty_login_cmd); install_element(VTY_NODE, &vty_ipv6_access_class_cmd); install_element(VTY_NODE, &no_vty_ipv6_access_class_cmd); + + /* Install interface lib debugs */ + install_node(&intf_lib_debug_node); + install_element(ENABLE_NODE, &intf_lib_debug_cmd); + install_element(CONFIG_NODE, &intf_lib_debug_cmd); } void vty_terminate(void) diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 6536e1b37693..11918768fe63 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -453,6 +453,9 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(FORWARDING_NODE, line); else if (strncmp(line, "debug vrf", strlen("debug vrf")) == 0) config = config_get(VRF_DEBUG_NODE, line); + else if (strncmp(line, "debug interface", + strlen("debug interface")) == 0) + config = config_get(INTF_DEBUG_NODE, line); else if (strncmp(line, "debug route-map", strlen("debug route-map")) == 0) @@ -528,7 +531,8 @@ void vtysh_config_parse_line(void *arg, const char *line) (I) == PREFIX_IPV6_NODE || (I) == FORWARDING_NODE || \ (I) == DEBUG_NODE || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || \ (I) == RMAP_DEBUG_NODE || (I) == RESOLVER_DEBUG_NODE || \ - (I) == MPLS_NODE || (I) == KEYCHAIN_KEY_NODE) + (I) == MPLS_NODE || (I) == KEYCHAIN_KEY_NODE || \ + (I) == INTF_DEBUG_NODE) static void configvec_dump(vector vec, bool nested) { diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang index fc5a29090876..c27c9b935247 100644 --- a/yang/frr-interface.yang +++ b/yang/frr-interface.yang @@ -289,6 +289,13 @@ module frr-interface { } container lib { + leaf debug-enable { + type boolean; + default false; + description + "Enable library-level debugs."; + } + list interface { key "name"; description