From feda3ca36c9d28af67b26336b41b1d839fb2d79f Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 22 Aug 2017 18:49:23 +0200 Subject: [PATCH 01/11] *: update git-reindent-branch.py - autodetect whether it's on master or stable/3.0 - grab .clang-format from master Signed-off-by: David Lamparter --- git-reindent-branch.py | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/git-reindent-branch.py b/git-reindent-branch.py index b0dd8db6de..c207f5946f 100644 --- a/git-reindent-branch.py +++ b/git-reindent-branch.py @@ -11,14 +11,28 @@ def run(cmd): proc.wait() return rv +clangfmt = run(['git', 'show', 'master:.clang-format']) + argp = argparse.ArgumentParser(description = 'git whitespace-fixing tool') argp.add_argument('branch', metavar='BRANCH', type = str, nargs = '?', default = 'HEAD') args = argp.parse_args() branch = args.branch commit = run(['git', 'rev-list', '-n', '1', branch, '--']).strip() -beforeid = run(['git', 'rev-list', '-n', '1', 'reindent-master-before', '--']).strip() -afterid = run(['git', 'rev-list', '-n', '1', 'reindent-master-after', '--']).strip() + +# frr-3.1-dev = first commit that is on master but not on stable/3.0 +masterid = run(['git', 'rev-list', '-n', '1', 'frr-3.1-dev', '--']).strip() +masterbase = run(['git', 'merge-base', commit, masterid]).strip() + +if masterbase == masterid: + refbranch = 'master' +else: + refbranch = '3.0' + +sys.stderr.write('autodetected base: %s (can be 3.0 or master)\n' % refbranch) + +beforeid = run(['git', 'rev-list', '-n', '1', 'reindent-%s-before' % refbranch, '--']).strip() +afterid = run(['git', 'rev-list', '-n', '1', 'reindent-%s-after' % refbranch, '--']).strip() beforebase = run(['git', 'merge-base', commit, beforeid]).strip() afterbase = run(['git', 'merge-base', commit, afterid]).strip() @@ -28,10 +42,10 @@ if afterbase == afterid: sys.exit(1) if beforebase != beforeid: - sys.stderr.write('you need to rebase your branch onto the tag "reindent-master-before"\n') + sys.stderr.write('you need to rebase your branch onto the tag "reindent-%s-before"\n' % refbranch) sys.exit(1) -revs = run(['git', 'rev-list', 'reindent-master-before..%s' % commit]).strip().split('\n') +revs = run(['git', 'rev-list', 'reindent-%s-before..%s' % (refbranch, commit)]).strip().split('\n') revs.reverse() srcdir = os.getcwd() @@ -39,9 +53,12 @@ tmpdir = tempfile.mkdtemp('frrindent') os.chdir(tmpdir) sys.stderr.write('using temporary directory %s; %d revisions\n' % (tmpdir, len(revs))) -run(['git', 'clone', '-s', '-b', 'reindent-master-after', srcdir, 'repo']) +run(['git', 'clone', '-s', '-b', 'reindent-%s-after' % refbranch, srcdir, 'repo']) os.chdir('repo') +with open('.clang-format', 'w') as fd: + fd.write(clangfmt) + prev = beforeid for rev in revs: filestat = run(['git', 'diff', '-z', '--name-status', prev, rev]).rstrip('\0').split('\0') From 9d1c2659293a757a672bf0aa0d2f5ca20a2b28e5 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 15:48:36 +0200 Subject: [PATCH 02/11] zebra: don't print 0.0.0.0:0 for FPM config Fixes: #319 Signed-off-by: David Lamparter --- zebra/zebra_fpm.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c index b88bce9e82..8c0700ac8b 100644 --- a/zebra/zebra_fpm.c +++ b/zebra/zebra_fpm.c @@ -1589,8 +1589,10 @@ static int fpm_remote_srv_write(struct vty *vty) in.s_addr = zfpm_g->fpm_server; - if (zfpm_g->fpm_server != FPM_DEFAULT_IP - || zfpm_g->fpm_port != FPM_DEFAULT_PORT) + if ((zfpm_g->fpm_server != FPM_DEFAULT_IP + && zfpm_g->fpm_server != INADDR_ANY) + || (zfpm_g->fpm_port != FPM_DEFAULT_PORT + && zfpm_g->fpm_port != 0)) vty_out(vty, "fpm connection ip %s port %d\n", inet_ntoa(in), zfpm_g->fpm_port); From 9eed278b163d2175ee714869085a54f2c3726cca Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 16:18:49 +0200 Subject: [PATCH 03/11] lib: centralized memstats-at-exit adds a new all-daemon "debug memstats-at-exit" command. Also saves memstats to a file in /tmp, useful if a long-running daemon is having weird issues (e.g. in a user install). Fixes: #437 Signed-off-by: David Lamparter --- bgpd/bgp_main.c | 3 --- lib/command.c | 17 +++++++++++++++++ lib/libfrr.c | 30 ++++++++++++++++++++++++++++++ lib/libfrr.h | 2 ++ lib/log.c | 2 +- lib/memory.c | 10 ++++++---- lib/memory.h | 4 +++- lib/sigevent.c | 2 +- tests/isisd/test_fuzz_isis_tlv.c | 2 +- tests/lib/cli/common_cli.c | 2 +- 10 files changed, 62 insertions(+), 12 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 3bf9ea02d5..fa8c45b004 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -219,9 +219,6 @@ static __attribute__((__noreturn__)) void bgp_exit(int status) memset(bm, 0, sizeof(*bm)); frr_fini(); - - if (bgp_debug_count()) - log_memstats_stderr("bgpd"); exit(status); } diff --git a/lib/command.c b/lib/command.c index 45b5593a3e..f47bf81452 100644 --- a/lib/command.c +++ b/lib/command.c @@ -42,6 +42,7 @@ #include "command_graph.h" #include "qobj.h" #include "defaults.h" +#include "libfrr.h" DEFINE_MTYPE(LIB, HOST, "Host config") DEFINE_MTYPE(LIB, STRVEC, "String vector") @@ -555,6 +556,9 @@ static int config_write_host(struct vty *vty) else if (!host.motd) vty_out(vty, "no banner motd\n"); + if (debug_memstats_at_exit) + vty_out(vty, "!\ndebug memstats-at-exit\n"); + return 1; } @@ -2366,6 +2370,17 @@ DEFUN (no_config_log_timestamp_precision, return CMD_SUCCESS; } +DEFUN (debug_memstats, + debug_memstats_cmd, + "[no] debug memstats-at-exit", + NO_STR + DEBUG_STR + "Print memory type statistics at exit\n") +{ + debug_memstats_at_exit = !!strcmp(argv[0]->text, "no"); + return CMD_SUCCESS; +} + int cmd_banner_motd_file(const char *file) { int success = CMD_SUCCESS; @@ -2527,6 +2542,7 @@ void cmd_init(int terminal) /* Each node's basic commands. */ install_element(VIEW_NODE, &show_version_cmd); install_element(ENABLE_NODE, &show_startup_config_cmd); + install_element(ENABLE_NODE, &debug_memstats_cmd); if (terminal) { install_element(VIEW_NODE, &config_list_cmd); @@ -2560,6 +2576,7 @@ void cmd_init(int terminal) install_element(CONFIG_NODE, &hostname_cmd); install_element(CONFIG_NODE, &no_hostname_cmd); install_element(CONFIG_NODE, &frr_version_defaults_cmd); + install_element(CONFIG_NODE, &debug_memstats_cmd); if (terminal > 0) { install_element(CONFIG_NODE, &password_cmd); diff --git a/lib/libfrr.c b/lib/libfrr.c index 255f91ec71..c3ef04c673 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -52,6 +52,8 @@ char frr_zclientpath[256]; static char pidfile_default[256]; static char vtypath_default[256]; +bool debug_memstats_at_exit = 0; + static char comb_optstr[256]; static struct option comb_lo[64]; static struct option *comb_next_lo = &comb_lo[0]; @@ -841,6 +843,10 @@ void frr_early_fini(void) void frr_fini(void) { + FILE *fp; + char filename[128]; + int have_leftovers; + hook_call(frr_fini); /* memory_init -> nothing needed */ @@ -851,4 +857,28 @@ void frr_fini(void) thread_master_free(master); closezlog(); /* frrmod_init -> nothing needed / hooks */ + + if (!debug_memstats_at_exit) + return; + + have_leftovers = log_memstats(stderr, di->name); + + /* in case we decide at runtime that we want exit-memstats for + * a daemon, but it has no stderr because it's daemonized + * (only do this if we actually have something to print though) + */ + if (!have_leftovers) + return; + + snprintf(filename, sizeof(filename), + "/tmp/frr-memstats-%s-%llu-%llu", + di->name, + (unsigned long long)getpid(), + (unsigned long long)time(NULL)); + + fp = fopen(filename, "w"); + if (fp) { + log_memstats(fp, di->name); + fclose(fp); + } } diff --git a/lib/libfrr.h b/lib/libfrr.h index 8a15d168a1..f7d69eecb3 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -121,4 +121,6 @@ extern const char frr_moduledir[]; extern char frr_protoname[]; extern char frr_protonameinst[]; +extern bool debug_memstats_at_exit; + #endif /* _ZEBRA_FRR_H */ diff --git a/lib/log.c b/lib/log.c index 5c89e7080e..5b2429b31a 100644 --- a/lib/log.c +++ b/lib/log.c @@ -701,7 +701,7 @@ void _zlog_assert_failed(const char *assertion, const char *file, assertion, file, line, (function ? function : "?")); zlog_backtrace(LOG_CRIT); zlog_thread_info(LOG_CRIT); - log_memstats_stderr("log"); + log_memstats(stderr, "log"); abort(); } diff --git a/lib/memory.c b/lib/memory.c index 0ccc204002..c684c7605c 100644 --- a/lib/memory.c +++ b/lib/memory.c @@ -104,6 +104,7 @@ int qmem_walk(qmem_walk_fn *func, void *arg) } struct exit_dump_args { + FILE *fp; const char *prefix; int error; }; @@ -113,7 +114,7 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt) struct exit_dump_args *eda = arg; if (!mt) { - fprintf(stderr, + fprintf(eda->fp, "%s: showing active allocations in " "memory group %s\n", eda->prefix, mg->name); @@ -122,15 +123,16 @@ static int qmem_exit_walker(void *arg, struct memgroup *mg, struct memtype *mt) char size[32]; eda->error++; snprintf(size, sizeof(size), "%10zu", mt->size); - fprintf(stderr, "%s: memstats: %-30s: %6zu * %s\n", + fprintf(eda->fp, "%s: memstats: %-30s: %6zu * %s\n", eda->prefix, mt->name, mt->n_alloc, mt->size == SIZE_VAR ? "(variably sized)" : size); } return 0; } -void log_memstats_stderr(const char *prefix) +int log_memstats(FILE *fp, const char *prefix) { - struct exit_dump_args eda = {.prefix = prefix, .error = 0}; + struct exit_dump_args eda = { .fp = fp, .prefix = prefix, .error = 0 }; qmem_walk(qmem_exit_walker, &eda); + return eda.error; } diff --git a/lib/memory.h b/lib/memory.h index d5facad583..132d4abd30 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -18,6 +18,7 @@ #define _QUAGGA_MEMORY_H #include +#include #include #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) @@ -194,7 +195,8 @@ static inline size_t mtype_stats_alloc(struct memtype *mt) * last value from qmem_walk_fn. */ typedef int qmem_walk_fn(void *arg, struct memgroup *mg, struct memtype *mt); extern int qmem_walk(qmem_walk_fn *func, void *arg); -extern void log_memstats_stderr(const char *); +extern int log_memstats(FILE *fp, const char *); +#define log_memstats_stderr(prefix) log_memstats(stderr, prefix) extern void memory_oom(size_t size, const char *name); diff --git a/lib/sigevent.c b/lib/sigevent.c index 2a04fa23cb..d55f368dfb 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -245,7 +245,7 @@ core_handler(int signo #endif ); /* dump memory stats on core */ - log_memstats_stderr("core_handler"); + log_memstats(stderr, "core_handler"); abort(); } diff --git a/tests/isisd/test_fuzz_isis_tlv.c b/tests/isisd/test_fuzz_isis_tlv.c index 6727e663f5..e61e9639ee 100644 --- a/tests/isisd/test_fuzz_isis_tlv.c +++ b/tests/isisd/test_fuzz_isis_tlv.c @@ -23,7 +23,7 @@ static bool atexit_registered; static void show_meminfo_at_exit(void) { - log_memstats_stderr("isis fuzztest"); + log_memstats(stderr, "isis fuzztest"); } static int comp_line(const void *p1, const void *p2) diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index 77f1610fe2..0fd2f80a39 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -53,7 +53,7 @@ static void vty_do_exit(int isexit) thread_master_free(master); closezlog(); - log_memstats_stderr("testcli"); + log_memstats(stderr, "testcli"); if (!isexit) exit(0); } From 6bd2b3608d6dc1eca171c30916f029f6f867db6b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 16:23:17 +0200 Subject: [PATCH 04/11] lib: fix cosmetic issue with exit race if we're using --terminal, the daemon may in some cases exit fast enough for the parent to see this; this resulted in a confusing/bogus "failed to start, exited 0" message. Signed-off-by: David Lamparter --- lib/libfrr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/libfrr.c b/lib/libfrr.c index c3ef04c673..9944fdd1e1 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -641,7 +641,10 @@ static void frr_daemon_wait(int fd) exit(0); /* child failed one way or another ... */ - if (WIFEXITED(exitstat)) + if (WIFEXITED(exitstat) && WEXITSTATUS(exitstat) == 0) + /* can happen in --terminal case if exit is fast enough */ + (void)0; + else if (WIFEXITED(exitstat)) fprintf(stderr, "%s failed to start, exited %d\n", di->name, WEXITSTATUS(exitstat)); else if (WIFSIGNALED(exitstat)) From 427f8e61bb711b51891dbaee845215ca228951f1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 16:54:15 +0200 Subject: [PATCH 05/11] ospf6d: properly update prefix list references Register add/delete hooks with the prefix list code to properly change ospf6_area's prefix list in/out pointers. There are 2 other uncached uses of prefix lists in the ASBR route-map code and the interface code; these should probably be cached too. (To be fixed another day...) Fixes: #453 Signed-off-by: David Lamparter --- lib/plist.c | 8 ++++++ lib/plist.h | 1 + ospf6d/ospf6_abr.c | 59 ++++++++++++++++++--------------------------- ospf6d/ospf6_area.c | 41 ++++++++++++++++++------------- ospf6d/ospf6_area.h | 1 + ospf6d/ospf6d.c | 18 ++++++++++++++ 6 files changed, 75 insertions(+), 53 deletions(-) diff --git a/lib/plist.c b/lib/plist.c index b0cf42ca49..ebd628d724 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -122,6 +122,14 @@ const char *prefix_list_name(struct prefix_list *plist) return plist->name; } +afi_t prefix_list_afi(struct prefix_list *plist) +{ + if (plist->master == &prefix_master_ipv4 + || plist->master == &prefix_master_orf_v4) + return AFI_IP; + return AFI_IP6; +} + /* Lookup prefix_list from list of prefix_list by name. */ static struct prefix_list *prefix_list_lookup_do(afi_t afi, int orf, const char *name) diff --git a/lib/plist.h b/lib/plist.h index 73d8da509a..3eba3046ae 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -48,6 +48,7 @@ extern void prefix_list_add_hook(void (*func)(struct prefix_list *)); extern void prefix_list_delete_hook(void (*func)(struct prefix_list *)); extern const char *prefix_list_name(struct prefix_list *); +extern afi_t prefix_list_afi(struct prefix_list *); extern struct prefix_list *prefix_list_lookup(afi_t, const char *); extern enum prefix_list_type prefix_list_apply(struct prefix_list *, void *); diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index f198ac4af6..36528d063c 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -386,27 +386,20 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, } /* Check filter-list */ - if (PREFIX_NAME_OUT(area)) { - if (PREFIX_LIST_OUT(area) == NULL) - PREFIX_LIST_OUT(area) = prefix_list_lookup( - AFI_IP6, PREFIX_NAME_OUT(area)); - - if (PREFIX_LIST_OUT(area)) - if (prefix_list_apply(PREFIX_LIST_OUT(area), - &route->prefix) - != PREFIX_PERMIT) { - if (is_debug) { - inet_ntop(AF_INET, - &(ADV_ROUTER_IN_PREFIX( - &route->prefix)), - buf, sizeof(buf)); - zlog_debug( - "prefix %s was denied by filter-list out", - buf); - } - return 0; + if (PREFIX_LIST_OUT(area)) + if (prefix_list_apply(PREFIX_LIST_OUT(area), &route->prefix) + != PREFIX_PERMIT) { + if (is_debug) { + inet_ntop(AF_INET, + &(ADV_ROUTER_IN_PREFIX( + &route->prefix)), + buf, sizeof(buf)); + zlog_debug( + "prefix %s was denied by filter-list out", + buf); } - } + return 0; + } /* the route is going to be originated. store it in area's summary_table */ @@ -873,22 +866,16 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) } /* Check input prefix-list */ - if (PREFIX_NAME_IN(oa)) { - if (PREFIX_LIST_IN(oa) == NULL) - PREFIX_LIST_IN(oa) = - prefix_list_lookup(AFI_IP6, PREFIX_NAME_IN(oa)); - - if (PREFIX_LIST_IN(oa)) - if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix) - != PREFIX_PERMIT) { - if (is_debug) - zlog_debug( - "Prefix was denied by prefix-list"); - if (old) - ospf6_route_remove(old, table); - return; - } - } + if (PREFIX_LIST_IN(oa)) + if (prefix_list_apply(PREFIX_LIST_IN(oa), &prefix) + != PREFIX_PERMIT) { + if (is_debug) + zlog_debug( + "Prefix was denied by prefix-list"); + if (old) + ospf6_route_remove(old, table); + return; + } /* (5),(6): the path preference is handled by the sorting in the routing table. Always install the path by substituting diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index a4cc0bf420..649d7a1000 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -45,6 +45,8 @@ #include "ospf6_asbr.h" #include "ospf6d.h" +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name") + int ospf6_area_cmp(void *va, void *vb) { struct ospf6_area *oa = (struct ospf6_area *)va; @@ -579,17 +581,15 @@ DEFUN (area_filter_list, plist = prefix_list_lookup(AFI_IP6, plistname); if (strmatch(inout, "in")) { PREFIX_LIST_IN(area) = plist; - if (PREFIX_NAME_IN(area)) - free(PREFIX_NAME_IN(area)); - - PREFIX_NAME_IN(area) = strdup(plistname); + XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area)); + PREFIX_NAME_IN(area) = XSTRDUP(MTYPE_OSPF6_PLISTNAME, + plistname); ospf6_abr_reimport(area); } else { PREFIX_LIST_OUT(area) = plist; - if (PREFIX_NAME_OUT(area)) - free(PREFIX_NAME_OUT(area)); - - PREFIX_NAME_OUT(area) = strdup(plistname); + XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area)); + PREFIX_NAME_OUT(area) = XSTRDUP(MTYPE_OSPF6_PLISTNAME, + plistname); ospf6_abr_enable_area(area); } @@ -622,27 +622,34 @@ DEFUN (no_area_filter_list, return CMD_SUCCESS; PREFIX_LIST_IN(area) = NULL; - if (PREFIX_NAME_IN(area)) - free(PREFIX_NAME_IN(area)); - - PREFIX_NAME_IN(area) = NULL; + XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_IN(area)); ospf6_abr_reimport(area); } else { if (PREFIX_NAME_OUT(area)) if (!strmatch(PREFIX_NAME_OUT(area), plistname)) return CMD_SUCCESS; - PREFIX_LIST_OUT(area) = NULL; - if (PREFIX_NAME_OUT(area)) - free(PREFIX_NAME_OUT(area)); - - PREFIX_NAME_OUT(area) = NULL; + XFREE(MTYPE_OSPF6_PLISTNAME, PREFIX_NAME_OUT(area)); ospf6_abr_enable_area(area); } return CMD_SUCCESS; } +void ospf6_area_plist_update(struct prefix_list *plist, int add) +{ + struct ospf6_area *oa; + struct listnode *n; + const char *name = prefix_list_name(plist); + + for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, n, oa)) { + if (!strcmp(PREFIX_NAME_IN(oa), name)) + PREFIX_LIST_IN(oa) = add ? plist : NULL; + if (!strcmp(PREFIX_NAME_OUT(oa), name)) + PREFIX_LIST_OUT(oa) = add ? plist : NULL; + } +} + DEFUN (area_import_list, area_import_list_cmd, "area A.B.C.D import-list NAME", diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index 4bc24a6dd8..d212d92387 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -122,6 +122,7 @@ extern void ospf6_area_disable(struct ospf6_area *); extern void ospf6_area_show(struct vty *, struct ospf6_area *); +extern void ospf6_area_plist_update(struct prefix_list *plist, int add); extern void ospf6_area_config_write(struct vty *vty); extern void ospf6_area_init(void); diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index f6b9e0ec14..84a56fb505 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -24,6 +24,7 @@ #include "linklist.h" #include "vty.h" #include "command.h" +#include "plist.h" #include "ospf6_proto.h" #include "ospf6_network.h" @@ -1139,6 +1140,20 @@ DEFUN (show_ipv6_ospf6_linkstate_detail, return CMD_SUCCESS; } +static void ospf6_plist_add(struct prefix_list *plist) +{ + if (prefix_list_afi(plist) != AFI_IP6) + return; + ospf6_area_plist_update(plist, 1); +} + +static void ospf6_plist_del(struct prefix_list *plist) +{ + if (prefix_list_afi(plist) != AFI_IP6) + return; + ospf6_area_plist_update(plist, 0); +} + /* Install ospf related commands. */ void ospf6_init(void) { @@ -1154,6 +1169,9 @@ void ospf6_init(void) ospf6_asbr_init(); ospf6_abr_init(); + prefix_list_add_hook(ospf6_plist_add); + prefix_list_delete_hook(ospf6_plist_del); + ospf6_bfd_init(); install_node(&debug_node, config_write_ospf6_debug); From 3cbb67f2294305ab8046db0405b0d486650d30dd Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 17:06:24 +0200 Subject: [PATCH 06/11] lib: better warnings for install_element Also fixes misuse of vector_slot() - that one doesn't check for access beyond end of vector... And print node names in grammar sandbox "printall". Fixes: #543 Signed-off-by: David Lamparter --- lib/command.c | 32 ++++++++++++++++++-------------- lib/grammar_sandbox.c | 3 ++- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/lib/command.c b/lib/command.c index f47bf81452..c86025a3bd 100644 --- a/lib/command.c +++ b/lib/command.c @@ -360,21 +360,23 @@ void install_element(enum node_type ntype, struct cmd_element *cmd) return; } - cnode = vector_slot(cmdvec, ntype); + cnode = vector_lookup(cmdvec, ntype); if (cnode == NULL) { fprintf(stderr, - "Command node %d doesn't exist, please check it\n", - ntype); - fprintf(stderr, - "Have you called install_node before this install_element?\n"); + "%s[%s]:\n" + "\tnode %d (%s) does not exist.\n" + "\tplease call install_node() before install_element()\n", + cmd->name, cmd->string, ntype, node_names[ntype]); exit(EXIT_FAILURE); } if (hash_lookup(cnode->cmd_hash, cmd) != NULL) { fprintf(stderr, - "Multiple command installs to node %d of command:\n%s\n", - ntype, cmd->string); + "%s[%s]:\n" + "\tnode %d (%s) already has this command installed.\n" + "\tduplicate install_element call?\n", + cmd->name, cmd->string, ntype, node_names[ntype]); return; } @@ -407,21 +409,23 @@ void uninstall_element(enum node_type ntype, struct cmd_element *cmd) return; } - cnode = vector_slot(cmdvec, ntype); + cnode = vector_lookup(cmdvec, ntype); if (cnode == NULL) { fprintf(stderr, - "Command node %d doesn't exist, please check it\n", - ntype); - fprintf(stderr, - "Have you called install_node before this install_element?\n"); + "%s[%s]:\n" + "\tnode %d (%s) does not exist.\n" + "\tplease call install_node() before uninstall_element()\n", + cmd->name, cmd->string, ntype, node_names[ntype]); exit(EXIT_FAILURE); } if (hash_release(cnode->cmd_hash, cmd) == NULL) { fprintf(stderr, - "Trying to uninstall non-installed command (node %d):\n%s\n", - ntype, cmd->string); + "%s[%s]:\n" + "\tnode %d (%s) does not have this command installed.\n" + "\tduplicate uninstall_element call?\n", + cmd->name, cmd->string, ntype, node_names[ntype]); return; } diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index 96ecfa44d3..3c6396f347 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -404,7 +404,8 @@ DEFUN (grammar_findambig, nodegraph = cnode->cmdgraph; if (!nodegraph) continue; - vty_out(vty, "scanning node %d\n", scannode - 1); + vty_out(vty, "scanning node %d (%s)\n", + scannode - 1, node_names[scannode - 1]); } commands = cmd_graph_permutations(nodegraph); From 67eb7a6c9910c121e7975e26eaae199cb03ff2b1 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 17:33:17 +0200 Subject: [PATCH 07/11] python/clippy: make output file writing less weird This should stomp out any parallel build issues in this regard. Fixes: #971 Signed-off-by: David Lamparter --- common.am | 3 +-- python/clidef.py | 2 +- python/clippy/__init__.py | 15 ++++++++++++--- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/common.am b/common.am index b115a871b9..c0094b1b88 100644 --- a/common.am +++ b/common.am @@ -13,8 +13,7 @@ CLIPPY_DEPS = $(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py SUFFIXES = _clippy.c .proto .pb-c.c .pb-c.h .pb.h .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 $< > $@.tmp - @{ test -f $@ && diff $@.tmp $@ >/dev/null 2>/dev/null; } && rm $@.tmp || mv $@.tmp $@ + $(AM_V_CLIPPY)$(top_builddir)/$(HOSTTOOLS)lib/clippy $(top_srcdir)/python/clidef.py -o $@ $< ## automake's "ylwrap" is a great piece of GNU software... not. .l.c: diff --git a/python/clidef.py b/python/clidef.py index 8e3c7595b7..aa6cd18b8b 100644 --- a/python/clidef.py +++ b/python/clidef.py @@ -257,4 +257,4 @@ if __name__ == '__main__': process_file(args.cfile, ofd, dumpfd, args.all_defun) if args.o is not None: - clippy.wrdiff(args.o, ofd) + clippy.wrdiff(args.o, ofd, [args.cfile, os.path.realpath(__file__)]) diff --git a/python/clippy/__init__.py b/python/clippy/__init__.py index 82aa9495d4..41aeae6b4d 100644 --- a/python/clippy/__init__.py +++ b/python/clippy/__init__.py @@ -16,6 +16,7 @@ # 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 +import os, stat import _clippy from _clippy import parse, Graph, GraphNode @@ -47,7 +48,7 @@ def dump(graph): for i, depth in graph_iterate(graph): print('\t%s%s %r' % (' ' * (depth * 2), i.type, i.text)) -def wrdiff(filename, buf): +def wrdiff(filename, buf, reffiles = []): '''write buffer to file if contents changed''' expl = '' @@ -57,8 +58,16 @@ def wrdiff(filename, buf): try: old = open(filename, 'r').read() except: pass if old == buf: + for reffile in reffiles: + # ensure output timestamp is newer than inputs, for make + reftime = os.stat(reffile)[stat.ST_MTIME] + outtime = os.stat(filename)[stat.ST_MTIME] + if outtime <= reftime: + os.utime(filename, (reftime + 1, reftime + 1)) # sys.stderr.write('%s unchanged, not written\n' % (filename)) return - with open('.new.' + filename, 'w') as out: + + newname = '%s.new-%d' % (filename, os.getpid()) + with open(newname, 'w') as out: out.write(buf) - os.rename('.new.' + filename, filename) + os.rename(newname, filename) From 8d0ab76de11bdaf38d9c89291347497bfed2d18b Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 18:21:30 +0200 Subject: [PATCH 08/11] bgpd: fix stats counting for IPv6 Fixes: #991 Signed-off-by: David Lamparter --- bgpd/bgp_route.c | 51 +++++++++++++++++++++++------------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index bb204b01f1..ee6f867cb9 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -20,6 +20,7 @@ */ #include +#include #include "prefix.h" #include "linklist.h" @@ -9347,6 +9348,7 @@ static const char *table_stats_strs[] = { struct bgp_table_stats { struct bgp_table *table; unsigned long long counts[BGP_STATS_MAX]; + double total_space; }; #if 0 @@ -9415,8 +9417,8 @@ static int bgp_table_stats_walker(struct thread *t) ts->counts[BGP_STATS_UNAGGREGATEABLE]++; /* announced address space */ if (space) - ts->counts[BGP_STATS_SPACE] += - 1 << (space - rn->p.prefixlen); + ts->total_space += pow(2.0, + space - rn->p.prefixlen); } else if (prn->info) ts->counts[BGP_STATS_MAX_AGGREGATEABLE]++; @@ -9526,31 +9528,26 @@ static int bgp_table_stats(struct vty *vty, struct bgp *bgp, afi_t afi, break; case BGP_STATS_SPACE: vty_out(vty, "%-30s: ", table_stats_strs[i]); - vty_out(vty, "%12llu\n", ts.counts[i]); - if (ts.counts[BGP_STATS_MAXBITLEN] < 9) - break; - vty_out(vty, "%30s: ", "%% announced "); - vty_out(vty, "%12.2f\n", - 100 * (float)ts.counts[BGP_STATS_SPACE] - / (float)((uint64_t)1UL - << ts.counts - [BGP_STATS_MAXBITLEN])); - vty_out(vty, "%30s: ", "/8 equivalent "); - vty_out(vty, "%12.2f\n", - (float)ts.counts[BGP_STATS_SPACE] - / (float)(1UL - << (ts.counts - [BGP_STATS_MAXBITLEN] - - 8))); - if (ts.counts[BGP_STATS_MAXBITLEN] < 25) - break; - vty_out(vty, "%30s: ", "/24 equivalent "); - vty_out(vty, "%12.2f", - (float)ts.counts[BGP_STATS_SPACE] - / (float)(1UL - << (ts.counts - [BGP_STATS_MAXBITLEN] - - 24))); + vty_out(vty, "%12g\n", ts.total_space); + + if (afi == AFI_IP6) { + vty_out(vty, "%30s: ", "/32 equivalent "); + vty_out(vty, "%12g\n", + ts.total_space * pow(2.0, -128+32)); + vty_out(vty, "%30s: ", "/48 equivalent "); + vty_out(vty, "%12g\n", + ts.total_space * pow(2.0, -128+48)); + } else { + vty_out(vty, "%30s: ", "% announced "); + vty_out(vty, "%12.2f\n", + ts.total_space * 100. * pow(2.0, -32)); + vty_out(vty, "%30s: ", "/8 equivalent "); + vty_out(vty, "%12.2f\n", + ts.total_space * pow(2.0, -32+8)); + vty_out(vty, "%30s: ", "/24 equivalent "); + vty_out(vty, "%12.2f\n", + ts.total_space * pow(2.0, -32+24)); + } break; default: vty_out(vty, "%-30s: ", table_stats_strs[i]); From c0e29be115fcf67e9b7ea77581fbcd94b3402672 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 18:51:18 +0200 Subject: [PATCH 09/11] lib: prefix: try harder to not hash garbage With prefix_ptr or prefix_ls, there can still be stuff in a struct prefix that we shouldn't hash. Signed-off-by: David Lamparter --- lib/prefix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/prefix.c b/lib/prefix.c index 2f61eb6e8b..10f77bda87 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1263,5 +1263,6 @@ unsigned prefix_hash_key(void *pp) * padding and unused prefix bytes. */ memset(©, 0, sizeof(copy)); prefix_copy(©, (struct prefix *)pp); - return jhash(©, sizeof(copy), 0x55aa5a5a); + return jhash(©, offsetof(struct prefix, u.prefix) + + PSIZE(copy.prefixlen), 0x55aa5a5a); } From 6a35bfba5e4e4135a29e87dc554b4e7f19f06831 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 15:45:05 +0200 Subject: [PATCH 10/11] build: fix libtool stupidity wrt. parallel install there's no dependency between libraries and other things to be installed, but libtool in its 90ies design wants to relink libraries when installing them. Add manual dependencies to work around this. Signed-off-by: David Lamparter --- Makefile.am | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Makefile.am b/Makefile.am index 494fcd4d56..48f4e50daa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,6 +25,14 @@ pkginclude_HEADERS = nodist_pkginclude_HEADERS = dist_examples_DATA = +## libtool, the self-made GNU scourge +## ... this should fix relinking +## ... and AUTOMAKE_DUMMY is needed to prevent automake from treating this +## as overriding the normal targets... +$(AUTOMAKE_DUMMY)install-moduleLTLIBRARIES: install-libLTLIBRARIES +$(AUTOMAKE_DUMMY)install-binPROGRAMS: install-libLTLIBRARIES +$(AUTOMAKE_DUMMY)install-sbinPROGRAMS: install-libLTLIBRARIES + include lib/subdir.am include zebra/subdir.am include qpb/subdir.am From de1a880c4e1f24e5cb4a2c1e4793fed73107ecbe Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 23 Aug 2017 20:22:31 +0200 Subject: [PATCH 11/11] lib: split off compiler magic into its own file Also make timed notices available via CONFDATE. Signed-off-by: David Lamparter --- Makefile.am | 2 +- lib/compiler.h | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/memory.h | 36 +--------------------- lib/prefix.h | 17 +---------- lib/subdir.am | 1 + lib/vty.h | 19 +++--------- 6 files changed, 89 insertions(+), 67 deletions(-) create mode 100644 lib/compiler.h diff --git a/Makefile.am b/Makefile.am index 48f4e50daa..f204f8a724 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,7 @@ include common.am AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/lib -I$(top_builddir) -I$(top_builddir)/lib AM_CFLAGS = $(WERROR) -DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" +DEFS = @DEFS@ -DSYSCONFDIR=\"$(sysconfdir)/\" -DCONFDATE=$(CONFDATE) LIBCAP = @LIBCAP@ EXTRA_DIST = diff --git a/lib/compiler.h b/lib/compiler.h new file mode 100644 index 0000000000..49a2f2a422 --- /dev/null +++ b/lib/compiler.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2015-2017 David Lamparter, for NetDEF, Inc. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _FRR_COMPILER_H +#define _FRR_COMPILER_H + +/* function attributes, use like + * void prototype(void) __attribute__((_CONSTRUCTOR(100))); + */ +#if defined(__clang__) +# if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5) +# define _RET_NONNULL , returns_nonnull +# endif +# define _CONSTRUCTOR(x) constructor(x) +#elif defined(__GNUC__) +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) +# define _RET_NONNULL , returns_nonnull +# endif +# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) +# define _CONSTRUCTOR(x) constructor(x) +# define _DESTRUCTOR(x) destructor(x) +# define _ALLOC_SIZE(x) alloc_size(x) +# endif +#endif + +#ifdef __sun +/* Solaris doesn't do constructor priorities due to linker restrictions */ +# undef _CONSTRUCTOR +# undef _DESTRUCTOR +#endif + +/* fallback versions */ +#ifndef _RET_NONNULL +# define _RET_NONNULL +#endif +#ifndef _CONSTRUCTOR +# define _CONSTRUCTOR(x) constructor +#endif +#ifndef _DESTRUCTOR +# define _DESTRUCTOR(x) destructor +#endif +#ifndef _ALLOC_SIZE +# define _ALLOC_SIZE(x) +#endif + +/* + * for warnings on macros, put in the macro content like this: + * #define MACRO BLA CPP_WARN("MACRO has been deprecated") + */ +#define CPP_STR(X) #X + +#if defined(__ICC) +#define CPP_NOTICE(text) _Pragma(CPP_STR(message __FILE__ ": " text)) +#define CPP_WARN(text) CPP_NOTICE(text) + +#elif (defined(__GNUC__) \ + && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \ + || (defined(__clang__) \ + && (__clang_major__ >= 4 \ + || (__clang_major__ == 3 && __clang_minor__ >= 5))) +#define CPP_WARN(text) _Pragma(CPP_STR(GCC warning text)) +#define CPP_NOTICE(text) _Pragma(CPP_STR(message text)) + +#else +#define CPP_WARN(text) +#endif + +#endif /* _FRR_COMPILER_H */ diff --git a/lib/memory.h b/lib/memory.h index 132d4abd30..6de370514a 100644 --- a/lib/memory.h +++ b/lib/memory.h @@ -20,6 +20,7 @@ #include #include #include +#include "compiler.h" #define array_size(ar) (sizeof(ar) / sizeof(ar[0])) @@ -37,41 +38,6 @@ struct memgroup { const char *name; }; -#if defined(__clang__) -#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 5) -# define _RET_NONNULL , returns_nonnull -#endif -# define _CONSTRUCTOR(x) constructor(x) -#elif defined(__GNUC__) -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9) -# define _RET_NONNULL , returns_nonnull -#endif -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) -# define _CONSTRUCTOR(x) constructor(x) -# define _DESTRUCTOR(x) destructor(x) -# define _ALLOC_SIZE(x) alloc_size(x) -#endif -#endif - -#ifdef __sun -/* Solaris doesn't do constructor priorities due to linker restrictions */ -#undef _CONSTRUCTOR -#undef _DESTRUCTOR -#endif - -#ifndef _RET_NONNULL -# define _RET_NONNULL -#endif -#ifndef _CONSTRUCTOR -# define _CONSTRUCTOR(x) constructor -#endif -#ifndef _DESTRUCTOR -# define _DESTRUCTOR(x) destructor -#endif -#ifndef _ALLOC_SIZE -# define _ALLOC_SIZE(x) -#endif - /* macro usage: * * mydaemon.h diff --git a/lib/prefix.h b/lib/prefix.h index bc4abb492a..eab4ac2bb7 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -33,28 +33,13 @@ #endif #include "sockunion.h" #include "ipaddr.h" +#include "compiler.h" #ifndef ETH_ALEN #define ETH_ALEN 6 #endif /* for compatibility */ -#if defined(__ICC) -#define CPP_WARN_STR(X) #X -#define CPP_WARN(text) _Pragma(CPP_WARN_STR(message __FILE__ ": " text)) - -#elif (defined(__GNUC__) \ - && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \ - || (defined(__clang__) \ - && (__clang_major__ >= 4 \ - || (__clang_major__ == 3 && __clang_minor__ >= 5))) -#define CPP_WARN_STR(X) #X -#define CPP_WARN(text) _Pragma(CPP_WARN_STR(GCC warning text)) - -#else -#define CPP_WARN(text) -#endif - #ifdef ETHER_ADDR_LEN #undef ETHER_ADDR_LEN #endif diff --git a/lib/subdir.am b/lib/subdir.am index 8545184228..d6349ba22d 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -85,6 +85,7 @@ pkginclude_HEADERS += \ lib/command.h \ lib/command_graph.h \ lib/command_match.h \ + lib/compiler.h \ lib/csv.h \ lib/distribute.h \ lib/event_counter.h \ diff --git a/lib/vty.h b/lib/vty.h index dcb8da225d..9acd62af3c 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -25,6 +25,7 @@ #include "log.h" #include "sockunion.h" #include "qobj.h" +#include "compiler.h" #define VTY_BUFSIZ 4096 #define VTY_MAXHIST 20 @@ -182,23 +183,11 @@ struct vty_arg { /* Integrated configuration file. */ #define INTEGRATE_DEFAULT_CONFIG "frr.conf" -/* for compatibility */ -#if defined(__ICC) -#define CPP_WARN_STR(X) #X -#define CPP_WARN(text) _Pragma(CPP_WARN_STR(message __FILE__ ": " text)) - -#elif (defined(__GNUC__) \ - && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))) \ - || (defined(__clang__) \ - && (__clang_major__ >= 4 \ - || (__clang_major__ == 3 && __clang_minor__ >= 5))) -#define CPP_WARN_STR(X) #X -#define CPP_WARN(text) _Pragma(CPP_WARN_STR(GCC warning text)) - -#else -#define CPP_WARN(text) +#if CONFDATE > 20180401 +CPP_NOTICE("It's probably time to remove VTY_NEWLINE compatibility foo.") #endif +/* for compatibility */ #define VNL "\n" CPP_WARN("VNL has been replaced with \\n.") #define VTYNL "\n" CPP_WARN("VTYNL has been replaced with \\n.") #define VTY_NEWLINE "\n" CPP_WARN("VTY_NEWLINE has been replaced with \\n.")