From c05795b16b4bcb9de4663f3fc9664a623277d47a Mon Sep 17 00:00:00 2001 From: Sid Khot Date: Wed, 17 Aug 2016 19:36:54 -0700 Subject: [PATCH 1/4] Fix for CM-12450 Ensure quagga logs at startup are sent to syslog (until log configuration is processed) Ticket: CM-12450 Reviewed By: CCR-5112 Testing Done: Manual --- bgpd/bgp_main.c | 4 +++- isisd/isis_main.c | 4 +++- lib/command.c | 4 ++++ ospf6d/ospf6_main.c | 4 +++- ospfd/ospf_main.c | 4 +++- pimd/pim_main.c | 4 +++- ripd/rip_main.c | 4 +++- ripngd/ripng_main.c | 4 +++- watchquagga/watchquagga.c | 2 -- zebra/main.c | 4 +++- 10 files changed, 28 insertions(+), 10 deletions(-) diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index a5f066bff0..0d24c9c294 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -419,7 +419,9 @@ main (int argc, char **argv) zlog_default = openzlog (progname, ZLOG_BGP, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&bgpd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* BGP master init. */ bgp_master_init (); diff --git a/isisd/isis_main.c b/isisd/isis_main.c index f088bc1dec..234e516db5 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -245,7 +245,9 @@ main (int argc, char **argv, char **envp) zlog_default = openzlog (progname, ZLOG_ISIS, 0, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); zprivs_init (&isisd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME , zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* for reload */ _argc = argc; diff --git a/lib/command.c b/lib/command.c index 2e80eea9e3..10ab066bfb 100644 --- a/lib/command.c +++ b/lib/command.c @@ -3752,6 +3752,10 @@ set_log_file(struct vty *vty, const char *fname, int loglevel) host.logfile = XSTRDUP (MTYPE_HOST, fname); +#if defined(HAVE_CUMULUS) + if (zlog_default->maxlvl[ZLOG_DEST_SYSLOG] != ZLOG_DISABLED) + zlog_default->maxlvl[ZLOG_DEST_SYSLOG] = ZLOG_DISABLED; +#endif return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index c989a5a10a..a368b05304 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -321,7 +321,9 @@ main (int argc, char *argv[], char *envp[]) LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ospf6d_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* initialize zebra libraries */ signal_init (master, array_size(ospf6_signals), ospf6_signals); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 495ee2fd02..48f39d0099 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -288,7 +288,9 @@ main (int argc, char **argv) zlog_default = openzlog (progname, ZLOG_OSPF, instance, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ospfd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* OSPF master init. */ ospf_master_init (); diff --git a/pimd/pim_main.c b/pimd/pim_main.c index b28b3d6242..b65b925fad 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -138,7 +138,9 @@ int main(int argc, char** argv, char** envp) { zlog_default = openzlog(progname, ZLOG_PIM, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&pimd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* this while just reads the options */ while (1) { diff --git a/ripd/rip_main.c b/ripd/rip_main.c index f920e809e2..aa1c4ff4df 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -205,7 +205,9 @@ main (int argc, char **argv) zlog_default = openzlog (progname, ZLOG_RIP, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ripd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif /* Command line option parse. */ while (1) diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index a1c71c8562..f401a43156 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -204,7 +204,9 @@ main (int argc, char **argv) zlog_default = openzlog(progname, ZLOG_RIPNG, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&ripngd_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif while (1) { diff --git a/watchquagga/watchquagga.c b/watchquagga/watchquagga.c index 2a237efb6a..e882653e38 100644 --- a/watchquagga/watchquagga.c +++ b/watchquagga/watchquagga.c @@ -1337,8 +1337,6 @@ main(int argc, char **argv) zlog_default = openzlog(progname, ZLOG_NONE, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); - zlog_set_level(NULL, ZLOG_DEST_MONITOR, ZLOG_DISABLED); if (daemon_mode) { diff --git a/zebra/main.c b/zebra/main.c index ab907f83e8..8a9857a04d 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -245,7 +245,9 @@ main (int argc, char **argv) zlog_default = openzlog (progname, ZLOG_ZEBRA, 0, LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON); zprivs_init (&zserv_privs); - zlog_set_file (NULL, LOG_DEFAULT_FILENAME, zlog_default->default_lvl); +#if defined(HAVE_CUMULUS) + zlog_set_level (NULL, ZLOG_DEST_SYSLOG, zlog_default->default_lvl); +#endif while (1) { From a5b89524bccfeac78388402fab524fa1290cc871 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Thu, 18 Aug 2016 17:47:01 +0000 Subject: [PATCH 2/4] vtysh --markfile needs to ignore the "end" lines Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-12515 --- vtysh/vtysh.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index ad43f41fd9..3d3b8e6dce 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -504,6 +504,28 @@ vtysh_execute (const char *line) return vtysh_execute_func (line, 1); } +static char * +trim (char *s) +{ + size_t size; + char *end; + + size = strlen(s); + + if (!size) + return s; + + end = s + size - 1; + while (end >= s && isspace(*end)) + end--; + *(end + 1) = '\0'; + + while (*s && isspace(*s)) + s++; + + return s; +} + int vtysh_mark_file (const char *filename) { @@ -515,6 +537,8 @@ vtysh_mark_file (const char *filename) struct cmd_element *cmd; int saved_ret, prev_node; int lineno = 0; + char *vty_buf_copy = NULL; + char *vty_buf_trimmed = NULL; if (strncmp("-", filename, 1) == 0) confp = stdin; @@ -535,13 +559,16 @@ vtysh_mark_file (const char *filename) vtysh_execute_no_pager ("enable"); vtysh_execute_no_pager ("configure terminal"); + vty_buf_copy = XCALLOC (MTYPE_VTY, VTY_BUFSIZ); while (fgets (vty->buf, VTY_BUFSIZ, confp)) { lineno++; tried = 0; + strcpy(vty_buf_copy, vty->buf); + vty_buf_trimmed = trim(vty_buf_copy); - if (vty->buf[0] == '!' || vty->buf[1] == '#') + if (vty_buf_trimmed[0] == '!' || vty_buf_trimmed[0] == '#') { fprintf(stdout, "%s", vty->buf); continue; @@ -556,6 +583,12 @@ vtysh_mark_file (const char *filename) continue; } + /* Ignore the "end" lines, we will generate these where appropriate */ + if (strlen(vty_buf_trimmed) == 3 && strncmp("end", vty_buf_trimmed, 3) == 0) + { + continue; + } + prev_node = vty->node; saved_ret = ret = cmd_execute_command_strict (vline, vty, &cmd); @@ -606,21 +639,25 @@ vtysh_mark_file (const char *filename) fprintf (stderr,"line %d: Warning...: %s\n", lineno, vty->buf); fclose(confp); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); return CMD_WARNING; case CMD_ERR_AMBIGUOUS: fprintf (stderr,"line %d: %% Ambiguous command: %s\n", lineno, vty->buf); fclose(confp); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); return CMD_ERR_AMBIGUOUS; case CMD_ERR_NO_MATCH: fprintf (stderr,"line %d: %% Unknown command: %s\n", lineno, vty->buf); fclose(confp); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); return CMD_ERR_NO_MATCH; case CMD_ERR_INCOMPLETE: fprintf (stderr,"line %d: %% Command incomplete: %s\n", lineno, vty->buf); fclose(confp); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); return CMD_ERR_INCOMPLETE; case CMD_SUCCESS: fprintf(stdout, "%s", vty->buf); @@ -652,6 +689,7 @@ vtysh_mark_file (const char *filename) /* This is the end */ fprintf(stdout, "end\n"); vty_close(vty); + XFREE(MTYPE_VTY, vty_buf_copy); if (confp != stdin) fclose(confp); From 926ea62e0bfb598bfa2fb950e28861b2588f41ea Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Thu, 18 Aug 2016 18:03:46 +0000 Subject: [PATCH 3/4] quagga-reload.py should not restart quagga if bgp ASN changes Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Reviewed-by: Dinesh Dutt Ticket: CM-12521 --- tools/quagga-reload.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tools/quagga-reload.py b/tools/quagga-reload.py index f90b3e95fc..781086d9da 100755 --- a/tools/quagga-reload.py +++ b/tools/quagga-reload.py @@ -448,7 +448,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): for (ctx_keys, line) in lines_to_del: deleted = False - if ctx_keys[0].startswith('router bgp') and line.startswith('neighbor '): + if ctx_keys[0].startswith('router bgp') and line and line.startswith('neighbor '): """ BGP changed how it displays swpX peers that are part of peer-group. Older versions of quagga would display these on separate lines: @@ -608,7 +608,7 @@ def compare_context_objects(newconf, running): # Compare the two Config objects to find the lines that we need to add/del lines_to_add = [] lines_to_del = [] - restart_bgpd = False + delete_bgpd = False # Find contexts that are in newconf but not in running # Find contexts that are in running but not in newconf @@ -616,17 +616,21 @@ def compare_context_objects(newconf, running): if running_ctx_keys not in newconf.contexts: - # Check if bgp's local ASN has changed. If yes, just restart it # We check that the len is 1 here so that we only look at ('router bgp 10') # and not ('router bgp 10', 'address-family ipv4 unicast'). The - # latter could cause a false restart_bgpd positive if ipv4 unicast is in + # latter could cause a false delete_bgpd positive if ipv4 unicast is in # running but not in newconf. if "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) == 1: - restart_bgpd = True + delete_bgpd = True + lines_to_del.append((running_ctx_keys, None)) + + # If this is an address-family under 'router bgp' and we are already deleting the + # entire 'router bgp' context then ignore this sub-context + elif "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) > 1 and delete_bgpd: continue # Non-global context - if running_ctx_keys and not any("address-family" in key for key in running_ctx_keys): + elif running_ctx_keys and not any("address-family" in key for key in running_ctx_keys): lines_to_del.append((running_ctx_keys, None)) # Global context @@ -652,11 +656,6 @@ def compare_context_objects(newconf, running): for (newconf_ctx_keys, newconf_ctx) in newconf.contexts.iteritems(): if newconf_ctx_keys not in running.contexts: - - # If its "router bgp" and we're restarting bgp, skip doing - # anything specific for bgp - if "router bgp" in newconf_ctx_keys[0] and restart_bgpd: - continue lines_to_add.append((newconf_ctx_keys, None)) for line in newconf_ctx.lines: @@ -664,7 +663,7 @@ def compare_context_objects(newconf, running): (lines_to_add, lines_to_del) = ignore_delete_re_add_lines(lines_to_add, lines_to_del) - return (lines_to_add, lines_to_del, restart_bgpd) + return (lines_to_add, lines_to_del) if __name__ == '__main__': # Command line options @@ -684,6 +683,11 @@ if __name__ == '__main__': if args.test or args.stdout: logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)5s: %(message)s') + + # Color the errors and warnings in red + logging.addLevelName(logging.ERROR, "\033[91m %s\033[0m" % logging.getLevelName(logging.ERROR)) + logging.addLevelName(logging.WARNING, "\033[91m%s\033[0m" % logging.getLevelName(logging.WARNING)) + elif args.reload: if not os.path.isdir('/var/log/quagga/'): os.makedirs('/var/log/quagga/') @@ -742,7 +746,7 @@ if __name__ == '__main__': else: running.load_from_show_running() - (lines_to_add, lines_to_del, restart_bgp) = compare_context_objects(newconf, running) + (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) lines_to_configure = [] if lines_to_del: @@ -771,9 +775,6 @@ if __name__ == '__main__': lines_to_configure.append(cmd) print cmd - if restart_bgp: - print "BGP local AS changed, bgpd would restart" - elif args.reload: logger.debug('New Quagga Config\n%s', newconf.get_lines()) @@ -805,7 +806,7 @@ if __name__ == '__main__': running.load_from_show_running() logger.debug('Running Quagga Config (Pass #%d)\n%s', x, running.get_lines()) - (lines_to_add, lines_to_del, restart_bgp) = compare_context_objects(newconf, running) + (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) if lines_to_del: for (ctx_keys, line) in lines_to_del: @@ -881,6 +882,5 @@ if __name__ == '__main__': subprocess.call(['/usr/bin/vtysh', '-f', filename]) os.unlink(filename) - if restart_bgp: - subprocess.call(['sudo', 'systemctl', 'reset-failed', 'quagga']) - subprocess.call(['sudo', 'systemctl', '--no-block', 'restart', 'quagga']) + # Make these changes persistent + subprocess.call(['/usr/bin/vtysh', '-c', 'write']) From e5d1e72daaf5775e4bf67d812553d4fd8775791a Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 18 Aug 2016 15:02:49 -0700 Subject: [PATCH 4/4] bgpd: Upon interface up (update) only kick-off non-Established peers Any interface flags/parameter change (e.g., MTU, PROMISC flag change) is notified by zebra to clients as an "up" event. BGP literally treats this as the interface coming up and kicks all neighbors on that interface (i.e., directly connected peers). When doing so for IPv4 peers on the interface (numbered or unnumbered /30-/31) or IPv6 numbered peers, peers that may already be Established are also flapped; when doing so for IPv6 unnumbered peers (classic 'neighbor swpX interface' scenario with no configured IP address on interface), only peers not in Established state are processed. This patch fixes the code to ensure that in all cases, only non-Established peers are kicked. Signed-off-by: Vivek Venkatraman Reviewed-by: Don Slice Reviewed-by: Chris Cormier Ticket: CM-12526 Reviewed By: CCR-5119 Testing Done: Manual, bgp-min --- bgpd/bgp_nexthop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 80495065b0..a58b73e9f3 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -236,6 +236,7 @@ bgp_connected_add (struct bgp *bgp, struct connected *ifc) for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { if (peer->conf_if && (strcmp (peer->conf_if, ifc->ifp->name) == 0) && + peer->status != Established && !CHECK_FLAG(peer->flags, PEER_FLAG_IFPEER_V6ONLY)) { if (peer_active(peer))