summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--bgpd/bgp_attr.c16
-rw-r--r--bgpd/bgp_attr.h11
-rw-r--r--bgpd/bgp_route.c119
-rw-r--r--bgpd/bgp_vty.c3
-rwxr-xr-xconfigure.ac32
-rw-r--r--lib/command.c20
-rw-r--r--lib/command.h2
-rw-r--r--lib/log.c81
-rw-r--r--lib/subdir.am2
-rw-r--r--lib/vty.c28
-rw-r--r--lib/vty.h7
-rw-r--r--tests/lib/test_segv.c31
-rw-r--r--vtysh/vtysh.c2
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);
/*
diff --git a/lib/log.c b/lib/log.c
index 10cb2cd8a4..5cc303daf0 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -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 \
diff --git a/lib/vty.c b/lib/vty.c
index f812dd4279..a73cc23b97 100644
--- a/lib/vty.c
+++ b/lib/vty.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);
diff --git a/lib/vty.h b/lib/vty.h
index b55abf2204..efe91a568b 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -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: