From 7b526b616873cf360e690955e2ab36c2d9f04507 Mon Sep 17 00:00:00 2001 From: Quentin Young Date: Wed, 13 Jun 2018 23:08:30 +0000 Subject: [PATCH] lib: add error reference system * Add zlog_* function to log with a reference code * Add ability to track reference cards for errors to ferr.[ch] * Assign some reference code ranges Signed-off-by: Quentin Young --- lib/ferr.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/ferr.h | 30 +++++++++++++++ lib/log.h | 5 +++ vtysh/vtysh.c | 16 ++++++++ 4 files changed, 151 insertions(+) diff --git a/lib/ferr.c b/lib/ferr.c index 45574520a5..ccf2f853ef 100644 --- a/lib/ferr.c +++ b/lib/ferr.c @@ -24,9 +24,14 @@ #include "vty.h" #include "jhash.h" #include "memory.h" +#include "hash.h" +#include "command.h" DEFINE_MTYPE_STATIC(LIB, ERRINFO, "error information") +/* + * Thread-specific key for temporary storage of allocated ferr. + */ static pthread_key_t errkey; static void ferr_free(void *arg) @@ -46,6 +51,101 @@ static void err_key_fini(void) pthread_key_delete(errkey); } +/* + * Global shared hash table holding reference text for all defined errors. + */ +pthread_mutex_t refs_mtx = PTHREAD_MUTEX_INITIALIZER; +struct hash *refs; + +static int ferr_hash_cmp(const void *a, const void *b) +{ + const struct ferr_ref *f_a = a; + const struct ferr_ref *f_b = b; + + return f_a->code == f_b->code; +} + +static inline unsigned int ferr_hash_key(void *a) +{ + struct ferr_ref *f = a; + + return f->code; +} + +void ferr_ref_add(struct ferr_ref *ref) +{ + pthread_mutex_lock(&refs_mtx); + { + hash_get(refs, ref, hash_alloc_intern); + } + pthread_mutex_unlock(&refs_mtx); +} + +struct ferr_ref *ferr_ref_get(uint32_t code) +{ + struct ferr_ref holder; + struct ferr_ref *ref; + + holder.code = code; + pthread_mutex_lock(&refs_mtx); + { + ref = hash_lookup(refs, &holder); + } + pthread_mutex_unlock(&refs_mtx); + + return ref; +} + +void ferr_ref_display(struct vty *vty, uint32_t code) +{ + struct ferr_ref *ref = ferr_ref_get(code); + + if (!ref) { + vty_out(vty, "Code %d - Unknown\n", code); + return; + } + + vty_out(vty, "Error Code %d - %s\n", code, ref->title); + vty_out(vty, "--------------------------------------\n"); + vty_out(vty, "\nDescription:\n%s\n\nRecommendation:\n%s\n\n", + ref->description, ref->suggestion); +} + +DEFUN_NOSH(show_error_code, + show_error_code_cmd, + "show error (0-4294967296)", + SHOW_STR + "Information on errors\n" + "Error code to get info about\n") +{ + uint32_t arg = strtoul(argv[2]->arg, NULL, 10); + + ferr_ref_display(vty, arg); + return CMD_SUCCESS; +} + +void ferr_ref_init(void) +{ + pthread_mutex_lock(&refs_mtx); + { + refs = hash_create(ferr_hash_key, ferr_hash_cmp, + "Error Reference Texts"); + } + pthread_mutex_unlock(&refs_mtx); + + install_element(VIEW_NODE, &show_error_code_cmd); +} + +void ferr_ref_fini(void) +{ + pthread_mutex_lock(&refs_mtx); + { + hash_free(refs); + refs = NULL; + } + pthread_mutex_unlock(&refs_mtx); +} + const struct ferr *ferr_get_last(ferr_r errval) { struct ferr *last_error = pthread_getspecific(errkey); diff --git a/lib/ferr.h b/lib/ferr.h index 2f100c1b01..5efdc6bd6b 100644 --- a/lib/ferr.h +++ b/lib/ferr.h @@ -25,6 +25,8 @@ #include #include +#include "vty.h" + /* return type when this error indication stuff is used. * * guaranteed to have boolean evaluation to "false" when OK, "true" when error @@ -93,6 +95,34 @@ struct ferr { char pathname[PATH_MAX]; }; +/* Numeric ranges assigned to daemons for use as error codes. */ +#define LIB_FERR_START 0x01000001 +#define LIB_FERR_END 0x01FFFFFF +#define BGP_FERR_START 0x02000000 +#define BGP_FERR_END 0x02FFFFFF +#define OSPF_FERR_START 0x03000001 +#define OSPF_FERR_END 0x03FFFFFF +#define ZEBRA_FERR_START 0x04000001 +#define ZEBRA_FERR_END 0x04FFFFFF + +struct ferr_ref { + /* Unique error code displayed to end user as a reference. -1 means + * this is an uncoded error that does not have reference material. */ + uint32_t code; + /* Ultra brief title */ + const char *title; + /* Brief description of error */ + const char *description; + /* Remedial suggestion */ + const char *suggestion; +}; + +void ferr_ref_add(struct ferr_ref *ref); +struct ferr_ref *ferr_ref_get(uint32_t code); +void ferr_ref_display(struct vty *, uint32_t code); +void ferr_ref_init(void); +void ferr_ref_fini(void); + /* get error details. * * NB: errval/ferr_r does NOT carry the full error information. It's only diff --git a/lib/log.h b/lib/log.h index 07eb6d5bd5..a2546298a8 100644 --- a/lib/log.h +++ b/lib/log.h @@ -85,6 +85,11 @@ extern void zlog_info(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); extern void zlog_notice(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); extern void zlog_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2); +/* For logs which have error codes associated with them */ +#define zlog_ferr(ferr_id, format, ...) \ + zlog_err("[EC %d] " format, ferr_id, ##__VA_ARGS__) + + extern void zlog_thread_info(int log_level); /* Set logging level for the given destination. If the log_level diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 48a90a695c..540e30e447 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2344,6 +2344,21 @@ DEFUN (vtysh_show_debugging_hashtable, "Hashtable statistics for %s:\n"); } +DEFUN (vtysh_show_error_code, + vtysh_show_error_code_cmd, + "show error (0-4294967296)", + SHOW_STR + "Information on errors\n" + "Error code to get info about\n") +{ + char cmd[256]; + + snprintf(cmd, sizeof(cmd), "do show error %s", argv[2]->arg); + + /* FIXME: Needs to determine which daemon to send to via code ranges */ + return show_per_daemon(cmd, ""); +} + /* Memory */ DEFUN (vtysh_show_memory, vtysh_show_memory_cmd, @@ -3780,6 +3795,7 @@ void vtysh_init_vty(void) /* debugging */ install_element(VIEW_NODE, &vtysh_show_debugging_cmd); + install_element(VIEW_NODE, &vtysh_show_error_code_cmd); install_element(VIEW_NODE, &vtysh_show_debugging_hashtable_cmd); install_element(ENABLE_NODE, &vtysh_debug_all_cmd); install_element(CONFIG_NODE, &vtysh_debug_all_cmd); -- 2.39.5