summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/agentx.c13
-rw-r--r--lib/bfd.h1
-rw-r--r--lib/buffer.c11
-rw-r--r--lib/command.c21
-rw-r--r--lib/command.h8
-rw-r--r--lib/command_parse.y8
-rw-r--r--lib/defun_lex.l1
-rw-r--r--lib/ferr.c169
-rw-r--r--lib/ferr.h68
-rw-r--r--lib/frr_zmq.c7
-rw-r--r--lib/if.c17
-rw-r--r--lib/if.h12
-rw-r--r--lib/json.h14
-rw-r--r--lib/lib_errors.c118
-rw-r--r--lib/lib_errors.h45
-rw-r--r--lib/libfrr.c15
-rw-r--r--lib/linklist.c20
-rw-r--r--lib/linklist.h13
-rw-r--r--lib/log.c29
-rw-r--r--lib/log.h7
-rw-r--r--lib/memory.c28
-rw-r--r--lib/memory.h8
-rw-r--r--lib/memory_vty.c20
-rw-r--r--lib/mpls.h1
-rw-r--r--lib/netns_linux.c23
-rw-r--r--lib/pid_output.c17
-rw-r--r--lib/prefix.c6
-rw-r--r--lib/privs.c35
-rw-r--r--lib/privs.h39
-rw-r--r--lib/route_types.txt2
-rw-r--r--lib/sigevent.c4
-rw-r--r--lib/skiplist.c4
-rw-r--r--lib/sockopt.c14
-rw-r--r--lib/sockunion.c13
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/vrf.c75
-rw-r--r--lib/vty.c71
-rw-r--r--lib/workqueue.c8
-rw-r--r--lib/zclient.c107
-rw-r--r--lib/zclient.h1
-rw-r--r--lib/zebra.h17
41 files changed, 861 insertions, 231 deletions
diff --git a/lib/agentx.c b/lib/agentx.c
index 302bbf0a42..8e6493d4d3 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -31,6 +31,7 @@
#include "memory.h"
#include "linklist.h"
#include "version.h"
+#include "lib_errors.h"
static int agentx_enabled = 0;
@@ -141,16 +142,20 @@ static int agentx_log_callback(int major, int minor, void *serverarg,
msg[strlen(msg) - 1] = '\0';
switch (slm->priority) {
case LOG_EMERG:
- zlog_err("snmp[emerg]: %s", msg ? msg : slm->msg);
+ flog_err(LIB_ERR_SNMP,
+ "snmp[emerg]: %s", msg ? msg : slm->msg);
break;
case LOG_ALERT:
- zlog_err("snmp[alert]: %s", msg ? msg : slm->msg);
+ flog_err(LIB_ERR_SNMP,
+ "snmp[alert]: %s", msg ? msg : slm->msg);
break;
case LOG_CRIT:
- zlog_err("snmp[crit]: %s", msg ? msg : slm->msg);
+ flog_err(LIB_ERR_SNMP,
+ "snmp[crit]: %s", msg ? msg : slm->msg);
break;
case LOG_ERR:
- zlog_err("snmp[err]: %s", msg ? msg : slm->msg);
+ flog_err(LIB_ERR_SNMP,
+ "snmp[err]: %s", msg ? msg : slm->msg);
break;
case LOG_WARNING:
zlog_warn("snmp[warning]: %s", msg ? msg : slm->msg);
diff --git a/lib/bfd.h b/lib/bfd.h
index 94430051a8..f824b0fd9b 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -24,6 +24,7 @@
#define _ZEBRA_BFD_H
#include "lib/json.h"
+#include "lib/zclient.h"
#define BFD_DEF_MIN_RX 300
#define BFD_MIN_MIN_RX 50
diff --git a/lib/buffer.c b/lib/buffer.c
index b573981c1b..0292c85dac 100644
--- a/lib/buffer.c
+++ b/lib/buffer.c
@@ -25,6 +25,8 @@
#include "buffer.h"
#include "log.h"
#include "network.h"
+#include "lib_errors.h"
+
#include <stddef.h>
DEFINE_MTYPE_STATIC(LIB, BUFFER, "Buffer")
@@ -341,7 +343,8 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width,
iov_alloc * sizeof(*iov));
} else {
/* This should absolutely never occur. */
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"%s: corruption detected: iov_small overflowed; "
"head %p, tail %p, head->next %p",
__func__, (void *)b->head,
@@ -456,9 +459,9 @@ in one shot. */
while (written > 0) {
struct buffer_data *d;
if (!(d = b->head)) {
- zlog_err(
- "%s: corruption detected: buffer queue empty, "
- "but written is %lu",
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
+ "%s: corruption detected: buffer queue empty, but written is %lu",
__func__, (unsigned long)written);
break;
}
diff --git a/lib/command.c b/lib/command.c
index 0bf856f248..1df6442107 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -45,6 +45,7 @@
#include "libfrr.h"
#include "jhash.h"
#include "hook.h"
+#include "lib_errors.h"
DEFINE_MTYPE(LIB, HOST, "Host config")
DEFINE_MTYPE(LIB, COMPLETION, "Completion item")
@@ -143,6 +144,8 @@ const char *node_names[] = {
*/
"bgp ipv6 flowspec", /* BGP_FLOWSPECV6_NODE
*/
+ "bfd", /* BFD_NODE */
+ "bfd peer", /* BFD_PEER_NODE */
};
/* clang-format on */
@@ -987,6 +990,9 @@ enum node_type node_parent(enum node_type node)
case LDP_PSEUDOWIRE_NODE:
ret = LDP_L2VPN_NODE;
break;
+ case BFD_PEER_NODE:
+ ret = BFD_NODE;
+ break;
default:
ret = CONFIG_NODE;
break;
@@ -1433,6 +1439,7 @@ void cmd_exit(struct vty *vty)
case RMAP_NODE:
case PBRMAP_NODE:
case VTY_NODE:
+ case BFD_NODE:
vty->node = CONFIG_NODE;
break;
case BGP_IPV4_NODE:
@@ -1474,6 +1481,9 @@ void cmd_exit(struct vty *vty)
case LINK_PARAMS_NODE:
vty->node = INTERFACE_NODE;
break;
+ case BFD_PEER_NODE:
+ vty->node = BFD_NODE;
+ break;
default:
break;
}
@@ -1544,6 +1554,8 @@ DEFUN (config_end,
case KEYCHAIN_KEY_NODE:
case VTY_NODE:
case LINK_PARAMS_NODE:
+ case BFD_NODE:
+ case BFD_PEER_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
break;
@@ -2405,15 +2417,12 @@ static int set_log_file(struct vty *vty, const char *fname, int loglevel)
cwd[MAXPATHLEN] = '\0';
if (getcwd(cwd, MAXPATHLEN) == NULL) {
- zlog_err("config_log_file: Unable to alloc mem!");
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "config_log_file: Unable to alloc mem!");
return CMD_WARNING_CONFIG_FAILED;
}
- if ((p = XMALLOC(MTYPE_TMP, strlen(cwd) + strlen(fname) + 2))
- == NULL) {
- zlog_err("config_log_file: Unable to alloc mem!");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ p = XMALLOC(MTYPE_TMP, strlen(cwd) + strlen(fname) + 2);
sprintf(p, "%s/%s", cwd, fname);
fullpath = p;
} else
diff --git a/lib/command.h b/lib/command.h
index a001a90e2e..75b69507ec 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -139,6 +139,8 @@ enum node_type {
connections.*/
BGP_FLOWSPECV4_NODE, /* BGP IPv4 FLOWSPEC Address-Family */
BGP_FLOWSPECV6_NODE, /* BGP IPv6 FLOWSPEC Address-Family */
+ BFD_NODE, /* BFD protocol mode. */
+ BFD_PEER_NODE, /* BFD peer configuration mode. */
NODE_TYPE_MAX, /* maximum */
};
@@ -220,6 +222,9 @@ struct cmd_node {
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
funcdecl_##funcname
+#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \
+ DEFPY(funcname, cmdname, cmdstr, helpstr)
+
#define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
funcdecl_##funcname
@@ -302,6 +307,9 @@ struct cmd_node {
#define DEFPY(funcname, cmdname, cmdstr, helpstr) \
DEFUN(funcname, cmdname, cmdstr, helpstr)
+#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \
+ DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr)
+
#define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr)
#endif /* VTYSH_EXTRACT_PL */
diff --git a/lib/command_parse.y b/lib/command_parse.y
index 0f3e42219e..1b304a98b2 100644
--- a/lib/command_parse.y
+++ b/lib/command_parse.y
@@ -404,8 +404,8 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
char spacing[256];
int lineno = 0;
- zlog_err ("%s: FATAL parse error: %s", __func__, msg);
- zlog_err ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
+ zlog_notice ("%s: FATAL parse error: %s", __func__, msg);
+ zlog_notice ("%s: %d:%d-%d of this command definition:", __func__, loc->first_line, loc->first_column, loc->last_column);
line = tmpstr;
do {
@@ -414,7 +414,7 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
if (eol)
*eol++ = '\0';
- zlog_err ("%s: | %s", __func__, line);
+ zlog_notice ("%s: | %s", __func__, line);
if (lineno == loc->first_line && lineno == loc->last_line
&& loc->first_column < (int)sizeof(spacing) - 1
&& loc->last_column < (int)sizeof(spacing) - 1) {
@@ -426,7 +426,7 @@ yyerror (CMD_YYLTYPE *loc, struct parser_ctx *ctx, char const *msg)
memset(spacing, ' ', loc->first_column - 1);
memset(spacing + loc->first_column - 1, '^', len);
spacing[loc->first_column - 1 + len] = '\0';
- zlog_err ("%s: | %s", __func__, spacing);
+ zlog_notice ("%s: | %s", __func__, spacing);
}
} while ((line = eol));
free(tmpstr);
diff --git a/lib/defun_lex.l b/lib/defun_lex.l
index 9c995db266..d901c26a2e 100644
--- a/lib/defun_lex.l
+++ b/lib/defun_lex.l
@@ -132,6 +132,7 @@ SPECIAL [(),]
"DEFUN_NOSH" value = strdup(yytext); return DEFUNNY;
"DEFUN_HIDDEN" value = strdup(yytext); return DEFUNNY;
"DEFPY" value = strdup(yytext); return DEFUNNY;
+"DEFPY_NOSH" value = strdup(yytext); return DEFUNNY;
"DEFPY_ATTR" value = strdup(yytext); return DEFUNNY;
"DEFPY_HIDDEN" value = strdup(yytext); return DEFUNNY;
"ALIAS" value = strdup(yytext); return DEFUNNY;
diff --git a/lib/ferr.c b/lib/ferr.c
index d315cf843c..2fa5db6f34 100644
--- a/lib/ferr.c
+++ b/lib/ferr.c
@@ -19,14 +19,22 @@
#include <string.h>
#include <pthread.h>
#include <signal.h>
+#include <inttypes.h>
#include "ferr.h"
#include "vty.h"
#include "jhash.h"
#include "memory.h"
+#include "hash.h"
+#include "command.h"
+#include "json.h"
+#include "linklist.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 +54,160 @@ 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 log_ref *f_a = a;
+ const struct log_ref *f_b = b;
+
+ return f_a->code == f_b->code;
+}
+
+static inline unsigned int ferr_hash_key(void *a)
+{
+ struct log_ref *f = a;
+
+ return f->code;
+}
+
+void log_ref_add(struct log_ref *ref)
+{
+ uint32_t i = 0;
+
+ pthread_mutex_lock(&refs_mtx);
+ {
+ while (ref[i].code != END_FERR) {
+ hash_get(refs, &ref[i], hash_alloc_intern);
+ i++;
+ }
+ }
+ pthread_mutex_unlock(&refs_mtx);
+}
+
+struct log_ref *log_ref_get(uint32_t code)
+{
+ struct log_ref holder;
+ struct log_ref *ref;
+
+ holder.code = code;
+ pthread_mutex_lock(&refs_mtx);
+ {
+ ref = hash_lookup(refs, &holder);
+ }
+ pthread_mutex_unlock(&refs_mtx);
+
+ return ref;
+}
+
+void log_ref_display(struct vty *vty, uint32_t code, bool json)
+{
+ struct log_ref *ref;
+ struct json_object *top, *obj;
+ struct list *errlist;
+ struct listnode *ln;
+
+ if (json)
+ top = json_object_new_object();
+
+ pthread_mutex_lock(&refs_mtx);
+ {
+ errlist = code ? list_new() : hash_to_list(refs);
+ }
+ pthread_mutex_unlock(&refs_mtx);
+
+ if (code) {
+ ref = log_ref_get(code);
+ if (!ref) {
+ vty_out(vty, "Code %"PRIu32" - Unknown\n", code);
+ return;
+ }
+ listnode_add(errlist, ref);
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(errlist, ln, ref)) {
+ if (json) {
+ char key[11];
+
+ snprintf(key, sizeof(key), "%"PRIu32, ref->code);
+ obj = json_object_new_object();
+ json_object_string_add(obj, "title", ref->title);
+ json_object_string_add(obj, "description",
+ ref->description);
+ json_object_string_add(obj, "suggestion",
+ ref->suggestion);
+ json_object_object_add(top, key, obj);
+ } else {
+ char pbuf[256];
+ char ubuf[256];
+
+ snprintf(pbuf, sizeof(pbuf), "\nError %"PRIu32" - %s",
+ code, ref->title);
+ memset(ubuf, '=', strlen(pbuf));
+ ubuf[sizeof(ubuf) - 1] = '\0';
+
+ vty_out(vty, "%s\n%s\n", pbuf, ubuf);
+ vty_out(vty, "Description:\n%s\n\n", ref->description);
+ vty_out(vty, "Recommendation:\n%s\n", ref->suggestion);
+ }
+ }
+
+ if (json) {
+ const char *str = json_object_to_json_string_ext(
+ top, JSON_C_TO_STRING_PRETTY);
+ vty_out(vty, "%s\n", str);
+ json_object_free(top);
+ }
+
+ list_delete_and_null(&errlist);
+}
+
+DEFUN_NOSH(show_error_code,
+ show_error_code_cmd,
+ "show error <(1-4294967296)|all> [json]",
+ SHOW_STR
+ "Information on errors\n"
+ "Error code to get info about\n"
+ "Information on all errors\n"
+ JSON_STR)
+{
+ bool json = strmatch(argv[argc-1]->text, "json");
+ uint32_t arg = 0;
+
+ if (!strmatch(argv[2]->text, "all"))
+ arg = strtoul(argv[2]->arg, NULL, 10);
+
+ log_ref_display(vty, arg, json);
+ return CMD_SUCCESS;
+}
+
+void log_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 log_ref_fini(void)
+{
+ pthread_mutex_lock(&refs_mtx);
+ {
+ hash_clean(refs, NULL);
+ 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);
@@ -70,13 +232,6 @@ static ferr_r ferr_set_va(const char *file, int line, const char *func,
if (!error) {
error = XCALLOC(MTYPE_ERRINFO, sizeof(*error));
- if (!error) {
- /* we're screwed */
- zlog_err("out of memory while allocating error info");
- raise(SIGSEGV);
- abort(); /* raise() can return, but raise(SIGSEGV) shall
- not */
- }
pthread_setspecific(errkey, error);
}
diff --git a/lib/ferr.h b/lib/ferr.h
index 2f100c1b01..335875c166 100644
--- a/lib/ferr.h
+++ b/lib/ferr.h
@@ -25,6 +25,8 @@
#include <limits.h>
#include <errno.h>
+#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,66 @@ struct ferr {
char pathname[PATH_MAX];
};
+/* Numeric ranges assigned to daemons for use as error codes. */
+#define BABEL_FERR_START 0x01000001
+#define BABEL_FRRR_END 0x01FFFFFF
+#define BGP_FERR_START 0x02000001
+#define BGP_FERR_END 0x02FFFFFF
+#define EIGRP_FERR_START 0x03000001
+#define EIGRP_FERR_END 0x03FFFFFF
+#define ISIS_FERR_START 0x04000001
+#define ISIS_FERR_END 0x04FFFFFF
+#define LDP_FERR_START 0x05000001
+#define LDP_FERR_END 0x05FFFFFF
+#define LIB_FERR_START 0x06000001
+#define LIB_FERR_END 0x06FFFFFF
+#define NHRP_FERR_START 0x07000001
+#define NHRP_FERR_END 0x07FFFFFF
+#define OSPF_FERR_START 0x08000001
+#define OSPF_FERR_END 0x08FFFFFF
+#define OSPFV3_FERR_START 0x09000001
+#define OSPFV3_FERR_END 0x09FFFFFF
+#define PBR_FERR_START 0x0A000001
+#define PBR_FERR_END 0x0AFFFFFF
+#define PIM_FERR_START 0x0B000001
+#define PIM_FERR_STOP 0x0BFFFFFF
+#define RIP_FERR_START 0x0C000001
+#define RIP_FERR_STOP 0x0CFFFFFF
+#define RIPNG_FERR_START 0x0D000001
+#define RIPNG_FERR_STOP 0x0DFFFFFF
+#define SHARP_FERR_START 0x0E000001
+#define SHARP_FERR_END 0x0EFFFFFF
+#define VTYSH_FERR_START 0x0F000001
+#define VTYSH_FRR_END 0x0FFFFFFF
+#define WATCHFRR_FERR_START 0x10000001
+#define WATCHFRR_FERR_END 0x10FFFFFF
+#define ZEBRA_FERR_START 0xF1000001
+#define ZEBRA_FERR_END 0xF1FFFFFF
+#define END_FERR 0xFFFFFFFF
+
+struct log_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 log_ref_add(struct log_ref *ref);
+struct log_ref *log_ref_get(uint32_t code);
+void log_ref_display(struct vty *vty, uint32_t code, bool json);
+
+/*
+ * This function should be called by the
+ * code in libfrr.c
+ */
+void log_ref_init(void);
+void log_ref_fini(void);
+
/* get error details.
*
* NB: errval/ferr_r does NOT carry the full error information. It's only
@@ -101,8 +163,10 @@ struct ferr {
*/
const struct ferr *ferr_get_last(ferr_r errval);
-/* can optionally be called at strategic locations.
- * always returns 0. */
+/*
+ * Can optionally be called at strategic locations.
+ * Always returns 0.
+ */
ferr_r ferr_clear(void);
/* do NOT call these functions directly. only for macro use! */
diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c
index 3153e697fa..02d9b68bc1 100644
--- a/lib/frr_zmq.c
+++ b/lib/frr_zmq.c
@@ -24,6 +24,7 @@
#include "memory.h"
#include "frr_zmq.h"
#include "log.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, ZEROMQ_CB, "ZeroMQ callback")
@@ -140,7 +141,8 @@ static int frrzmq_read_msg(struct thread *t)
return 0;
out_err:
- zlog_err("ZeroMQ read error: %s(%d)", strerror(errno), errno);
+ flog_err(LIB_ERR_ZMQ, "ZeroMQ read error: %s(%d)", strerror(errno),
+ errno);
if (cb->read.cb_error)
cb->read.cb_error(cb->read.arg, cb->zmqsock);
return 1;
@@ -253,7 +255,8 @@ static int frrzmq_write_msg(struct thread *t)
return 0;
out_err:
- zlog_err("ZeroMQ write error: %s(%d)", strerror(errno), errno);
+ flog_err(LIB_ERR_ZMQ, "ZeroMQ write error: %s(%d)", strerror(errno),
+ errno);
if (cb->write.cb_error)
cb->write.cb_error(cb->write.arg, cb->zmqsock);
return 1;
diff --git a/lib/if.c b/lib/if.c
index e31ccd8563..6023624dc1 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -23,6 +23,7 @@
#include "linklist.h"
#include "vector.h"
+#include "lib_errors.h"
#include "vty.h"
#include "command.h"
#include "vrf.h"
@@ -626,7 +627,7 @@ static struct interface *if_sunwzebra_get(char *name, vrf_id_t vrf_id)
}
#endif /* SUNOS_5 */
-DEFUN (interface,
+DEFUN_NOSH (interface,
interface_cmd,
"interface IFNAME [vrf NAME]",
"Select an interface to configure\n"
@@ -669,13 +670,13 @@ DEFUN (interface,
return CMD_SUCCESS;
}
-DEFUN_NOSH (no_interface,
- no_interface_cmd,
- "no interface IFNAME [vrf NAME]",
- NO_STR
- "Delete a pseudo interface's configuration\n"
- "Interface's name\n"
- VRF_CMD_HELP_STR)
+DEFUN (no_interface,
+ no_interface_cmd,
+ "no interface IFNAME [vrf NAME]",
+ NO_STR
+ "Delete a pseudo interface's configuration\n"
+ "Interface's name\n"
+ VRF_CMD_HELP_STR)
{
int idx_vrf = 4;
const char *ifname = argv[2]->arg;
diff --git a/lib/if.h b/lib/if.h
index 7b65bbd2e5..3a9c4af848 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -297,28 +297,32 @@ DECLARE_QOBJ_TYPE(interface)
#define IFNAME_RB_INSERT(vrf, ifp) \
if (RB_INSERT(if_name_head, &vrf->ifaces_by_name, (ifp))) \
- zlog_err( \
+ flog_err( \
+ LIB_ERR_INTERFACE, \
"%s(%s): corruption detected -- interface with this " \
"name exists already in VRF %u!", \
__func__, (ifp)->name, (ifp)->vrf_id);
#define IFNAME_RB_REMOVE(vrf, ifp) \
if (RB_REMOVE(if_name_head, &vrf->ifaces_by_name, (ifp)) == NULL) \
- zlog_err( \
+ flog_err( \
+ LIB_ERR_INTERFACE, \
"%s(%s): corruption detected -- interface with this " \
"name doesn't exist in VRF %u!", \
__func__, (ifp)->name, (ifp)->vrf_id);
#define IFINDEX_RB_INSERT(vrf, ifp) \
if (RB_INSERT(if_index_head, &vrf->ifaces_by_index, (ifp))) \
- zlog_err( \
+ flog_err( \
+ LIB_ERR_INTERFACE, \
"%s(%u): corruption detected -- interface with this " \
"ifindex exists already in VRF %u!", \
__func__, (ifp)->ifindex, (ifp)->vrf_id);
#define IFINDEX_RB_REMOVE(vrf, ifp) \
if (RB_REMOVE(if_index_head, &vrf->ifaces_by_index, (ifp)) == NULL) \
- zlog_err( \
+ flog_err( \
+ LIB_ERR_INTERFACE, \
"%s(%u): corruption detected -- interface with this " \
"ifindex doesn't exist in VRF %u!", \
__func__, (ifp)->ifindex, (ifp)->vrf_id);
diff --git a/lib/json.h b/lib/json.h
index 675d852af7..788d1d6efa 100644
--- a/lib/json.h
+++ b/lib/json.h
@@ -23,6 +23,20 @@
#if defined(HAVE_JSON_C_JSON_H)
#include <json-c/json.h>
+
+/*
+ * FRR style JSON iteration.
+ * Usage: JSON_FOREACH(...) { ... }
+ */
+#define JSON_FOREACH(jo, joi, join) \
+ /* struct json_object *jo; */ \
+ /* struct json_object_iterator joi; */ \
+ /* struct json_object_iterator join; */ \
+ for ((joi) = json_object_iter_begin((jo)), \
+ (join) = json_object_iter_end((jo)); \
+ json_object_iter_equal(&(joi), &(join)) == 0; \
+ json_object_iter_next(&(joi)))
+
#else
#include <json/json.h>
diff --git a/lib/lib_errors.c b/lib/lib_errors.c
new file mode 100644
index 0000000000..332a5b1d45
--- /dev/null
+++ b/lib/lib_errors.c
@@ -0,0 +1,118 @@
+/*
+ * Library-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * 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
+ */
+
+#include "lib_errors.h"
+
+/* clang-format off */
+static struct log_ref ferr_lib_err[] = {
+ {
+ .code = LIB_ERR_PRIVILEGES,
+ .title = "Failure to raise or lower privileges",
+ .description = "FRR attempted to raise or lower its privileges and was unable to do so",
+ .suggestion = "Ensure that you are running FRR as the frr user and that the user has sufficient privileges to properly access root privileges"
+ },
+ {
+ .code = LIB_ERR_VRF_START,
+ .title = "VRF Failure on Start",
+ .description = "Upon startup FRR failed to properly initialize and startup the VRF subsystem",
+ .suggestion = "Ensure that there is sufficient memory to start processes and restart FRR",
+ },
+ {
+ .code = LIB_ERR_SOCKET,
+ .title = "Socket Error",
+ .description = "When attempting to access a socket a system error has occured and we were unable to properly complete the request",
+ .suggestion = "Ensure that there are sufficient system resources available and ensure that the frr user has sufficient permisions to work",
+ },
+ {
+ .code = LIB_ERR_ZAPI_MISSMATCH,
+ .title = "ZAPI Error",
+ .description = "A version miss-match has been detected between zebra and client protocol",
+ .suggestion = "Two different versions of FRR have been installed and the install is not properly setup. Completely stop FRR, remove it from the system and reinstall. Typically only developers should see this issue."
+ },
+ {
+ .code = LIB_ERR_ZAPI_ENCODE,
+ .title = "ZAPI Error",
+ .description = "The ZAPI subsystem has detected an encoding issue, between zebra and a client protocol",
+ .suggestion = "Restart FRR"
+ },
+ {
+ .code = LIB_ERR_ZAPI_SOCKET,
+ .title = "ZAPI Error",
+ .description = "The ZAPI subsystem has detected a socket error between zebra and a client",
+ .suggestion = "Restart FRR"
+ },
+ {
+ .code = LIB_ERR_SYSTEM_CALL,
+ .title = "System Call Error",
+ .description = "FRR has detected a error from using a vital system call and has probably already exited",
+ .suggestion = "Ensure permissions are correct for FRR files, users and groups are correct. Additionally check that sufficient system resources are available."
+ },
+ {
+ .code = LIB_ERR_VTY,
+ .title = "VTY Subsystem Error",
+ .description = "FRR has detected a problem with the specified configuration file",
+ .suggestion = "Ensure configuration file exists and has correct permissions for operations Additionally ensure that all config lines are correct as well",
+ },
+ {
+ .code = LIB_ERR_SNMP,
+ .title = "SNMP Subsystem Error",
+ .description = "FRR has detected a problem with the snmp library it uses A callback from this subsystem has indicated some error",
+ .suggestion = "Examine callback message and ensure snmp is properly setup and working"
+ },
+ {
+ .code = LIB_ERR_INTERFACE,
+ .title = "Interface Subsystem Error",
+ .description = "FRR has detected a problem with interface data from the kernel as it deviates from what we would expect to happen via normal netlink messaging",
+ .suggestion = "Open an Issue with all relevant log files and restart FRR"
+ },
+ {
+ .code = LIB_ERR_NS,
+ .title = "NameSpace Subsystem Error",
+ .description = "FRR has detected a problem with NameSpace data from the kernel as it deviates from what we would expect to happen via normal kernel messaging",
+ .suggestion = "Open an Issue with all relevant log files and restart FRR"
+ },
+ {
+ .code = LIB_ERR_DEVELOPMENT,
+ .title = "Developmental Escape Error",
+ .description = "FRR has detected an issue where new development has not properly updated all code paths.",
+ .suggestion = "Open an Issue with all relevant log files"
+ },
+ {
+ .code = LIB_ERR_ZMQ,
+ .title = "ZMQ Subsystem Error",
+ .description = "FRR has detected an issue with the Zero MQ subsystem and ZeroMQ is not working properly now",
+ .suggestion = "Open an Issue with all relevant log files and restart FRR"
+ },
+ {
+ .code = LIB_ERR_UNAVAILABLE,
+ .title = "Feature or system unavailable",
+ .description = "FRR was not compiled with support for a particular feature, or it is not available on the current platform",
+ .suggestion = "Recompile FRR with the feature enabled, or find out what platforms support the feature"
+ },
+ {
+ .code = END_FERR,
+ }
+};
+/* clang-format on */
+
+void lib_error_init(void)
+{
+ log_ref_add(ferr_lib_err);
+}
diff --git a/lib/lib_errors.h b/lib/lib_errors.h
new file mode 100644
index 0000000000..84f5b8dc10
--- /dev/null
+++ b/lib/lib_errors.h
@@ -0,0 +1,45 @@
+/*
+ * Library-specific error messages.
+ * Copyright (C) 2018 Cumulus Networks, Inc.
+ * Donald Sharp
+ *
+ * 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
+ */
+
+#ifndef __LIB_ERRORS_H__
+#define __LIB_ERRORS_H__
+
+#include "lib/ferr.h"
+
+enum lib_log_refs {
+ LIB_ERR_PRIVILEGES = LIB_FERR_START,
+ LIB_ERR_VRF_START,
+ LIB_ERR_SOCKET,
+ LIB_ERR_ZAPI_MISSMATCH,
+ LIB_ERR_ZAPI_ENCODE,
+ LIB_ERR_ZAPI_SOCKET,
+ LIB_ERR_SYSTEM_CALL,
+ LIB_ERR_VTY,
+ LIB_ERR_SNMP,
+ LIB_ERR_INTERFACE,
+ LIB_ERR_NS,
+ LIB_ERR_DEVELOPMENT,
+ LIB_ERR_ZMQ,
+ LIB_ERR_UNAVAILABLE,
+};
+
+extern void lib_error_init(void);
+
+#endif
diff --git a/lib/libfrr.c b/lib/libfrr.c
index 86a5bd29f8..821c57f37b 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -35,6 +35,7 @@
#include "log_int.h"
#include "module.h"
#include "network.h"
+#include "lib_errors.h"
DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm))
DEFINE_KOOH(frr_early_fini, (), ())
@@ -598,6 +599,9 @@ struct thread_master *frr_init(void)
vty_init(master);
memory_init();
+ log_ref_init();
+ lib_error_init();
+
return master;
}
@@ -825,8 +829,9 @@ static void frr_terminal_close(int isexit)
nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
if (nullfd == -1) {
- zlog_err("%s: failed to open /dev/null: %s", __func__,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: failed to open /dev/null: %s", __func__,
+ safe_strerror(errno));
} else {
dup2(nullfd, 0);
dup2(nullfd, 1);
@@ -897,8 +902,9 @@ void frr_run(struct thread_master *master)
} else if (di->daemon_mode) {
int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY);
if (nullfd == -1) {
- zlog_err("%s: failed to open /dev/null: %s", __func__,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "%s: failed to open /dev/null: %s",
+ __func__, safe_strerror(errno));
} else {
dup2(nullfd, 0);
dup2(nullfd, 1);
@@ -935,6 +941,7 @@ void frr_fini(void)
/* memory_init -> nothing needed */
vty_terminate();
cmd_terminate();
+ log_ref_fini();
zprivs_terminate(di->privs);
/* signal_init -> nothing needed */
thread_master_free(master);
diff --git a/lib/linklist.c b/lib/linklist.c
index 86649dd495..effd384e46 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -70,6 +70,26 @@ void listnode_add(struct list *list, void *val)
list->count++;
}
+void listnode_add_head(struct list *list, void *val)
+{
+ struct listnode *node;
+
+ assert(val != NULL);
+
+ node = listnode_new();
+
+ node->next = list->head;
+ node->data = val;
+
+ if (list->head == NULL)
+ list->head = node;
+ else
+ list->head->prev = node;
+ list->head = node;
+
+ list->count++;
+}
+
void listnode_add_sort(struct list *list, void *val)
{
struct listnode *n;
diff --git a/lib/linklist.h b/lib/linklist.h
index cee6c1e505..f5cd44efb0 100644
--- a/lib/linklist.h
+++ b/lib/linklist.h
@@ -83,6 +83,19 @@ extern struct list *list_new(void);
extern void listnode_add(struct list *list, void *data);
/*
+ * Add a new element to the beginning of a list.
+ *
+ * Runtime is O(1).
+ *
+ * list
+ * list to operate on
+ *
+ * data
+ * element to add
+ */
+extern void listnode_add_head(struct list *list, void *data);
+
+/*
* Insert a new element into a list with insertion sort.
*
* If list->cmp is set, this function is used to determine the position to
diff --git a/lib/log.c b/lib/log.c
index 1345ff2fd1..e011a78f1c 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -28,6 +28,8 @@
#include "log_int.h"
#include "memory.h"
#include "command.h"
+#include "lib_errors.h"
+
#ifndef SUNOS_5
#include <sys/un.h>
#endif
@@ -631,7 +633,8 @@ void zlog_backtrace(int priority)
size = backtrace(array, array_size(array));
if (size <= 0 || (size_t)size > array_size(array)) {
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Cannot get backtrace, returned invalid # of frames %d "
"(valid range is between 1 and %lu)",
size, (unsigned long)(array_size(array)));
@@ -639,7 +642,8 @@ void zlog_backtrace(int priority)
}
zlog(priority, "Backtrace for %d stack frames:", size);
if (!(strings = backtrace_symbols(array, size))) {
- zlog_err("Cannot get backtrace symbols (out of memory?)");
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Cannot get backtrace symbols (out of memory?)");
for (i = 0; i < size; i++)
zlog(priority, "[bt %d] %p", i, array[i]);
} else {
@@ -712,10 +716,10 @@ void _zlog_assert_failed(const char *assertion, const char *file,
void memory_oom(size_t size, const char *name)
{
- zlog_err(
- "out of memory: failed to allocate %zu bytes for %s"
- "object",
- size, name);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "out of memory: failed to allocate %zu bytes for %s"
+ "object",
+ size, name);
zlog_backtrace(LOG_ERR);
abort();
}
@@ -864,7 +868,8 @@ int zlog_rotate(void)
save_errno = errno;
umask(oldumask);
if (zl->fp == NULL) {
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Log rotate failed: cannot open file %s for append: %s",
zl->filename, safe_strerror(save_errno));
ret = -1;
@@ -984,7 +989,8 @@ static const struct zebra_desc_table *zroute_lookup(unsigned int zroute)
unsigned int i;
if (zroute >= array_size(route_types)) {
- zlog_err("unknown zebra route type: %u", zroute);
+ flog_err(LIB_ERR_DEVELOPMENT, "unknown zebra route type: %u",
+ zroute);
return &unknown;
}
if (zroute == route_types[zroute].type)
@@ -998,7 +1004,9 @@ static const struct zebra_desc_table *zroute_lookup(unsigned int zroute)
return &route_types[i];
}
}
- zlog_err("internal error: cannot find route type %u in table!", zroute);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "internal error: cannot find route type %u in table!",
+ zroute);
return &unknown;
}
@@ -1015,7 +1023,8 @@ char zebra_route_char(unsigned int zroute)
const char *zserv_command_string(unsigned int command)
{
if (command >= array_size(command_types)) {
- zlog_err("unknown zserv command type: %u", command);
+ flog_err(LIB_ERR_DEVELOPMENT, "unknown zserv command type: %u",
+ command);
return unknown.string;
}
return command_types[command].string;
diff --git a/lib/log.h b/lib/log.h
index 07eb6d5bd5..980f3ddf4b 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -85,6 +85,13 @@ 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 flog_err(ferr_id, format, ...) \
+ zlog_err("[EC %d] " format, ferr_id, ##__VA_ARGS__)
+#define flog_err_sys(ferr_id, format, ...) \
+ flog_err(ferr_id, format, ##__VA_ARGS__)
+
+
extern void zlog_thread_info(int log_level);
/* Set logging level for the given destination. If the log_level
diff --git a/lib/memory.c b/lib/memory.c
index e279b17d12..87cba69fc5 100644
--- a/lib/memory.c
+++ b/lib/memory.c
@@ -17,6 +17,12 @@
#include <zebra.h>
#include <stdlib.h>
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_MALLOC_MALLOC_H
+#include <malloc/malloc.h>
+#endif
#include "memory.h"
#include "log.h"
@@ -28,7 +34,7 @@ DEFINE_MGROUP(LIB, "libfrr")
DEFINE_MTYPE(LIB, TMP, "Temporary memory")
DEFINE_MTYPE(LIB, PREFIX_FLOWSPEC, "Prefix Flowspec")
-static inline void mt_count_alloc(struct memtype *mt, size_t size)
+static inline void mt_count_alloc(struct memtype *mt, size_t size, void *ptr)
{
size_t oldsize;
@@ -41,12 +47,24 @@ static inline void mt_count_alloc(struct memtype *mt, size_t size)
if (oldsize != 0 && oldsize != size && oldsize != SIZE_VAR)
atomic_store_explicit(&mt->size, SIZE_VAR,
memory_order_relaxed);
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
+ size_t mallocsz = malloc_usable_size(ptr);
+
+ atomic_fetch_add_explicit(&mt->total, mallocsz, memory_order_relaxed);
+#endif
}
-static inline void mt_count_free(struct memtype *mt)
+static inline void mt_count_free(struct memtype *mt, void *ptr)
{
assert(mt->n_alloc);
atomic_fetch_sub_explicit(&mt->n_alloc, 1, memory_order_relaxed);
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
+ size_t mallocsz = malloc_usable_size(ptr);
+
+ atomic_fetch_sub_explicit(&mt->total, mallocsz, memory_order_relaxed);
+#endif
}
static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
@@ -58,7 +76,7 @@ static inline void *mt_checkalloc(struct memtype *mt, void *ptr, size_t size)
}
return NULL;
}
- mt_count_alloc(mt, size);
+ mt_count_alloc(mt, size, ptr);
return ptr;
}
@@ -75,7 +93,7 @@ void *qcalloc(struct memtype *mt, size_t size)
void *qrealloc(struct memtype *mt, void *ptr, size_t size)
{
if (ptr)
- mt_count_free(mt);
+ mt_count_free(mt, ptr);
return mt_checkalloc(mt, ptr ? realloc(ptr, size) : malloc(size), size);
}
@@ -87,7 +105,7 @@ void *qstrdup(struct memtype *mt, const char *str)
void qfree(struct memtype *mt, void *ptr)
{
if (ptr)
- mt_count_free(mt);
+ mt_count_free(mt, ptr);
free(ptr);
}
diff --git a/lib/memory.h b/lib/memory.h
index 1fbbbe4231..c39f34e3a7 100644
--- a/lib/memory.h
+++ b/lib/memory.h
@@ -24,12 +24,20 @@
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
+#if defined(HAVE_MALLOC_SIZE) && !defined(HAVE_MALLOC_USABLE_SIZE)
+#define malloc_usable_size(x) malloc_size(x)
+#define HAVE_MALLOC_USABLE_SIZE
+#endif
+
#define SIZE_VAR ~0UL
struct memtype {
struct memtype *next, **ref;
const char *name;
_Atomic size_t n_alloc;
_Atomic size_t size;
+#ifdef HAVE_MALLOC_USABLE_SIZE
+ _Atomic size_t total;
+#endif
};
struct memgroup {
diff --git a/lib/memory_vty.c b/lib/memory_vty.c
index 972914bf24..9ee2e52ec7 100644
--- a/lib/memory_vty.c
+++ b/lib/memory_vty.c
@@ -21,9 +21,12 @@
#include <zebra.h>
/* malloc.h is generally obsolete, however GNU Libc mallinfo wants it. */
-#if (defined(GNU_LINUX) && defined(HAVE_MALLINFO))
+#ifdef HAVE_MALLOC_H
#include <malloc.h>
-#endif /* HAVE_MALLINFO */
+#endif
+#ifdef HAVE_MALLOC_MALLOC_H
+#include <malloc/malloc.h>
+#endif
#include <dlfcn.h>
#include <link.h>
@@ -76,12 +79,21 @@ static int qmem_walker(void *arg, struct memgroup *mg, struct memtype *mt)
if (mt->n_alloc != 0) {
char size[32];
snprintf(size, sizeof(size), "%6zu", mt->size);
- vty_out(vty, "%-30s: %10zu %s\n", mt->name,
+
+#ifdef HAVE_MALLOC_USABLE_SIZE
+#define TSTR " %9zu"
+#define TARG , mt->total
+#else
+#define TSTR ""
+#define TARG
+#endif
+ vty_out(vty, "%-30s: %10zu %-16s"TSTR"\n", mt->name,
mt->n_alloc,
mt->size == 0 ? ""
: mt->size == SIZE_VAR
? "(variably sized)"
- : size);
+ : size
+ TARG);
}
}
return 0;
diff --git a/lib/mpls.h b/lib/mpls.h
index ff6f1d6c98..c9dd60dce0 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -22,6 +22,7 @@
#ifndef _QUAGGA_MPLS_H
#define _QUAGGA_MPLS_H
+#include <zebra.h>
#include <arpa/inet.h>
#ifdef MPLS_LABEL_MAX
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index a80b51fa00..b8eaa72c22 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -35,10 +35,10 @@
#include "ns.h"
#include "log.h"
#include "memory.h"
-
#include "command.h"
#include "vty.h"
#include "vrf.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, NS, "NetNS Context")
DEFINE_MTYPE_STATIC(LIB, NS_NAME, "NetNS Name")
@@ -219,15 +219,17 @@ static int ns_enable_internal(struct ns *ns, void (*func)(ns_id_t, void *))
}
if (!ns_is_enabled(ns)) {
- zlog_err("Can not enable NS %u: %s!", ns->ns_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Can not enable NS %u: %s!", ns->ns_id,
+ safe_strerror(errno));
return 0;
}
/* Non default NS. leave */
if (ns->ns_id == NS_UNKNOWN) {
- zlog_err("Can not enable NS %s %u: Invalid NSID",
- ns->name, ns->ns_id);
+ flog_err(LIB_ERR_NS,
+ "Can not enable NS %s %u: Invalid NSID",
+ ns->name, ns->ns_id);
return 0;
}
if (func)
@@ -470,8 +472,9 @@ void ns_init(void)
if (have_netns_enabled < 0) {
ns_default_ns_fd = open(NS_DEFAULT_NAME, O_RDONLY);
if (ns_default_ns_fd == -1)
- zlog_err("NS initialization failure %d(%s)",
- errno, safe_strerror(errno));
+ flog_err(LIB_ERR_NS,
+ "NS initialization failure %d(%s)", errno,
+ safe_strerror(errno));
} else {
ns_default_ns_fd = -1;
default_ns = NULL;
@@ -492,7 +495,8 @@ void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns)
ns_init();
default_ns = ns_get_created_internal(NULL, NULL, default_ns_id);
if (!default_ns) {
- zlog_err("%s: failed to create the default NS!", __func__);
+ flog_err(LIB_ERR_NS, "%s: failed to create the default NS!",
+ __func__);
exit(1);
}
if (have_netns()) {
@@ -509,7 +513,8 @@ void ns_init_management(ns_id_t default_ns_id, ns_id_t internal_ns)
/* Enable the default NS. */
if (!ns_enable(default_ns, NULL)) {
- zlog_err("%s: failed to enable the default NS!", __func__);
+ flog_err(LIB_ERR_NS, "%s: failed to enable the default NS!",
+ __func__);
exit(1);
}
}
diff --git a/lib/pid_output.c b/lib/pid_output.c
index 023a166f27..c6120de861 100644
--- a/lib/pid_output.c
+++ b/lib/pid_output.c
@@ -24,6 +24,7 @@
#include <log.h>
#include "version.h"
#include "network.h"
+#include "lib_errors.h"
#define PIDFILE_MASK 0644
@@ -41,8 +42,9 @@ pid_t pid_output(const char *path)
oldumask = umask(0777 & ~PIDFILE_MASK);
fd = open(path, O_RDWR | O_CREAT, PIDFILE_MASK);
if (fd < 0) {
- zlog_err("Can't create pid lock file %s (%s), exiting", path,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Can't create pid lock file %s (%s), exiting",
+ path, safe_strerror(errno));
umask(oldumask);
exit(1);
} else {
@@ -57,19 +59,22 @@ pid_t pid_output(const char *path)
lock.l_whence = SEEK_SET;
if (fcntl(fd, F_SETLK, &lock) < 0) {
- zlog_err("Could not lock pid_file %s (%s), exiting",
- path, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Could not lock pid_file %s (%s), exiting",
+ path, safe_strerror(errno));
exit(1);
}
sprintf(buf, "%d\n", (int)pid);
pidsize = strlen(buf);
if ((tmp = write(fd, buf, pidsize)) != (int)pidsize)
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Could not write pid %d to pid_file %s, rc was %d: %s",
(int)pid, path, tmp, safe_strerror(errno));
else if (ftruncate(fd, pidsize) < 0)
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Could not truncate pid_file %s to %u bytes: %s",
path, (unsigned int)pidsize,
safe_strerror(errno));
diff --git a/lib/prefix.c b/lib/prefix.c
index 751f20cb83..a7f4fda1b2 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -27,6 +27,7 @@
#include "memory.h"
#include "log.h"
#include "jhash.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, PREFIX, "Prefix")
@@ -656,8 +657,9 @@ void prefix_copy(struct prefix *dest, const struct prefix *src)
memcpy((void *)dest->u.prefix_flowspec.ptr,
(void *)src->u.prefix_flowspec.ptr, len);
} else {
- zlog_err("prefix_copy(): Unknown address family %d",
- src->family);
+ flog_err(LIB_ERR_DEVELOPMENT,
+ "prefix_copy(): Unknown address family %d",
+ src->family);
assert(0);
}
}
diff --git a/lib/privs.c b/lib/privs.c
index 7c99742d34..34905ca480 100644
--- a/lib/privs.c
+++ b/lib/privs.c
@@ -696,6 +696,41 @@ static int getgrouplist(const char *user, gid_t group, gid_t *groups,
}
#endif /* HAVE_GETGROUPLIST */
+struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
+ const char *funcname)
+{
+ int save_errno = errno;
+
+ if (!privs)
+ return NULL;
+
+ errno = 0;
+ if (privs->change(ZPRIVS_RAISE)) {
+ zlog_err("%s: Failed to raise privileges (%s)",
+ funcname, safe_strerror(errno));
+ }
+ errno = save_errno;
+ privs->raised_in_funcname = funcname;
+ return privs;
+}
+
+void _zprivs_lower(struct zebra_privs_t **privs)
+{
+ int save_errno = errno;
+
+ if (!*privs)
+ return;
+
+ errno = 0;
+ if ((*privs)->change(ZPRIVS_LOWER)) {
+ zlog_err("%s: Failed to lower privileges (%s)",
+ (*privs)->raised_in_funcname, safe_strerror(errno));
+ }
+ errno = save_errno;
+ (*privs)->raised_in_funcname = NULL;
+ *privs = NULL;
+}
+
void zprivs_preinit(struct zebra_privs_t *zprivs)
{
struct passwd *pwentry = NULL;
diff --git a/lib/privs.h b/lib/privs.h
index 7fe59328b2..b061370b75 100644
--- a/lib/privs.h
+++ b/lib/privs.h
@@ -62,6 +62,7 @@ struct zebra_privs_t {
int (*change)(zebra_privs_ops_t); /* change privileges, 0 on success */
zebra_privs_current_t (*current_state)(
void); /* current privilege state */
+ const char *raised_in_funcname;
};
struct zprivs_ids_t {
@@ -81,4 +82,42 @@ extern void zprivs_terminate(struct zebra_privs_t *);
/* query for runtime uid's and gid's, eg vty needs this */
extern void zprivs_get_ids(struct zprivs_ids_t *);
+/*
+ * Wrapper around zprivs, to be used as:
+ * frr_elevate_privs(&privs) {
+ * ... code ...
+ * if (error)
+ * break; -- break can be used to get out of the block
+ * ... code ...
+ * }
+ *
+ * The argument to frr_elevate_privs() can be NULL to leave privileges as-is
+ * (mostly useful for conditional privilege-raising, i.e.:)
+ * frr_elevate_privs(cond ? &privs : NULL) {}
+ *
+ * NB: The code block is always executed, regardless of whether privileges
+ * could be raised or not, or whether NULL was given or not. This is fully
+ * intentional; the user may have configured some RBAC or similar that we
+ * are not aware of, but that allows our code to proceed without privileges.
+ *
+ * The point of this wrapper is to prevent accidental bugs where privileges
+ * are elevated but then not dropped. This can happen when, for example, a
+ * "return", "goto" or "break" in the middle of the elevated-privilege code
+ * skips past the privilege dropping call.
+ *
+ * The macro below uses variable cleanup to drop privileges as soon as the
+ * code block is left in any way (and thus the _privs variable goes out of
+ * scope.) _once is just a trick to run the loop exactly once.
+ */
+extern struct zebra_privs_t *_zprivs_raise(struct zebra_privs_t *privs,
+ const char *funcname);
+extern void _zprivs_lower(struct zebra_privs_t **privs);
+
+#define frr_elevate_privs(privs) \
+ for (struct zebra_privs_t *_once = NULL, \
+ *_privs __attribute__( \
+ (unused, cleanup(_zprivs_lower))) = \
+ _zprivs_raise(privs, __func__); \
+ _once == NULL; _once = (void *)1)
+
#endif /* _ZEBRA_PRIVS_H */
diff --git a/lib/route_types.txt b/lib/route_types.txt
index cfa55e468c..72f59a1b78 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -81,6 +81,7 @@ ZEBRA_ROUTE_BGP_DIRECT_EXT, bgp-direct-to-nve-groups, NULL, 'e', 0, 0, 0, "BGP2V
ZEBRA_ROUTE_BABEL, babel, babeld, 'A', 1, 1, 1, "Babel"
ZEBRA_ROUTE_SHARP, sharp, sharpd, 'D', 1, 1, 1, "SHARP"
ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
+ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
@@ -107,3 +108,4 @@ ZEBRA_ROUTE_VNC_DIRECT, "VNC direct (not via zebra) routes"
ZEBRA_ROUTE_BABEL, "Babel routing protocol (Babel)"
ZEBRA_ROUTE_SHARP, "Super Happy Advanced Routing Protocol (sharpd)"
ZEBRA_ROUTE_PBR, "Policy Based Routing (PBR)"
+ZEBRA_ROUTE_BFD, "Bidirectional Fowarding Detection (BFD)"
diff --git a/lib/sigevent.c b/lib/sigevent.c
index 59eaa80370..0346027935 100644
--- a/lib/sigevent.c
+++ b/lib/sigevent.c
@@ -22,6 +22,7 @@
#include <sigevent.h>
#include <log.h>
#include <memory.h>
+#include <lib_errors.h>
#ifdef SA_SIGINFO
#ifdef HAVE_UCONTEXT_H
@@ -83,7 +84,8 @@ int quagga_sigevent_process(void)
sigdelset(&newmask, SIGKILL);
if ((sigprocmask(SIG_BLOCK, &newmask, &oldmask)) < 0) {
- zlog_err("quagga_signal_timer: couldnt block signals!");
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "quagga_signal_timer: couldnt block signals!");
return -1;
}
#endif /* SIGEVENT_BLOCK_SIGNALS */
diff --git a/lib/skiplist.c b/lib/skiplist.c
index a546bb44c0..a36bf47139 100644
--- a/lib/skiplist.c
+++ b/lib/skiplist.c
@@ -60,6 +60,7 @@
#include "log.h"
#include "vty.h"
#include "skiplist.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, SKIP_LIST, "Skip List")
DEFINE_MTYPE_STATIC(LIB, SKIP_LIST_NODE, "Skip Node")
@@ -182,7 +183,8 @@ int skiplist_insert(register struct skiplist *l, register void *key,
/* DEBUG */
if (!key) {
- zlog_err("%s: key is 0, value is %p", __func__, value);
+ flog_err(LIB_ERR_DEVELOPMENT, "%s: key is 0, value is %p",
+ __func__, value);
}
p = l->header;
diff --git a/lib/sockopt.c b/lib/sockopt.c
index e979bef174..878b5ae09d 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -27,6 +27,7 @@
#include "log.h"
#include "sockopt.h"
#include "sockunion.h"
+#include "lib_errors.h"
void setsockopt_so_recvbuf(int sock, int size)
{
@@ -61,8 +62,9 @@ int getsockopt_so_sendbuf(const int sock)
int ret = getsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char *)&optval,
&optlen);
if (ret < 0) {
- zlog_err("fd %d: can't getsockopt SO_SNDBUF: %d (%s)", sock,
- errno, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "fd %d: can't getsockopt SO_SNDBUF: %d (%s)", sock,
+ errno, safe_strerror(errno));
return ret;
}
return optval;
@@ -73,7 +75,7 @@ static void *getsockopt_cmsg_data(struct msghdr *msgh, int level, int type)
struct cmsghdr *cmsg;
void *ptr = NULL;
- for (cmsg = ZCMSG_FIRSTHDR(msgh); cmsg != NULL;
+ for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != NULL;
cmsg = CMSG_NXTHDR(msgh, cmsg))
if (cmsg->cmsg_level == level && cmsg->cmsg_type == type)
return (ptr = CMSG_DATA(cmsg));
@@ -670,8 +672,10 @@ int sockopt_tcp_signature(int sock, union sockunion *su, const char *password)
if (ENOENT == errno)
ret = 0;
else
- zlog_err("sockopt_tcp_signature: setsockopt(%d): %s",
- sock, safe_strerror(errno));
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
+ "sockopt_tcp_signature: setsockopt(%d): %s",
+ sock, safe_strerror(errno));
}
return ret;
#else /* HAVE_TCP_MD5SIG */
diff --git a/lib/sockunion.c b/lib/sockunion.c
index 44378b5363..bbbfbfc424 100644
--- a/lib/sockunion.c
+++ b/lib/sockunion.c
@@ -26,6 +26,7 @@
#include "memory.h"
#include "log.h"
#include "jhash.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, SOCKUNION, "Socket union")
@@ -365,14 +366,10 @@ int sockopt_mark_default(int sock, int mark, struct zebra_privs_t *cap)
#ifdef SO_MARK
int ret;
- if (cap->change(ZPRIVS_RAISE))
- zlog_err("routing_socket: Can't raise privileges");
-
- ret = setsockopt(sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
-
- if (cap->change(ZPRIVS_LOWER))
- zlog_err("routing_socket: Can't lower privileges");
-
+ frr_elevate_privs(cap) {
+ ret = setsockopt(sock, SOL_SOCKET, SO_MARK, &mark,
+ sizeof(mark));
+ }
return ret;
#else
return 0;
diff --git a/lib/subdir.am b/lib/subdir.am
index 9eaae59df8..b938dbcea3 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -35,6 +35,7 @@ lib_libfrr_la_SOURCES = \
lib/jhash.c \
lib/json.c \
lib/keychain.c \
+ lib/lib_errors.c \
lib/libfrr.c \
lib/linklist.c \
lib/log.c \
@@ -118,6 +119,7 @@ pkginclude_HEADERS += \
lib/jhash.h \
lib/json.h \
lib/keychain.h \
+ lib/lib_errors.h \
lib/libfrr.h \
lib/libospf.h \
lib/linklist.h \
diff --git a/lib/vrf.c b/lib/vrf.c
index ca50c1e70e..36111dfeae 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -35,6 +35,7 @@
#include "ns.h"
#include "privs.h"
#include "nexthop_group.h"
+#include "lib_errors.h"
/* default VRF ID value used when VRF backend is not NETNS */
#define VRF_DEFAULT_INTERNAL 0
@@ -466,13 +467,15 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
/* The default VRF always exists. */
default_vrf = vrf_get(VRF_DEFAULT, VRF_DEFAULT_NAME);
if (!default_vrf) {
- zlog_err("vrf_init: failed to create the default VRF!");
+ flog_err(LIB_ERR_VRF_START,
+ "vrf_init: failed to create the default VRF!");
exit(1);
}
/* Enable the default VRF. */
if (!vrf_enable(default_vrf)) {
- zlog_err("vrf_init: failed to enable the default VRF!");
+ flog_err(LIB_ERR_VRF_START,
+ "vrf_init: failed to enable the default VRF!");
exit(1);
}
@@ -542,20 +545,23 @@ int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
+
if (ret > 0 && interfacename && vrf_default_accepts_vrf(type)) {
zlog_err("VRF socket not used since net.ipv4.%s_l3mdev_accept != 0",
(type == SOCK_STREAM ? "tcp" : "udp"));
errno = EEXIST; /* not sure if this is the best error... */
return -2;
}
+
ret = socket(domain, type, protocol);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- zlog_err("%s: Can't switchback from VRF %u (%s)", __func__,
- vrf_id, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
errno = save_errno;
if (ret <= 0)
return ret;
@@ -711,12 +717,12 @@ DEFUN_NOSH (vrf,
return vrf_handler_create(vty, vrfname, NULL);
}
-DEFUN_NOSH (no_vrf,
- no_vrf_cmd,
- "no vrf NAME",
- NO_STR
- "Delete a pseudo VRF's configuration\n"
- "VRF's name\n")
+DEFUN (no_vrf,
+ no_vrf_cmd,
+ "no vrf NAME",
+ NO_STR
+ "Delete a pseudo VRF's configuration\n"
+ "VRF's name\n")
{
const char *vrfname = argv[2]->arg;
@@ -744,7 +750,7 @@ DEFUN_NOSH (no_vrf,
struct cmd_node vrf_node = {VRF_NODE, "%s(config-vrf)# ", 1};
-DEFUN (vrf_netns,
+DEFUN_NOSH (vrf_netns,
vrf_netns_cmd,
"netns NAME",
"Attach VRF to a Namespace\n"
@@ -758,20 +764,14 @@ DEFUN (vrf_netns,
if (!pathname)
return CMD_WARNING_CONFIG_FAILED;
- if (vrf_daemon_privs &&
- vrf_daemon_privs->change(ZPRIVS_RAISE))
- zlog_err("%s: Can't raise privileges", __func__);
-
- ret = vrf_netns_handler_create(vty, vrf, pathname,
- NS_UNKNOWN, NS_UNKNOWN);
-
- if (vrf_daemon_privs &&
- vrf_daemon_privs->change(ZPRIVS_LOWER))
- zlog_err("%s: Can't lower privileges", __func__);
+ frr_elevate_privs(vrf_daemon_privs) {
+ ret = vrf_netns_handler_create(vty, vrf, pathname,
+ NS_UNKNOWN, NS_UNKNOWN);
+ }
return ret;
}
-DEFUN (no_vrf_netns,
+DEFUN_NOSH (no_vrf_netns,
no_vrf_netns_cmd,
"no netns [NAME]",
NO_STR
@@ -905,14 +905,15 @@ int vrf_getaddrinfo(const char *node, const char *service,
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
ret = getaddrinfo(node, service, hints, res);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- zlog_err("%s: Can't switchback from VRF %u (%s)", __func__,
- vrf_id, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
errno = save_errno;
return ret;
}
@@ -923,16 +924,17 @@ int vrf_ioctl(vrf_id_t vrf_id, int d, unsigned long request, char *params)
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0) {
- zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
return 0;
}
rc = ioctl(d, request, params);
saved_errno = errno;
ret = vrf_switchback_to_initial();
if (ret < 0)
- zlog_err("%s: Can't switchback from VRF %u (%s)", __func__,
- vrf_id, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
errno = saved_errno;
return rc;
}
@@ -944,14 +946,15 @@ int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id,
ret = vrf_switch_to_netns(vrf_id);
if (ret < 0)
- zlog_err("%s: Can't switch to VRF %u (%s)", __func__, vrf_id,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "%s: Can't switch to VRF %u (%s)",
+ __func__, vrf_id, safe_strerror(errno));
ret = sockunion_socket(su);
save_errno = errno;
ret2 = vrf_switchback_to_initial();
if (ret2 < 0)
- zlog_err("%s: Can't switchback from VRF %u (%s)", __func__,
- vrf_id, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "%s: Can't switchback from VRF %u (%s)", __func__,
+ vrf_id, safe_strerror(errno));
errno = save_errno;
if (ret <= 0)
diff --git a/lib/vty.c b/lib/vty.c
index 073092dfb6..748c14f675 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -40,6 +40,7 @@
#include "network.h"
#include "libfrr.h"
#include "frrstr.h"
+#include "lib_errors.h"
#include <arpa/telnet.h>
#include <termios.h>
@@ -511,7 +512,7 @@ static int vty_command(struct vty *vty, char *buf)
vty_str);
/* now log the command */
- zlog_err("%s%s", prompt_str, buf);
+ zlog_notice("%s%s", prompt_str, buf);
}
#ifdef CONSUMED_TIME_CHECK
@@ -814,6 +815,8 @@ static void vty_end_config(struct vty *vty)
case KEYCHAIN_KEY_NODE:
case VTY_NODE:
case BGP_EVPN_VNI_NODE:
+ case BFD_NODE:
+ case BFD_PEER_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
break;
@@ -1210,6 +1213,8 @@ static void vty_stop_input(struct vty *vty)
case KEYCHAIN_NODE:
case KEYCHAIN_KEY_NODE:
case VTY_NODE:
+ case BFD_NODE:
+ case BFD_PEER_NODE:
vty_config_unlock(vty);
vty->node = ENABLE_NODE;
break;
@@ -1325,9 +1330,9 @@ static int vty_telnet_option(struct vty *vty, unsigned char *buf, int nbytes)
TELNET_NAWS_SB_LEN,
(unsigned long)vty->sb_len);
else if (sizeof(vty->sb_buf) < TELNET_NAWS_SB_LEN)
- zlog_err(
- "Bug detected: sizeof(vty->sb_buf) %lu < %d, "
- "too small to handle the telnet NAWS option",
+ flog_err(
+ LIB_ERR_DEVELOPMENT,
+ "Bug detected: sizeof(vty->sb_buf) %lu < %d, too small to handle the telnet NAWS option",
(unsigned long)sizeof(vty->sb_buf),
TELNET_NAWS_SB_LEN);
else {
@@ -1968,7 +1973,8 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port)
ret = getaddrinfo(hostname, port_str, &req, &ainfo);
if (ret != 0) {
- zlog_err("getaddrinfo failed: %s", gai_strerror(ret));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL, "getaddrinfo failed: %s",
+ gai_strerror(ret));
exit(1);
}
@@ -2028,8 +2034,9 @@ static void vty_serv_un(const char *path)
/* Make UNIX domain socket. */
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock < 0) {
- zlog_err("Cannot create unix stream socket: %s",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET,
+ "Cannot create unix stream socket: %s",
+ safe_strerror(errno));
return;
}
@@ -2047,15 +2054,16 @@ static void vty_serv_un(const char *path)
ret = bind(sock, (struct sockaddr *)&serv, len);
if (ret < 0) {
- zlog_err("Cannot bind path %s: %s", path, safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "Cannot bind path %s: %s", path,
+ safe_strerror(errno));
close(sock); /* Avoid sd leak. */
return;
}
ret = listen(sock, 5);
if (ret < 0) {
- zlog_err("listen(fd %d) failed: %s", sock,
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SOCKET, "listen(fd %d) failed: %s", sock,
+ safe_strerror(errno));
close(sock); /* Avoid sd leak. */
return;
}
@@ -2070,8 +2078,9 @@ static void vty_serv_un(const char *path)
if ((int)ids.gid_vty > 0) {
/* set group of socket */
if (chown(path, -1, ids.gid_vty)) {
- zlog_err("vty_serv_un: could chown socket, %s",
- safe_strerror(errno));
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "vty_serv_un: could chown socket, %s",
+ safe_strerror(errno));
}
}
@@ -2303,9 +2312,9 @@ void vty_close(struct vty *vty)
* additionally, we'd need to replace these fds with /dev/null. */
if (vty->wfd > STDERR_FILENO && vty->wfd != vty->fd)
close(vty->wfd);
- if (vty->fd > STDERR_FILENO) {
+ if (vty->fd > STDERR_FILENO)
close(vty->fd);
- } else
+ if (vty->fd == STDIN_FILENO)
was_stdio = true;
if (vty->buf)
@@ -2402,8 +2411,9 @@ static void vty_read_file(FILE *confp)
nl = strchr(vty->error_buf, '\n');
if (nl)
*nl = '\0';
- zlog_err("ERROR: %s on config line %u: %s", message, line_num,
- vty->error_buf);
+ flog_err(LIB_ERR_VTY,
+ "ERROR: %s on config line %u: %s", message, line_num,
+ vty->error_buf);
}
vty_close(vty);
@@ -2476,7 +2486,8 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
if (config_file != NULL) {
if (!IS_DIRECTORY_SEP(config_file[0])) {
if (getcwd(cwd, MAXPATHLEN) == NULL) {
- zlog_err(
+ flog_err_sys(
+ LIB_ERR_SYSTEM_CALL,
"Failure to determine Current Working Directory %d!",
errno);
exit(1);
@@ -2491,7 +2502,7 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
confp = fopen(fullpath, "r");
if (confp == NULL) {
- zlog_err("%s: failed to open configuration file %s: %s",
+ zlog_warn("%s: failed to open configuration file %s: %s, checking backup",
__func__, fullpath, safe_strerror(errno));
confp = vty_use_backup_config(fullpath);
@@ -2499,8 +2510,9 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
zlog_warn(
"WARNING: using backup configuration file!");
else {
- zlog_err("can't open configuration file [%s]",
- config_file);
+ flog_err(LIB_ERR_VTY,
+ "can't open configuration file [%s]",
+ config_file);
exit(1);
}
}
@@ -2536,9 +2548,9 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
#endif /* VTYSH */
confp = fopen(config_default_dir, "r");
if (confp == NULL) {
- zlog_err("%s: failed to open configuration file %s: %s",
- __func__, config_default_dir,
- safe_strerror(errno));
+ zlog_warn("%s: failed to open configuration file %s: %s, checking backup",
+ __func__, config_default_dir,
+ safe_strerror(errno));
confp = vty_use_backup_config(config_default_dir);
if (confp) {
@@ -2546,8 +2558,9 @@ bool vty_read_config(const char *config_file, char *config_default_dir)
"WARNING: using backup configuration file!");
fullpath = config_default_dir;
} else {
- zlog_err("can't open configuration file [%s]",
- config_default_dir);
+ flog_err(LIB_ERR_VTY,
+ "can't open configuration file [%s]",
+ config_default_dir);
goto tmp_free_and_out;
}
} else
@@ -3060,12 +3073,14 @@ static void vty_save_cwd(void)
* Hence not worrying about it too much.
*/
if (!chdir(SYSCONFDIR)) {
- zlog_err("Failure to chdir to %s, errno: %d",
- SYSCONFDIR, errno);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Failure to chdir to %s, errno: %d",
+ SYSCONFDIR, errno);
exit(-1);
}
if (getcwd(cwd, MAXPATHLEN) == NULL) {
- zlog_err("Failure to getcwd, errno: %d", errno);
+ flog_err_sys(LIB_ERR_SYSTEM_CALL,
+ "Failure to getcwd, errno: %d", errno);
exit(-1);
}
}
diff --git a/lib/workqueue.c b/lib/workqueue.c
index 39dd142afb..c927d5d714 100644
--- a/lib/workqueue.c
+++ b/lib/workqueue.c
@@ -81,9 +81,6 @@ struct work_queue *work_queue_new(struct thread_master *m,
new = XCALLOC(MTYPE_WORK_QUEUE, sizeof(struct work_queue));
- if (new == NULL)
- return new;
-
new->name = XSTRDUP(MTYPE_WORK_QUEUE_NAME, queue_name);
new->master = m;
SET_FLAG(new->flags, WQ_UNPLUGGED);
@@ -152,10 +149,7 @@ void work_queue_add(struct work_queue *wq, void *data)
assert(wq);
- if (!(item = work_queue_item_new(wq))) {
- zlog_err("%s: unable to get new queue item", __func__);
- return;
- }
+ item = work_queue_item_new(wq);
item->data = data;
work_queue_item_enqueue(wq, item);
diff --git a/lib/zclient.c b/lib/zclient.c
index 38a9e6c78e..cc91705ee2 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -38,6 +38,7 @@
#include "sockopt.h"
#include "pbr.h"
#include "nexthop_group.h"
+#include "lib_errors.h"
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient")
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs")
@@ -212,9 +213,9 @@ int zclient_socket_connect(struct zclient *zclient)
set_cloexec(sock);
- zclient->privs->change(ZPRIVS_RAISE);
- setsockopt_so_sendbuf(sock, 1048576);
- zclient->privs->change(ZPRIVS_LOWER);
+ frr_elevate_privs(zclient->privs) {
+ setsockopt_so_sendbuf(sock, 1048576);
+ }
/* Connect to zebra. */
ret = connect(sock, (struct sockaddr *)&zclient_addr, zclient_addr_len);
@@ -312,9 +313,9 @@ int zclient_read_header(struct stream *s, int sock, uint16_t *size,
STREAM_GETW(s, *cmd);
if (*version != ZSERV_VERSION || *marker != ZEBRA_HEADER_MARKER) {
- zlog_err(
- "%s: socket %d version mismatch, marker %d, version %d",
- __func__, sock, *marker, *version);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: socket %d version mismatch, marker %d, version %d",
+ __func__, sock, *marker, *version);
return -1;
}
@@ -1045,12 +1046,12 @@ int zapi_route_encode(uint8_t cmd, struct stream *s, struct zapi_route *api)
char buf[PREFIX2STR_BUFFER];
prefix2str(&api->prefix, buf,
sizeof(buf));
- zlog_err(
- "%s: prefix %s: can't encode "
- "%u labels (maximum is %u)",
- __func__, buf,
- api_nh->label_num,
- MPLS_MAX_LABELS);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "%s: prefix %s: can't encode "
+ "%u labels (maximum is %u)",
+ __func__, buf,
+ api_nh->label_num,
+ MPLS_MAX_LABELS);
return -1;
}
@@ -1671,10 +1672,10 @@ static void link_params_set_value(struct stream *s, struct if_link_params *iflp)
for (i = 0; i < bwclassnum && i < MAX_CLASS_TYPE; i++)
iflp->unrsv_bw[i] = stream_getf(s);
if (i < bwclassnum)
- zlog_err(
- "%s: received %d > %d (MAX_CLASS_TYPE) bw entries"
- " - outdated library?",
- __func__, bwclassnum, MAX_CLASS_TYPE);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: received %d > %d (MAX_CLASS_TYPE) bw entries"
+ " - outdated library?",
+ __func__, bwclassnum, MAX_CLASS_TYPE);
}
iflp->admin_grp = stream_getl(s);
iflp->rmt_as = stream_getl(s);
@@ -1703,8 +1704,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s)
struct interface *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
if (ifp == NULL) {
- zlog_err("%s: unknown ifindex %u, shouldn't happen", __func__,
- ifindex);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "%s: unknown ifindex %u, shouldn't happen", __func__,
+ ifindex);
return NULL;
}
@@ -2039,7 +2041,8 @@ static int zclient_read_sync_response(struct zclient *zclient,
size);
}
if (ret != 0) {
- zlog_err("%s: Invalid Sync Message Reply", __func__);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "%s: Invalid Sync Message Reply", __func__);
return -1;
}
@@ -2081,13 +2084,13 @@ int lm_label_manager_connect(struct zclient *zclient)
ret = writen(zclient->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("Can't write to zclient sock");
+ flog_err(LIB_ERR_ZAPI_SOCKET, "Can't write to zclient sock");
close(zclient->sock);
zclient->sock = -1;
return -1;
}
if (ret == 0) {
- zlog_err("Zclient sock closed");
+ flog_err(LIB_ERR_ZAPI_SOCKET, "Zclient sock closed");
close(zclient->sock);
zclient->sock = -1;
return -1;
@@ -2108,13 +2111,13 @@ int lm_label_manager_connect(struct zclient *zclient)
/* sanity */
if (proto != zclient->redist_default)
- zlog_err(
- "Wrong proto (%u) in LM connect response. Should be %u",
- proto, zclient->redist_default);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Wrong proto (%u) in LM connect response. Should be %u",
+ proto, zclient->redist_default);
if (instance != zclient->instance)
- zlog_err(
- "Wrong instId (%u) in LM connect response. Should be %u",
- instance, zclient->instance);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Wrong instId (%u) in LM connect response. Should be %u",
+ instance, zclient->instance);
/* result code */
result = stream_getc(s);
@@ -2203,13 +2206,15 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
ret = writen(zclient->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("Can't write to zclient sock");
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "Can't write to zclient sock");
close(zclient->sock);
zclient->sock = -1;
return -1;
}
if (ret == 0) {
- zlog_err("Zclient sock closed");
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "Zclient sock closed");
close(zclient->sock);
zclient->sock = -1;
return -1;
@@ -2230,11 +2235,13 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
/* sanities */
if (proto != zclient->redist_default)
- zlog_err("Wrong proto (%u) in get chunk response. Should be %u",
- proto, zclient->redist_default);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Wrong proto (%u) in get chunk response. Should be %u",
+ proto, zclient->redist_default);
if (instance != zclient->instance)
- zlog_err("Wrong instId (%u) in get chunk response Should be %u",
- instance, zclient->instance);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Wrong instId (%u) in get chunk response Should be %u",
+ instance, zclient->instance);
/* keep */
response_keep = stream_getc(s);
@@ -2244,14 +2251,15 @@ int lm_get_label_chunk(struct zclient *zclient, uint8_t keep,
/* not owning this response */
if (keep != response_keep) {
- zlog_err(
- "Invalid Label chunk: %u - %u, keeps mismatch %u != %u",
- *start, *end, keep, response_keep);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Invalid Label chunk: %u - %u, keeps mismatch %u != %u",
+ *start, *end, keep, response_keep);
}
/* sanity */
if (*start > *end || *start < MPLS_LABEL_UNRESERVED_MIN
|| *end > MPLS_LABEL_UNRESERVED_MAX) {
- zlog_err("Invalid Label chunk: %u - %u", *start, *end);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "Invalid Label chunk: %u - %u", *start, *end);
return -1;
}
@@ -2301,13 +2309,14 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start,
ret = writen(zclient->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("Can't write to zclient sock");
+ flog_err(LIB_ERR_ZAPI_SOCKET, "Can't write to zclient sock");
close(zclient->sock);
zclient->sock = -1;
return -1;
}
if (ret == 0) {
- zlog_err("Zclient sock connection closed");
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "Zclient sock connection closed");
close(zclient->sock);
zclient->sock = -1;
return -1;
@@ -2410,13 +2419,15 @@ int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size,
ret = writen(zclient->sock, s->data, stream_get_endp(s));
if (ret < 0) {
- zlog_err("%s: can't write to zclient->sock", __func__);
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "%s: can't write to zclient->sock", __func__);
close(zclient->sock);
zclient->sock = -1;
return -1;
}
if (ret == 0) {
- zlog_err("%s: zclient->sock connection closed", __func__);
+ flog_err(LIB_ERR_ZAPI_SOCKET,
+ "%s: zclient->sock connection closed", __func__);
close(zclient->sock);
zclient->sock = -1;
return -1;
@@ -2502,7 +2513,8 @@ int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw)
stream_write(s, (uint8_t *)&pw->nexthop.ipv6, 16);
break;
default:
- zlog_err("%s: unknown af", __func__);
+ flog_err(LIB_ERR_ZAPI_ENCODE,
+ "%s: unknown af", __func__);
return -1;
}
@@ -2604,15 +2616,16 @@ static int zclient_read(struct thread *thread)
command = stream_getw(zclient->ibuf);
if (marker != ZEBRA_HEADER_MARKER || version != ZSERV_VERSION) {
- zlog_err(
- "%s: socket %d version mismatch, marker %d, version %d",
- __func__, zclient->sock, marker, version);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: socket %d version mismatch, marker %d, version %d",
+ __func__, zclient->sock, marker, version);
return zclient_failed(zclient);
}
if (length < ZEBRA_HEADER_SIZE) {
- zlog_err("%s: socket %d message length %u is less than %d ",
- __func__, zclient->sock, length, ZEBRA_HEADER_SIZE);
+ flog_err(LIB_ERR_ZAPI_MISSMATCH,
+ "%s: socket %d message length %u is less than %d ",
+ __func__, zclient->sock, length, ZEBRA_HEADER_SIZE);
return zclient_failed(zclient);
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 49419b3df3..962b1707c9 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -108,6 +108,7 @@ typedef enum {
ZEBRA_VRF_LABEL,
ZEBRA_INTERFACE_VRF_UPDATE,
ZEBRA_BFD_CLIENT_REGISTER,
+ ZEBRA_BFD_CLIENT_DEREGISTER,
ZEBRA_INTERFACE_ENABLE_RADV,
ZEBRA_INTERFACE_DISABLE_RADV,
ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB,
diff --git a/lib/zebra.h b/lib/zebra.h
index c2d135bbeb..b12f6616ba 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -242,23 +242,6 @@ size_t strlcpy(char *__restrict dest,
const char *__restrict src, size_t destsize);
#endif
-#ifdef HAVE_BROKEN_CMSG_FIRSTHDR
-/* This bug is present in Solaris 8 and pre-patch Solaris 9 <sys/socket.h>;
- please refer to http://bugzilla.quagga.net/show_bug.cgi?id=142 */
-
-/* Check that msg_controllen is large enough. */
-#define ZCMSG_FIRSTHDR(mhdr) \
- (((size_t)((mhdr)->msg_controllen) >= sizeof(struct cmsghdr)) \
- ? CMSG_FIRSTHDR(mhdr) \
- : (struct cmsghdr *)NULL)
-
-#warning "CMSG_FIRSTHDR is broken on this platform, using a workaround"
-
-#else /* HAVE_BROKEN_CMSG_FIRSTHDR */
-#define ZCMSG_FIRSTHDR(M) CMSG_FIRSTHDR(M)
-#endif /* HAVE_BROKEN_CMSG_FIRSTHDR */
-
-
/* GCC have printf type attribute check. */
#ifdef __GNUC__
#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))