summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/clippy.c2
-rw-r--r--lib/command.c13
-rw-r--r--lib/compiler.h79
-rw-r--r--lib/defun_lex.l17
-rw-r--r--lib/iana_afi.h133
-rw-r--r--lib/lib_errors.c6
-rw-r--r--lib/lib_errors.h1
-rw-r--r--lib/log.h19
-rw-r--r--lib/prefix.c26
-rw-r--r--lib/sbuf.c7
-rw-r--r--lib/sbuf.h2
-rw-r--r--lib/subdir.am15
-rw-r--r--lib/termtable.c9
-rw-r--r--lib/termtable.h5
-rw-r--r--lib/thread.c83
-rw-r--r--lib/vty.c5
-rw-r--r--lib/vty.h4
-rw-r--r--lib/zebra.h108
18 files changed, 360 insertions, 174 deletions
diff --git a/lib/clippy.c b/lib/clippy.c
index 44dcc02eb8..cd8067f5eb 100644
--- a/lib/clippy.c
+++ b/lib/clippy.c
@@ -85,8 +85,6 @@ int main(int argc, char **argv)
if (PyRun_AnyFile(fp, pyfile)) {
if (PyErr_Occurred())
PyErr_Print();
- else
- printf("unknown python failure (?)\n");
return 1;
}
Py_Finalize();
diff --git a/lib/command.c b/lib/command.c
index e5e0623163..0e16f30a8a 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -1053,9 +1053,16 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
if (matched_element->daemon)
ret = CMD_SUCCESS_DAEMON;
else {
- /* Clear enqueued configuration changes. */
- vty->num_cfg_changes = 0;
- memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes));
+ if (vty->config) {
+ /* Clear array of enqueued configuration changes. */
+ vty->num_cfg_changes = 0;
+ memset(&vty->cfg_changes, 0, sizeof(vty->cfg_changes));
+
+ /* Regenerate candidate configuration. */
+ if (frr_get_cli_mode() == FRR_CLI_CLASSIC)
+ nb_config_replace(vty->candidate_config,
+ running_config, true);
+ }
ret = matched_element->func(matched_element, vty, argc, argv);
}
diff --git a/lib/compiler.h b/lib/compiler.h
index 9ce91e3361..7c7f4ce294 100644
--- a/lib/compiler.h
+++ b/lib/compiler.h
@@ -173,6 +173,11 @@ extern "C" {
#endif
#endif
+#ifdef container_of
+#undef container_of
+#endif
+
+#if !(defined(__cplusplus) || defined(test__cplusplus))
/* this variant of container_of() retains 'const' on pointers without needing
* to be told to do so. The following will all work without warning:
*
@@ -191,9 +196,6 @@ extern "C" {
* struct cont *x = container_of(cp, const struct cont, member);
* struct cont *x = container_of(p, const struct cont, member);
*/
-#ifdef container_of
-#undef container_of
-#endif
#define container_of(ptr, type, member) \
(__builtin_choose_expr( \
__builtin_types_compatible_p(typeof(&((type *)0)->member), \
@@ -209,6 +211,15 @@ extern "C" {
offsetof(type, member)); \
}) \
))
+#else
+/* current C++ compilers don't have the builtins used above; so this version
+ * of the macro doesn't do the const check. */
+#define container_of(ptr, type, member) \
+ ({ \
+ const typeof(((type *)0)->member) *__mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); \
+ })
+#endif
#define container_of_null(ptr, type, member) \
({ \
@@ -218,6 +229,68 @@ extern "C" {
#define array_size(ar) (sizeof(ar) / sizeof(ar[0]))
+/* sigh. this is so ugly, it overflows and wraps to being nice again.
+ *
+ * printfrr() supports "%Ld" for <int64_t>, whatever that is typedef'd to.
+ * However, gcc & clang think that "%Ld" is <long long>, which doesn't quite
+ * match up since int64_t is <long> on a lot of 64-bit systems.
+ *
+ * If we have _FRR_ATTRIBUTE_PRINTFRR, we loaded a compiler plugin that
+ * replaces the whole format checking bits with a custom version that
+ * understands "%Ld" (along with "%pI4" and co.), so we don't need to do
+ * anything.
+ *
+ * If we don't have that attribute... we still want -Wformat to work. So,
+ * this is the "f*ck it" approach and we just redefine int64_t to always be
+ * <long long>. This should work until such a time that <long long> is
+ * something else (e.g. 128-bit integer)... let's just guard against that
+ * with the _Static_assert below and work with the world we have right now,
+ * where <long long> is always 64-bit.
+ */
+
+/* these need to be included before any of the following, so we can
+ * "overwrite" things.
+ */
+#include <stdint.h>
+#include <inttypes.h>
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#define PRINTFRR(a, b) __attribute__((printfrr(a, b)))
+
+#else /* !_FRR_ATTRIBUTE_PRINTFRR */
+#define PRINTFRR(a, b) __attribute__((format(printf, a, b)))
+
+/* these should be typedefs, but might also be #define */
+#ifdef uint64_t
+#undef uint64_t
+#endif
+#ifdef int64_t
+#undef int64_t
+#endif
+
+/* can't overwrite the typedef, but we can replace int64_t with _int64_t */
+typedef unsigned long long _uint64_t;
+#define uint64_t _uint64_t
+typedef signed long long _int64_t;
+#define int64_t _int64_t
+
+/* if this breaks, 128-bit machines may have entered reality (or <long long>
+ * is something weird)
+ */
+#if __STDC_VERSION__ >= 201112L
+_Static_assert(sizeof(_uint64_t) == 8 && sizeof(_int64_t) == 8,
+ "nobody expects the spanish intquisition");
+#endif
+
+/* since we redefined int64_t, we also need to redefine PRI*64 */
+#undef PRIu64
+#undef PRId64
+#undef PRIx64
+#define PRIu64 "llu"
+#define PRId64 "lld"
+#define PRIx64 "llx"
+#endif /* !_FRR_ATTRIBUTE_PRINTFRR */
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/defun_lex.l b/lib/defun_lex.l
index 6c0805a4fa..19b06f51b8 100644
--- a/lib/defun_lex.l
+++ b/lib/defun_lex.l
@@ -163,7 +163,7 @@ static int yylex_clr(char **retbuf)
return rv;
}
-static PyObject *get_args(void)
+static PyObject *get_args(const char *filename, int lineno)
{
PyObject *pyObj = PyList_New(0);
PyObject *pyArg = NULL;
@@ -190,6 +190,13 @@ static PyObject *get_args(void)
free(tval);
continue;
}
+ if (token == PREPROC) {
+ free(tval);
+ Py_DECREF(pyObj);
+ return PyErr_Format(PyExc_ValueError,
+ "%s:%d: cannot process CPP directive within argument list",
+ filename, lineno);
+ }
if (token == SPECIAL) {
if (depth == 1 && (tval[0] == ',' || tval[0] == ')')) {
if (pyArg)
@@ -244,7 +251,12 @@ PyObject *clippy_parse(PyObject *self, PyObject *args)
case DEFUNNY:
case INSTALL:
case AUXILIARY:
- pyArgs = get_args();
+ pyArgs = get_args(filename, lineno);
+ if (!pyArgs) {
+ free(tval);
+ Py_DECREF(pyCont);
+ return NULL;
+ }
pyItem = PyDict_New();
PyDict_SetItemString(pyItem, "type", PyUnicode_FromString(tval));
PyDict_SetItemString(pyItem, "args", pyArgs);
@@ -260,6 +272,7 @@ PyObject *clippy_parse(PyObject *self, PyObject *args)
pyItem = PyDict_New();
PyDict_SetItemString(pyItem, "type", PyUnicode_FromString("PREPROC"));
PyDict_SetItemString(pyItem, "line", PyUnicode_FromString(tval));
+ lineno--;
break;
}
if (pyItem) {
diff --git a/lib/iana_afi.h b/lib/iana_afi.h
new file mode 100644
index 0000000000..ac03f73193
--- /dev/null
+++ b/lib/iana_afi.h
@@ -0,0 +1,133 @@
+/*
+ * iana_afi and safi definitions.
+ * Copyright (C) 2018-2019 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 __IANA_AFI_H__
+
+#include <prefix.h>
+
+/*
+ * The above AFI and SAFI definitions are for internal use. The protocol
+ * definitions (IANA values) as for example used in BGP protocol packets
+ * are defined below and these will get mapped to/from the internal values
+ * in the appropriate places.
+ * The rationale is that the protocol (IANA) values may be sparse and are
+ * not optimal for use in data-structure sizing.
+ * Note: Only useful (i.e., supported) values are defined below.
+ */
+typedef enum {
+ IANA_AFI_RESERVED = 0,
+ IANA_AFI_IPV4 = 1,
+ IANA_AFI_IPV6 = 2,
+ IANA_AFI_L2VPN = 25,
+} iana_afi_t;
+
+typedef enum {
+ IANA_SAFI_RESERVED = 0,
+ IANA_SAFI_UNICAST = 1,
+ IANA_SAFI_MULTICAST = 2,
+ IANA_SAFI_LABELED_UNICAST = 4,
+ IANA_SAFI_ENCAP = 7,
+ IANA_SAFI_EVPN = 70,
+ IANA_SAFI_MPLS_VPN = 128,
+ IANA_SAFI_FLOWSPEC = 133
+} iana_safi_t;
+
+static inline afi_t afi_iana2int(iana_afi_t afi)
+{
+ switch (afi) {
+ case IANA_AFI_IPV4:
+ return AFI_IP;
+ case IANA_AFI_IPV6:
+ return AFI_IP6;
+ case IANA_AFI_L2VPN:
+ return AFI_L2VPN;
+ default:
+ return AFI_MAX;
+ }
+}
+
+static inline iana_afi_t afi_int2iana(afi_t afi)
+{
+ switch (afi) {
+ case AFI_IP:
+ return IANA_AFI_IPV4;
+ case AFI_IP6:
+ return IANA_AFI_IPV6;
+ case AFI_L2VPN:
+ return IANA_AFI_L2VPN;
+ default:
+ return IANA_AFI_RESERVED;
+ }
+}
+
+static inline const char *iana_afi2str(iana_afi_t afi)
+{
+ return afi2str(afi_iana2int(afi));
+}
+
+static inline safi_t safi_iana2int(iana_safi_t safi)
+{
+ switch (safi) {
+ case IANA_SAFI_UNICAST:
+ return SAFI_UNICAST;
+ case IANA_SAFI_MULTICAST:
+ return SAFI_MULTICAST;
+ case IANA_SAFI_MPLS_VPN:
+ return SAFI_MPLS_VPN;
+ case IANA_SAFI_ENCAP:
+ return SAFI_ENCAP;
+ case IANA_SAFI_EVPN:
+ return SAFI_EVPN;
+ case IANA_SAFI_LABELED_UNICAST:
+ return SAFI_LABELED_UNICAST;
+ case IANA_SAFI_FLOWSPEC:
+ return SAFI_FLOWSPEC;
+ default:
+ return SAFI_MAX;
+ }
+}
+
+static inline iana_safi_t safi_int2iana(safi_t safi)
+{
+ switch (safi) {
+ case SAFI_UNICAST:
+ return IANA_SAFI_UNICAST;
+ case SAFI_MULTICAST:
+ return IANA_SAFI_MULTICAST;
+ case SAFI_MPLS_VPN:
+ return IANA_SAFI_MPLS_VPN;
+ case SAFI_ENCAP:
+ return IANA_SAFI_ENCAP;
+ case SAFI_EVPN:
+ return IANA_SAFI_EVPN;
+ case SAFI_LABELED_UNICAST:
+ return IANA_SAFI_LABELED_UNICAST;
+ case SAFI_FLOWSPEC:
+ return IANA_SAFI_FLOWSPEC;
+ default:
+ return IANA_SAFI_RESERVED;
+ }
+}
+
+static inline const char *iana_safi2str(iana_safi_t safi)
+{
+ return safi2str(safi_iana2int(safi));
+}
+
+#endif
diff --git a/lib/lib_errors.c b/lib/lib_errors.c
index b6c764d873..e0559f332d 100644
--- a/lib/lib_errors.c
+++ b/lib/lib_errors.c
@@ -51,6 +51,12 @@ static struct log_ref ferr_lib_warn[] = {
.suggestion = "Gather log data and open an Issue",
},
{
+ .code = EC_LIB_NO_THREAD,
+ .title = "The Event subsystem has detected an internal FD problem",
+ .description = "The Event subsystem has detected a file descriptor read/write event without an associated handling function. This is a bug, please collect log data and open an issue.",
+ .suggestion = "Gather log data and open an Issue",
+ },
+ {
.code = EC_LIB_RMAP_RECURSION_LIMIT,
.title = "Reached the Route-Map Recursion Limit",
.description = "The Route-Map subsystem has detected a route-map depth of RMAP_RECURSION_LIMIT and has stopped processing",
diff --git a/lib/lib_errors.h b/lib/lib_errors.h
index 39b39fb065..996a16ba95 100644
--- a/lib/lib_errors.h
+++ b/lib/lib_errors.h
@@ -45,6 +45,7 @@ enum lib_log_refs {
EC_LIB_STREAM,
EC_LIB_LINUX_NS,
EC_LIB_SLOW_THREAD,
+ EC_LIB_NO_THREAD,
EC_LIB_RMAP_RECURSION_LIMIT,
EC_LIB_BACKUP_CONFIG,
EC_LIB_VRF_LENGTH,
diff --git a/lib/log.h b/lib/log.h
index 3ef4d2f379..c5ae6fe32f 100644
--- a/lib/log.h
+++ b/lib/log.h
@@ -81,20 +81,13 @@ extern void openzlog(const char *progname, const char *protoname,
/* Close zlog function. */
extern void closezlog(void);
-/* GCC have printf type attribute check. */
-#ifdef __GNUC__
-#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
-#else
-#define PRINTF_ATTRIBUTE(a,b)
-#endif /* __GNUC__ */
-
/* Handy zlog functions. */
-extern void zlog_err(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
-extern void zlog_warn(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
-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);
-extern void zlog(int priority, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
+extern void zlog_err(const char *format, ...) PRINTFRR(1, 2);
+extern void zlog_warn(const char *format, ...) PRINTFRR(1, 2);
+extern void zlog_info(const char *format, ...) PRINTFRR(1, 2);
+extern void zlog_notice(const char *format, ...) PRINTFRR(1, 2);
+extern void zlog_debug(const char *format, ...) PRINTFRR(1, 2);
+extern void zlog(int priority, const char *format, ...) PRINTFRR(2, 3);
/* For logs which have error codes associated with them */
#define flog_err(ferr_id, format, ...) \
diff --git a/lib/prefix.c b/lib/prefix.c
index 134d9cf908..7abeebcd09 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -1329,13 +1329,29 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
{
const struct prefix *p = pu.p;
char buf[PREFIX2STR_BUFFER];
+ int byte, tmp, a, b;
+ bool z = false;
+ size_t l;
switch (p->family) {
case AF_INET:
case AF_INET6:
- snprintf(str, size, "%s/%d", inet_ntop(p->family, &p->u.prefix,
- buf, PREFIX2STR_BUFFER),
- p->prefixlen);
+ inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
+ l = strlen(buf);
+ buf[l++] = '/';
+ byte = p->prefixlen;
+ if ((tmp = p->prefixlen - 100) >= 0) {
+ buf[l++] = '1';
+ z = true;
+ byte = tmp;
+ }
+ b = byte % 10;
+ a = byte / 10;
+ if (a || z)
+ buf[l++] = '0' + a;
+ buf[l++] = '0' + b;
+ buf[l] = '\0';
+ strlcpy(str, buf, size);
break;
case AF_ETHERNET:
@@ -1349,11 +1365,11 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size)
break;
case AF_FLOWSPEC:
- sprintf(str, "FS prefix");
+ strlcpy(str, "FS prefix", size);
break;
default:
- sprintf(str, "UNK prefix");
+ strlcpy(str, "UNK prefix", size);
break;
}
diff --git a/lib/sbuf.c b/lib/sbuf.c
index 03a2be3e09..c04af153b1 100644
--- a/lib/sbuf.c
+++ b/lib/sbuf.c
@@ -22,6 +22,7 @@
*/
#include <zebra.h>
+#include "printfrr.h"
#include "sbuf.h"
#include "memory.h"
@@ -68,7 +69,7 @@ void sbuf_push(struct sbuf *buf, int indent, const char *format, ...)
written1 = indent;
va_start(args, format);
- written2 = vsnprintf(NULL, 0, format, args);
+ written2 = vsnprintfrr(NULL, 0, format, args);
va_end(args);
new_size = buf->size;
@@ -92,8 +93,8 @@ void sbuf_push(struct sbuf *buf, int indent, const char *format, ...)
buf->pos = buf->size;
va_start(args, format);
- written = vsnprintf(buf->buf + buf->pos, buf->size - buf->pos, format,
- args);
+ written = vsnprintfrr(buf->buf + buf->pos, buf->size - buf->pos,
+ format, args);
va_end(args);
if (written >= 0)
diff --git a/lib/sbuf.h b/lib/sbuf.h
index b1518a3aa8..9f0311006d 100644
--- a/lib/sbuf.h
+++ b/lib/sbuf.h
@@ -78,7 +78,7 @@ const char *sbuf_buf(struct sbuf *buf);
void sbuf_free(struct sbuf *buf);
#include "lib/log.h"
void sbuf_push(struct sbuf *buf, int indent, const char *format, ...)
- PRINTF_ATTRIBUTE(3, 4);
+ PRINTFRR(3, 4);
#ifdef __cplusplus
}
diff --git a/lib/subdir.am b/lib/subdir.am
index 4e6adced74..8b6cbe2aeb 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -3,7 +3,7 @@
#
lib_LTLIBRARIES += lib/libfrr.la
lib_libfrr_la_LDFLAGS = -version-info 0:0:0 -Xlinker -e_libfrr_version
-lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB)
+lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(LIBM)
lib_libfrr_la_SOURCES = \
lib/agg_table.c \
@@ -165,6 +165,7 @@ pkginclude_HEADERS += \
lib/graph.h \
lib/hash.h \
lib/hook.h \
+ lib/iana_afi.h \
lib/id_alloc.h \
lib/if.h \
lib/if_rmap.h \
@@ -340,8 +341,10 @@ noinst_PROGRAMS += \
if BUILD_CLIPPY
noinst_PROGRAMS += lib/clippy
else
-$(HOSTTOOLS)lib/clippy:
- @$(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/route_types.h lib/clippy
+if HOSTTOOLS_CLIPPY
+$(CLIPPY):
+ @$(MAKE) -C $(top_builddir)/hosttools lib/route_types.h lib/clippy
+endif
endif
lib_grammar_sandbox_SOURCES = \
@@ -372,13 +375,11 @@ am__v_CLIPPY_ = $(am__v_CLIPPY_$(AM_DEFAULT_VERBOSITY))
am__v_CLIPPY_0 = @echo " CLIPPY " $@;
am__v_CLIPPY_1 =
-CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py
+CLIPPY_DEPS = $(CLIPPY) $(top_srcdir)/python/clidef.py
SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h .pb.cc .grpc.pb.cc
.c_clippy.c:
- @{ test -x $(top_builddir)/$(HOSTTOOLS)lib/clippy || \
- $(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/clippy; }
- $(AM_V_CLIPPY) $(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $<
+ $(AM_V_CLIPPY) $(CLIPPY) $(top_srcdir)/python/clidef.py -o $@ $<
## automake's "ylwrap" is a great piece of GNU software... not.
.l.c:
diff --git a/lib/termtable.c b/lib/termtable.c
index 01468b8203..b59c1118f8 100644
--- a/lib/termtable.c
+++ b/lib/termtable.c
@@ -20,6 +20,7 @@
#include <zebra.h>
#include <stdio.h>
+#include "printfrr.h"
#include "memory.h"
#include "termtable.h"
@@ -134,6 +135,7 @@ static struct ttable_cell *ttable_insert_row_va(struct ttable *tt, int i,
{
assert(i >= -1 && i < tt->nrows);
+ char shortbuf[256];
char *res, *orig, *section;
struct ttable_cell *row;
int col = 0;
@@ -158,9 +160,7 @@ static struct ttable_cell *ttable_insert_row_va(struct ttable *tt, int i,
/* CALLOC a block of cells */
row = XCALLOC(MTYPE_TTABLE, tt->ncols * sizeof(struct ttable_cell));
- res = NULL;
- vasprintf(&res, format, ap);
-
+ res = vasnprintfrr(MTYPE_TMP, shortbuf, sizeof(shortbuf), format, ap);
orig = res;
while (res && col < tt->ncols) {
@@ -170,7 +170,8 @@ static struct ttable_cell *ttable_insert_row_va(struct ttable *tt, int i,
col++;
}
- free(orig);
+ if (orig != shortbuf)
+ XFREE(MTYPE_TMP, orig);
/* insert row */
if (i == -1 || i == tt->nrows)
diff --git a/lib/termtable.h b/lib/termtable.h
index 491010a856..4f7c595ce2 100644
--- a/lib/termtable.h
+++ b/lib/termtable.h
@@ -137,8 +137,7 @@ void ttable_cell_del(struct ttable_cell *cell);
* columns were specified
*/
struct ttable_cell *ttable_insert_row(struct ttable *tt, unsigned int row,
- const char *format, ...)
- PRINTF_ATTRIBUTE(3, 4);
+ const char *format, ...) PRINTFRR(3, 4);
/**
* Inserts a new row at the end of the table.
*
@@ -164,7 +163,7 @@ struct ttable_cell *ttable_insert_row(struct ttable *tt, unsigned int row,
* columns were specified
*/
struct ttable_cell *ttable_add_row(struct ttable *tt, const char *format, ...)
- PRINTF_ATTRIBUTE(2, 3);
+ PRINTFRR(2, 3);
/**
* Removes a row from the table.
diff --git a/lib/thread.c b/lib/thread.c
index 7489be5c2d..fc2de09df0 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -307,6 +307,7 @@ static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
{
const char *name = m->name ? m->name : "main";
char underline[strlen(name) + 1];
+ struct thread *thread;
uint32_t i;
memset(underline, '-', sizeof(underline));
@@ -316,11 +317,31 @@ static void show_thread_poll_helper(struct vty *vty, struct thread_master *m)
vty_out(vty, "----------------------%s\n", underline);
vty_out(vty, "Count: %u/%d\n", (uint32_t)m->handler.pfdcount,
m->fd_limit);
- for (i = 0; i < m->handler.pfdcount; i++)
- vty_out(vty, "\t%6d fd:%6d events:%2d revents:%2d\n", i,
- m->handler.pfds[i].fd,
- m->handler.pfds[i].events,
+ for (i = 0; i < m->handler.pfdcount; i++) {
+ vty_out(vty, "\t%6d fd:%6d events:%2d revents:%2d\t\t", i,
+ m->handler.pfds[i].fd, m->handler.pfds[i].events,
m->handler.pfds[i].revents);
+
+ if (m->handler.pfds[i].events & POLLIN) {
+ thread = m->read[m->handler.pfds[i].fd];
+
+ if (!thread)
+ vty_out(vty, "ERROR ");
+ else
+ vty_out(vty, "%s ", thread->funcname);
+ } else
+ vty_out(vty, " ");
+
+ if (m->handler.pfds[i].events & POLLOUT) {
+ thread = m->write[m->handler.pfds[i].fd];
+
+ if (!thread)
+ vty_out(vty, "ERROR\n");
+ else
+ vty_out(vty, "%s\n", thread->funcname);
+ } else
+ vty_out(vty, "\n");
+ }
}
DEFUN (show_thread_poll,
@@ -756,6 +777,7 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
debugargdef)
{
struct thread *thread = NULL;
+ struct thread **thread_array;
assert(fd >= 0 && fd < m->fd_limit);
pthread_mutex_lock(&m->mtx);
@@ -770,11 +792,25 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
/* default to a new pollfd */
nfds_t queuepos = m->handler.pfdcount;
+ if (dir == THREAD_READ)
+ thread_array = m->read;
+ else
+ thread_array = m->write;
+
/* if we already have a pollfd for our file descriptor, find and
* use it */
for (nfds_t i = 0; i < m->handler.pfdcount; i++)
if (m->handler.pfds[i].fd == fd) {
queuepos = i;
+
+#ifdef DEV_BUILD
+ /*
+ * What happens if we have a thread already
+ * created for this event?
+ */
+ if (thread_array[fd])
+ assert(!"Thread already scheduled for file descriptor");
+#endif
break;
}
@@ -794,10 +830,7 @@ struct thread *funcname_thread_add_read_write(int dir, struct thread_master *m,
pthread_mutex_lock(&thread->mtx);
{
thread->u.fd = fd;
- if (dir == THREAD_READ)
- m->read[thread->u.fd] = thread;
- else
- m->write[thread->u.fd] = thread;
+ thread_array[thread->u.fd] = thread;
}
pthread_mutex_unlock(&thread->mtx);
@@ -1238,12 +1271,31 @@ static struct thread *thread_run(struct thread_master *m, struct thread *thread,
}
static int thread_process_io_helper(struct thread_master *m,
- struct thread *thread, short state, int pos)
+ struct thread *thread, short state,
+ short actual_state, int pos)
{
struct thread **thread_array;
- if (!thread)
+ /*
+ * poll() clears the .events field, but the pollfd array we
+ * pass to poll() is a copy of the one used to schedule threads.
+ * We need to synchronize state between the two here by applying
+ * the same changes poll() made on the copy of the "real" pollfd
+ * array.
+ *
+ * This cleans up a possible infinite loop where we refuse
+ * to respond to a poll event but poll is insistent that
+ * we should.
+ */
+ m->handler.pfds[pos].events &= ~(state);
+
+ if (!thread) {
+ if ((actual_state & (POLLHUP|POLLIN)) != POLLHUP)
+ flog_err(EC_LIB_NO_THREAD,
+ "Attempting to process an I/O event but for fd: %d(%d) no thread to handle this!\n",
+ m->handler.pfds[pos].fd, actual_state);
return 0;
+ }
if (thread->type == THREAD_READ)
thread_array = m->read;
@@ -1253,9 +1305,7 @@ static int thread_process_io_helper(struct thread_master *m,
thread_array[thread->u.fd] = NULL;
thread_list_add_tail(&m->ready, thread);
thread->type = THREAD_READY;
- /* if another pthread scheduled this file descriptor for the event we're
- * responding to, no problem; we're getting to it now */
- thread->master->handler.pfds[pos].events &= ~(state);
+
return 1;
}
@@ -1291,12 +1341,13 @@ static void thread_process_io(struct thread_master *m, unsigned int num)
* there's no need to update it. Similarily, barring deletion,
* the fd
* should still be a valid index into the master's pfds. */
- if (pfds[i].revents & (POLLIN | POLLHUP))
+ if (pfds[i].revents & (POLLIN | POLLHUP)) {
thread_process_io_helper(m, m->read[pfds[i].fd], POLLIN,
- i);
+ pfds[i].revents, i);
+ }
if (pfds[i].revents & POLLOUT)
thread_process_io_helper(m, m->write[pfds[i].fd],
- POLLOUT, i);
+ POLLOUT, pfds[i].revents, i);
/* if one of our file descriptors is garbage, remove the same
* from
diff --git a/lib/vty.c b/lib/vty.c
index e306e69b87..0db3dc36f2 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -105,8 +105,8 @@ void vty_frame(struct vty *vty, const char *format, ...)
va_list args;
va_start(args, format);
- vsnprintf(vty->frame + vty->frame_pos,
- sizeof(vty->frame) - vty->frame_pos, format, args);
+ vsnprintfrr(vty->frame + vty->frame_pos,
+ sizeof(vty->frame) - vty->frame_pos, format, args);
vty->frame_pos = strlen(vty->frame);
va_end(args);
}
@@ -2289,6 +2289,7 @@ static void vty_read_file(struct nb_config *config, FILE *confp)
vty->wfd = STDERR_FILENO;
vty->type = VTY_FILE;
vty->node = CONFIG_NODE;
+ vty->config = true;
if (config)
vty->candidate_config = config;
else {
diff --git a/lib/vty.h b/lib/vty.h
index 035e758024..c7352efbd3 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -302,8 +302,8 @@ extern struct vty *vty_stdio(void (*atclose)(int isexit));
* - vty_endframe() clears the buffer without printing it, and prints an
* extra string if the buffer was empty before (for context-end markers)
*/
-extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
-extern void vty_frame(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3);
+extern int vty_out(struct vty *, const char *, ...) PRINTFRR(2, 3);
+extern void vty_frame(struct vty *, const char *, ...) PRINTFRR(2, 3);
extern void vty_endframe(struct vty *, const char *);
bool vty_set_include(struct vty *vty, const char *regexp);
diff --git a/lib/zebra.h b/lib/zebra.h
index 2f9ada09be..22239f8e60 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -244,13 +244,6 @@ size_t strlcpy(char *__restrict dest,
const char *__restrict src, size_t destsize);
#endif
-/* GCC have printf type attribute check. */
-#ifdef __GNUC__
-#define PRINTF_ATTRIBUTE(a,b) __attribute__ ((__format__ (__printf__, a, b)))
-#else
-#define PRINTF_ATTRIBUTE(a,b)
-#endif /* __GNUC__ */
-
/*
* RFC 3542 defines several macros for using struct cmsghdr.
* Here, we define those that are not present
@@ -373,35 +366,6 @@ typedef enum {
SAFI_MAX = 8
} safi_t;
-/*
- * The above AFI and SAFI definitions are for internal use. The protocol
- * definitions (IANA values) as for example used in BGP protocol packets
- * are defined below and these will get mapped to/from the internal values
- * in the appropriate places.
- * The rationale is that the protocol (IANA) values may be sparse and are
- * not optimal for use in data-structure sizing.
- * Note: Only useful (i.e., supported) values are defined below.
- */
-typedef enum {
- IANA_AFI_RESERVED = 0,
- IANA_AFI_IPV4 = 1,
- IANA_AFI_IPV6 = 2,
- IANA_AFI_L2VPN = 25,
- IANA_AFI_IPMR = 128,
- IANA_AFI_IP6MR = 129
-} iana_afi_t;
-
-typedef enum {
- IANA_SAFI_RESERVED = 0,
- IANA_SAFI_UNICAST = 1,
- IANA_SAFI_MULTICAST = 2,
- IANA_SAFI_LABELED_UNICAST = 4,
- IANA_SAFI_ENCAP = 7,
- IANA_SAFI_EVPN = 70,
- IANA_SAFI_MPLS_VPN = 128,
- IANA_SAFI_FLOWSPEC = 133
-} iana_safi_t;
-
/* Default Administrative Distance of each protocol. */
#define ZEBRA_KERNEL_DISTANCE_DEFAULT 0
#define ZEBRA_CONNECT_DISTANCE_DEFAULT 0
@@ -439,76 +403,4 @@ typedef uint32_t route_tag_t;
#define ROUTE_TAG_MAX UINT32_MAX
#define ROUTE_TAG_PRI PRIu32
-static inline afi_t afi_iana2int(iana_afi_t afi)
-{
- switch (afi) {
- case IANA_AFI_IPV4:
- return AFI_IP;
- case IANA_AFI_IPV6:
- return AFI_IP6;
- case IANA_AFI_L2VPN:
- return AFI_L2VPN;
- default:
- return AFI_MAX;
- }
-}
-
-static inline iana_afi_t afi_int2iana(afi_t afi)
-{
- switch (afi) {
- case AFI_IP:
- return IANA_AFI_IPV4;
- case AFI_IP6:
- return IANA_AFI_IPV6;
- case AFI_L2VPN:
- return IANA_AFI_L2VPN;
- default:
- return IANA_AFI_RESERVED;
- }
-}
-
-static inline safi_t safi_iana2int(iana_safi_t safi)
-{
- switch (safi) {
- case IANA_SAFI_UNICAST:
- return SAFI_UNICAST;
- case IANA_SAFI_MULTICAST:
- return SAFI_MULTICAST;
- case IANA_SAFI_MPLS_VPN:
- return SAFI_MPLS_VPN;
- case IANA_SAFI_ENCAP:
- return SAFI_ENCAP;
- case IANA_SAFI_EVPN:
- return SAFI_EVPN;
- case IANA_SAFI_LABELED_UNICAST:
- return SAFI_LABELED_UNICAST;
- case IANA_SAFI_FLOWSPEC:
- return SAFI_FLOWSPEC;
- default:
- return SAFI_MAX;
- }
-}
-
-static inline iana_safi_t safi_int2iana(safi_t safi)
-{
- switch (safi) {
- case SAFI_UNICAST:
- return IANA_SAFI_UNICAST;
- case SAFI_MULTICAST:
- return IANA_SAFI_MULTICAST;
- case SAFI_MPLS_VPN:
- return IANA_SAFI_MPLS_VPN;
- case SAFI_ENCAP:
- return IANA_SAFI_ENCAP;
- case SAFI_EVPN:
- return IANA_SAFI_EVPN;
- case SAFI_LABELED_UNICAST:
- return IANA_SAFI_LABELED_UNICAST;
- case SAFI_FLOWSPEC:
- return IANA_SAFI_FLOWSPEC;
- default:
- return IANA_SAFI_RESERVED;
- }
-}
-
#endif /* _ZEBRA_H */