diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/clippy.c | 2 | ||||
| -rw-r--r-- | lib/command.c | 13 | ||||
| -rw-r--r-- | lib/compiler.h | 79 | ||||
| -rw-r--r-- | lib/defun_lex.l | 17 | ||||
| -rw-r--r-- | lib/iana_afi.h | 133 | ||||
| -rw-r--r-- | lib/lib_errors.c | 6 | ||||
| -rw-r--r-- | lib/lib_errors.h | 1 | ||||
| -rw-r--r-- | lib/log.h | 19 | ||||
| -rw-r--r-- | lib/prefix.c | 26 | ||||
| -rw-r--r-- | lib/sbuf.c | 7 | ||||
| -rw-r--r-- | lib/sbuf.h | 2 | ||||
| -rw-r--r-- | lib/subdir.am | 15 | ||||
| -rw-r--r-- | lib/termtable.c | 9 | ||||
| -rw-r--r-- | lib/termtable.h | 5 | ||||
| -rw-r--r-- | lib/thread.c | 83 | ||||
| -rw-r--r-- | lib/vty.c | 5 | ||||
| -rw-r--r-- | lib/vty.h | 4 | ||||
| -rw-r--r-- | lib/zebra.h | 108 |
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, @@ -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 @@ -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 { @@ -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 */ |
