diff options
| -rw-r--r-- | Makefile.am | 1 | ||||
| -rw-r--r-- | bgpd/bgp_attr.c | 16 | ||||
| -rw-r--r-- | bgpd/bgp_attr.h | 11 | ||||
| -rw-r--r-- | bgpd/bgp_route.c | 119 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 3 | ||||
| -rwxr-xr-x | configure.ac | 32 | ||||
| -rw-r--r-- | lib/command.c | 20 | ||||
| -rw-r--r-- | lib/command.h | 2 | ||||
| -rw-r--r-- | lib/log.c | 81 | ||||
| -rw-r--r-- | lib/subdir.am | 2 | ||||
| -rw-r--r-- | lib/vty.c | 28 | ||||
| -rw-r--r-- | lib/vty.h | 7 | ||||
| -rw-r--r-- | tests/lib/test_segv.c | 31 | ||||
| -rw-r--r-- | vtysh/vtysh.c | 2 |
14 files changed, 292 insertions, 63 deletions
diff --git a/Makefile.am b/Makefile.am index 65aed79152..4cbf111b04 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,7 @@ AUTOMAKE_OPTIONS = subdir-objects 1.12 ACLOCAL_AMFLAGS = -I m4 AM_CFLAGS = \ + $(UNWIND_CFLAGS) \ $(SAN_FLAGS) \ $(WERROR) \ # end diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index c7d7c56a12..fb7db9d57e 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -723,8 +723,10 @@ struct attr *bgp_attr_default_set(struct attr *attr, uint8_t origin) /* Create the attributes for an aggregate */ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, struct aspath *aspath, - struct community *community, int as_set, - uint8_t atomic_aggregate) + struct community *community, + struct ecommunity *ecommunity, + struct lcommunity *lcommunity, + int as_set, uint8_t atomic_aggregate) { struct attr attr; struct attr *new; @@ -760,6 +762,16 @@ struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); } + if (ecommunity) { + attr.ecommunity = ecommunity; + attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); + } + + if (lcommunity) { + attr.lcommunity = lcommunity; + attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES); + } + if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) { bgp_attr_add_gshut_community(&attr); } diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 883b129136..4c8f98947e 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -272,10 +272,13 @@ extern void bgp_attr_unintern_sub(struct attr *); extern void bgp_attr_unintern(struct attr **); extern void bgp_attr_flush(struct attr *); extern struct attr *bgp_attr_default_set(struct attr *attr, uint8_t); -extern struct attr *bgp_attr_aggregate_intern(struct bgp *, uint8_t, - struct aspath *, - struct community *, int as_set, - uint8_t); +extern struct attr *bgp_attr_aggregate_intern(struct bgp *bgp, uint8_t origin, + struct aspath *aspath, + struct community *community, + struct ecommunity *ecommunity, + struct lcommunity *lcommunity, + int as_set, + uint8_t atomic_aggregate); extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *, struct stream *, struct attr *, struct bpacket_attr_vec_arr *vecarr, diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index c15ce7d9aa..bb6b8aab3c 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5482,7 +5482,9 @@ static void bgp_aggregate_free(struct bgp_aggregate *aggregate) static int bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin, struct aspath *aspath, - struct community *comm) + struct community *comm, + struct ecommunity *ecomm, + struct lcommunity *lcomm) { static struct aspath *ae = NULL; @@ -5501,6 +5503,12 @@ static int bgp_aggregate_info_same(struct bgp_path_info *pi, uint8_t origin, if (!community_cmp(pi->attr->community, comm)) return 0; + if (!ecommunity_cmp(pi->attr->ecommunity, ecomm)) + return 0; + + if (!lcommunity_cmp(pi->attr->lcommunity, lcomm)) + return 0; + if (!CHECK_FLAG(pi->flags, BGP_PATH_VALID)) return 0; @@ -5511,6 +5519,8 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, struct prefix *p, uint8_t origin, struct aspath *aspath, struct community *community, + struct ecommunity *ecommunity, + struct lcommunity *lcommunity, uint8_t atomic_aggregate, struct bgp_aggregate *aggregate) { @@ -5532,14 +5542,18 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, * If the aggregate information has not changed * no need to re-install it again. */ - if (bgp_aggregate_info_same(rn->info, origin, aspath, - community)) { + if (bgp_aggregate_info_same(rn->info, origin, aspath, community, + ecommunity, lcommunity)) { bgp_unlock_node(rn); if (aspath) aspath_free(aspath); if (community) community_free(community); + if (ecommunity) + ecommunity_free(&ecommunity); + if (lcommunity) + lcommunity_free(&lcommunity); return; } @@ -5550,12 +5564,14 @@ static void bgp_aggregate_install(struct bgp *bgp, afi_t afi, safi_t safi, if (pi) bgp_path_info_delete(rn, pi); - new = info_make( - ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, 0, bgp->peer_self, - bgp_attr_aggregate_intern(bgp, origin, aspath, - community, aggregate->as_set, - atomic_aggregate), - rn); + new = info_make(ZEBRA_ROUTE_BGP, BGP_ROUTE_AGGREGATE, 0, + bgp->peer_self, + bgp_attr_aggregate_intern(bgp, origin, aspath, + community, ecommunity, + lcommunity, + aggregate->as_set, + atomic_aggregate), + rn); SET_FLAG(new->flags, BGP_PATH_VALID); bgp_path_info_add(rn, new); @@ -5591,6 +5607,10 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, struct aspath *asmerge = NULL; struct community *community = NULL; struct community *commerge = NULL; + struct ecommunity *ecommunity = NULL; + struct ecommunity *ecommerge = NULL; + struct lcommunity *lcommunity = NULL; + struct lcommunity *lcommerge = NULL; struct bgp_path_info *pi; unsigned long match = 0; uint8_t atomic_aggregate = 0; @@ -5670,16 +5690,43 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, } else aspath = aspath_dup(pi->attr->aspath); - if (!pi->attr->community) - continue; + if (pi->attr->community) { + if (community) { + commerge = community_merge( + community, pi->attr->community); + community = + community_uniq_sort(commerge); + community_free(commerge); + } else + community = community_dup( + pi->attr->community); + } - if (community) { - commerge = community_merge(community, - pi->attr->community); - community = community_uniq_sort(commerge); - community_free(commerge); - } else - community = community_dup(pi->attr->community); + if (pi->attr->ecommunity) { + if (ecommunity) { + ecommerge = ecommunity_merge( + ecommunity, + pi->attr->ecommunity); + ecommunity = + ecommunity_uniq_sort(ecommerge); + ecommunity_free(&ecommerge); + } else + ecommunity = ecommunity_dup( + pi->attr->ecommunity); + } + + if (pi->attr->lcommunity) { + if (lcommunity) { + lcommerge = lcommunity_merge( + lcommunity, + pi->attr->lcommunity); + lcommunity = + lcommunity_uniq_sort(lcommerge); + lcommunity_free(&lcommerge); + } else + lcommunity = lcommunity_dup( + pi->attr->lcommunity); + } } if (match) bgp_process(bgp, rn, afi, safi); @@ -5716,17 +5763,48 @@ static void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, community = community_dup( pinew->attr->community); } + + if (pinew->attr->ecommunity) { + if (ecommunity) { + ecommerge = ecommunity_merge( + ecommunity, + pinew->attr->ecommunity); + ecommunity = + ecommunity_uniq_sort(ecommerge); + ecommunity_free(&ecommerge); + } else + ecommunity = ecommunity_dup( + pinew->attr->ecommunity); + } + + if (pinew->attr->lcommunity) { + if (lcommunity) { + lcommerge = lcommunity_merge( + lcommunity, + pinew->attr->lcommunity); + lcommunity = + lcommunity_uniq_sort(lcommerge); + lcommunity_free(&lcommerge); + } else + lcommunity = lcommunity_dup( + pinew->attr->lcommunity); + } } } bgp_aggregate_install(bgp, afi, safi, p, origin, aspath, community, - atomic_aggregate, aggregate); + ecommunity, lcommunity, atomic_aggregate, + aggregate); if (aggregate->count == 0) { if (aspath) aspath_free(aspath); if (community) community_free(community); + if (ecommunity) + ecommunity_free(&ecommunity); + if (lcommunity) + lcommunity_free(&lcommunity); } } @@ -5871,7 +5949,8 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, aggregate = bgp_aggregate_get_node_info(rn); bgp_aggregate_delete(bgp, &p, afi, safi, aggregate); - bgp_aggregate_install(bgp, afi, safi, &p, 0, NULL, NULL, 0, aggregate); + bgp_aggregate_install(bgp, afi, safi, &p, 0, NULL, NULL, + NULL, NULL, 0, aggregate); /* Unlock aggregate address configuration. */ bgp_aggregate_set_node_info(rn, NULL); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 20e6a18251..01d33a869d 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2740,7 +2740,8 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str, ret = peer_group_remote_as(bgp, peer_str, &as, as_type); if (ret < 0) { vty_out(vty, - "%% Create the peer-group or interface first\n"); + "%% Create the peer-group or interface first or specify \"interface\" keyword\n"); + vty_out(vty, "%% if using an unnumbered interface neighbor\n"); return CMD_WARNING_CONFIG_FAILED; } return CMD_SUCCESS; diff --git a/configure.ac b/configure.ac index 12100121d6..60d3a876a8 100755 --- a/configure.ac +++ b/configure.ac @@ -958,10 +958,6 @@ case "$host_os" in AC_CHECK_LIB(socket, main) AC_CHECK_LIB(nsl, main) AC_CHECK_LIB(umem, main) - AC_CHECK_FUNCS([printstack], [ - AC_DEFINE([HAVE_PRINTSTACK],1,[Solaris printstack]) - AC_DEFINE([HAVE_STACK_TRACE],1,[Stack symbols decode functionality]) - ]) CURSES=-lcurses SOLARIS="solaris" ;; @@ -1811,17 +1807,31 @@ dnl check for glibc 'backtrace' dnl --------------------------- if test x"${enable_backtrace}" != x"no" ; then backtrace_ok=no - AC_CHECK_HEADER([execinfo.h], [ - AC_SEARCH_LIBS([backtrace], [execinfo], [ - AC_DEFINE(HAVE_GLIBC_BACKTRACE,,[Glibc backtrace]) - AC_DEFINE(HAVE_STACK_TRACE,,[Stack symbol decoding]) - backtrace_ok=yes - ],, [-lm]) + PKG_CHECK_MODULES([UNWIND], [libunwind], [ + AC_DEFINE(HAVE_LIBUNWIND, 1, [libunwind]) + backtrace_ok=yes + ], [ + case "$host_os" in + sunos* | solaris2*) + AC_CHECK_FUNCS([printstack], [ + AC_DEFINE([HAVE_PRINTSTACK], 1, [Solaris printstack]) + backtrace_ok=yes + ]) + ;; + esac + if test "$backtrace_ok" = no; then + AC_CHECK_HEADER([execinfo.h], [ + AC_SEARCH_LIBS([backtrace], [execinfo], [ + AC_DEFINE(HAVE_GLIBC_BACKTRACE, 1, [Glibc backtrace]) + backtrace_ok=yes + ],, [-lm]) + ]) + fi ]) if test x"${enable_backtrace}" = x"yes" -a x"${backtrace_ok}" = x"no"; then dnl user explicitly requested backtrace but we failed to find support - AC_MSG_FAILURE([failed to find backtrace support]) + AC_MSG_FAILURE([failed to find backtrace or libunwind support]) fi fi diff --git a/lib/command.c b/lib/command.c index 60c5f4e75b..6fe4ae2d8f 100644 --- a/lib/command.c +++ b/lib/command.c @@ -1281,7 +1281,8 @@ int cmd_execute(struct vty *vty, const char *cmd, * as to why no command could be executed. */ int command_config_read_one_line(struct vty *vty, - const struct cmd_element **cmd, int use_daemon) + const struct cmd_element **cmd, + uint32_t line_num, int use_daemon) { vector vline; int saved_node; @@ -1322,8 +1323,16 @@ int command_config_read_one_line(struct vty *vty, } } - if (ret != CMD_SUCCESS && ret != CMD_WARNING) - memcpy(vty->error_buf, vty->buf, VTY_BUFSIZ); + if (ret != CMD_SUCCESS && ret != CMD_WARNING) { + struct vty_error *ve = XCALLOC(MTYPE_TMP, sizeof(*ve)); + + memcpy(ve->error_buf, vty->buf, VTY_BUFSIZ); + ve->line_num = line_num; + if (!vty->error) + vty->error = list_new(); + + listnode_add(vty->error, ve); + } cmd_free_strvec(vline); @@ -1337,10 +1346,9 @@ int config_from_file(struct vty *vty, FILE *fp, unsigned int *line_num) *line_num = 0; while (fgets(vty->buf, VTY_BUFSIZ, fp)) { - if (!error_ret) - ++(*line_num); + ++(*line_num); - ret = command_config_read_one_line(vty, NULL, 0); + ret = command_config_read_one_line(vty, NULL, *line_num, 0); if (ret != CMD_SUCCESS && ret != CMD_WARNING && ret != CMD_ERR_NOTHING_TODO) diff --git a/lib/command.h b/lib/command.h index 8e51641b88..fbff1e67f4 100644 --- a/lib/command.h +++ b/lib/command.h @@ -419,7 +419,7 @@ extern char **cmd_complete_command(vector, struct vty *, int *status); extern const char *cmd_prompt(enum node_type); extern int command_config_read_one_line(struct vty *vty, const struct cmd_element **, - int use_config_node); + uint32_t line_num, int use_config_node); extern int config_from_file(struct vty *, FILE *, unsigned int *line_num); extern enum node_type node_parent(enum node_type); /* @@ -38,6 +38,12 @@ #include <ucontext.h> #endif +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#include <dlfcn.h> +#endif + DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging") static int logfile_fd = -1; /* Used in signal handler. */ @@ -313,7 +319,9 @@ static char *num_append(char *s, int len, unsigned long x) return str_append(s, len, t); } -#if defined(SA_SIGINFO) || defined(HAVE_STACK_TRACE) +#if defined(SA_SIGINFO) \ + || defined(HAVE_PRINTSTACK) \ + || defined(HAVE_GLIBC_BACKTRACE) static char *hex_append(char *s, int len, unsigned long x) { char buf[30]; @@ -533,7 +541,37 @@ void zlog_signal(int signo, const char *action Needs to be enhanced to support syslog logging. */ void zlog_backtrace_sigsafe(int priority, void *program_counter) { -#ifdef HAVE_STACK_TRACE +#ifdef HAVE_LIBUNWIND + char buf[100]; + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, off, sp; + Dl_info dlinfo; + + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + while (unw_step(&cursor) > 0) { + char name[128] = "?"; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + if (unw_is_signal_frame(&cursor)) + dprintf(2, " ---- signal ----\n"); + + if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) { + snprintf(name, sizeof(name), "%s+%#lx", + buf, (long)off); + } + dprintf(2, "%-30s %16lx %16lx", name, (long)ip, (long)sp); + if (dladdr((void *)ip, &dlinfo)) { + dprintf(2, " %s (mapped at %p)", + dlinfo.dli_fname, dlinfo.dli_fbase); + } + dprintf(2, "\n"); + + } +#elif defined(HAVE_GLIBC_BACKTRACE) || defined(HAVE_PRINTSTACK) static const char pclabel[] = "Program counter: "; void *array[64]; int size; @@ -624,9 +662,38 @@ void zlog_backtrace_sigsafe(int priority, void *program_counter) void zlog_backtrace(int priority) { -#ifndef HAVE_GLIBC_BACKTRACE - zlog(priority, "No backtrace available on this platform."); -#else +#ifdef HAVE_LIBUNWIND + char buf[100]; + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, off, sp; + Dl_info dlinfo; + + unw_getcontext(&uc); + unw_init_local(&cursor, &uc); + zlog(priority, "Backtrace:"); + while (unw_step(&cursor) > 0) { + char name[128] = "?"; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + if (unw_is_signal_frame(&cursor)) + zlog(priority, " ---- signal ----"); + + if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) + snprintf(name, sizeof(name), "%s+%#lx", + buf, (long)off); + + if (dladdr((void *)ip, &dlinfo)) + zlog(priority, "%-30s %16lx %16lx %s (mapped at %p)", + name, (long)ip, (long)sp, + dlinfo.dli_fname, dlinfo.dli_fbase); + else + zlog(priority, "%-30s %16lx %16lx", + name, (long)ip, (long)sp); + } +#elif defined(HAVE_GLIBC_BACKTRACE) void *array[20]; int size, i; char **strings; @@ -651,7 +718,9 @@ void zlog_backtrace(int priority) zlog(priority, "[bt %d] %s", i, strings[i]); free(strings); } -#endif /* HAVE_GLIBC_BACKTRACE */ +#else /* !HAVE_GLIBC_BACKTRACE && !HAVE_LIBUNWIND */ + zlog(priority, "No backtrace available on this platform."); +#endif } void zlog(int priority, const char *format, ...) diff --git a/lib/subdir.am b/lib/subdir.am index dd2731f74c..eef00a9086 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@ +lib_libfrr_la_LIBADD = @LIBCAP@ $(UNWIND_LIBS) lib_libfrr_la_SOURCES = \ lib/agg_table.c \ @@ -1695,7 +1695,6 @@ struct vty *vty_new() new->lbuf = buffer_new(0); new->obuf = buffer_new(0); /* Use default buffer size. */ new->buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ); - new->error_buf = XCALLOC(MTYPE_VTY, VTY_BUFSIZ); new->max = VTY_BUFSIZ; return new; @@ -2278,6 +2277,13 @@ void vty_serv_sock(const char *addr, unsigned short port, const char *path) #endif /* VTYSH */ } +static void vty_error_delete(void *arg) +{ + struct vty_error *ve = arg; + + XFREE(MTYPE_TMP, ve); +} + /* Close vty interface. Warning: call this only from functions that will be careful not to access the vty afterwards (since it has now been freed). This is safest from top-level functions (called @@ -2329,8 +2335,10 @@ void vty_close(struct vty *vty) if (vty->buf) XFREE(MTYPE_VTY, vty->buf); - if (vty->error_buf) - XFREE(MTYPE_VTY, vty->error_buf); + if (vty->error) { + vty->error->del = vty_error_delete; + list_delete(&vty->error); + } /* Check configure. */ vty_config_unlock(vty); @@ -2368,6 +2376,8 @@ static void vty_read_file(FILE *confp) { int ret; struct vty *vty; + struct vty_error *ve; + struct listnode *node; unsigned int line_num = 0; vty = vty_new(); @@ -2417,11 +2427,13 @@ static void vty_read_file(FILE *confp) break; } - nl = strchr(vty->error_buf, '\n'); - if (nl) - *nl = '\0'; - flog_err(EC_LIB_VTY, "ERROR: %s on config line %u: %s", message, - line_num, vty->error_buf); + for (ALL_LIST_ELEMENTS_RO(vty->error, node, ve)) { + nl = strchr(ve->error_buf, '\n'); + if (nl) + *nl = '\0'; + flog_err(EC_LIB_VTY, "ERROR: %s on config line %u: %s", + message, ve->line_num, ve->error_buf); + } } vty_close(vty); @@ -33,6 +33,11 @@ #define VTY_BUFSIZ 4096 #define VTY_MAXHIST 20 +struct vty_error { + char error_buf[VTY_BUFSIZ]; + uint32_t line_num; +}; + /* VTY struct. */ struct vty { /* File descripter of this vty. */ @@ -71,7 +76,7 @@ struct vty { char *buf; /* Command input error buffer */ - char *error_buf; + struct list *error; /* Command cursor point */ int cp; diff --git a/tests/lib/test_segv.c b/tests/lib/test_segv.c index 3c9b57f049..43ca0837d5 100644 --- a/tests/lib/test_segv.c +++ b/tests/lib/test_segv.c @@ -32,10 +32,39 @@ struct quagga_signal_t sigs[] = {}; struct thread_master *master; -static int threadfunc(struct thread *thread) +void func1(int *arg); +void func3(void); + +void func1(int *arg) { int *null = NULL; *null += 1; + *arg = 1; +} + +static void func2(size_t depth, int *arg) +{ + /* variable stack frame size */ + int buf[depth]; + for (size_t i = 0; i < depth; i++) + buf[i] = arg[i] + 1; + if (depth > 0) + func2(depth - 1, buf); + else + func1(&buf[0]); + for (size_t i = 0; i < depth; i++) + buf[i] = arg[i] + 2; +} + +void func3(void) +{ + int buf[6]; + func2(6, buf); +} + +static int threadfunc(struct thread *thread) +{ + func3(); return 0; } diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 6a92b90813..8ed11f1876 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -856,7 +856,7 @@ int vtysh_config_from_file(struct vty *vty, FILE *fp) while (fgets(vty->buf, VTY_BUFSIZ, fp)) { lineno++; - ret = command_config_read_one_line(vty, &cmd, 1); + ret = command_config_read_one_line(vty, &cmd, lineno, 1); switch (ret) { case CMD_WARNING: |
