From 3aef92192569c33906c6a2623d0753c16c0e7a64 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 30 Aug 2016 08:59:08 -0400 Subject: [PATCH 01/11] bgpd: Add fix for multiple set commands with prefer-global In further testing, found that if there were multiple set commands in the route-map with one being prefer-global, the removal of the prefer-global was not recognized and reacted to correctly. This small addition includes that support Ticket: CM-11480 Signed-off-by: Don Slice Reviewed By: Donald Sharp Testing Done: Manual testing, bgp-min and bgp-smoke completed --- bgpd/bgp_attr.h | 2 ++ bgpd/bgp_routemap.c | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index a279674af2..9a8e2a75e2 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -148,6 +148,7 @@ struct attr #define BATTR_RMAP_NEXTHOP_UNCHANGED (1 << 3) #define BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED (1 << 4) #define BATTR_RMAP_IPV6_LL_NHOP_CHANGED (1 << 5) +#define BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED (1 << 6) /* Router Reflector related structure. */ struct cluster_list @@ -277,6 +278,7 @@ bgp_rmap_nhop_changed(u_int32_t out_rmap_flags, u_int32_t in_rmap_flags) CHECK_FLAG(out_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED) || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV4_NHOP_CHANGED) || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED) || + CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED) || CHECK_FLAG(out_rmap_flags, BATTR_RMAP_IPV6_LL_NHOP_CHANGED) || CHECK_FLAG(in_rmap_flags, BATTR_RMAP_NEXTHOP_UNCHANGED)) ? 1 : 0); } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 2a4d416633..e4fd730cf0 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2215,8 +2215,14 @@ route_set_ipv6_nexthop_prefer_global (void *rule, struct prefix *prefix, /* Set next hop preference to global */ bgp_info->attr->extra->mp_nexthop_prefer_global = TRUE; SET_FLAG(bgp_info->attr->rmap_change_flags, - BATTR_RMAP_IPV6_GLOBAL_NHOP_CHANGED); + BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); } + else + { + bgp_info->attr->extra->mp_nexthop_prefer_global = FALSE; + SET_FLAG(bgp_info->attr->rmap_change_flags, + BATTR_RMAP_IPV6_PREFER_GLOBAL_CHANGED); + } } return RMAP_OKAY; } From 6a98e6a916c18bb130430d1dcbd9f23a17ac97bd Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 31 Aug 2016 13:31:16 +0200 Subject: [PATCH 02/11] zebra: stack overrun in IPv6 RA receive code (CVE ##TBA##) The IPv6 RA code also receives ICMPv6 RS and RA messages. Unfortunately, by bad coding practice, the buffer size specified on receiving such messages mixed up 2 constants that in fact have different values. The code itself has: #define RTADV_MSG_SIZE 4096 While BUFSIZ is system-dependent, in my case (x86_64 glibc): /usr/include/_G_config.h:#define _G_BUFSIZ 8192 /usr/include/libio.h:#define _IO_BUFSIZ _G_BUFSIZ /usr/include/stdio.h:# define BUFSIZ _IO_BUFSIZ As the latter is passed to the kernel on recvmsg(), it's possible to overwrite 4kB of stack -- with ICMPv6 packets that can be globally sent to any of the system's addresses (using fragmentation to get to 8k). (The socket has filters installed limiting this to RS and RA packets, but does not have a filter for source address or TTL.) Issue discovered by trying to test other stuff, which randomly caused the stack to be smaller than 8kB in that code location, which then causes the kernel to report EFAULT (Bad address). Ticket: CM-12687 Signed-off-by: David Lamparter Reviewed-by: Donald Sharp --- zebra/rtadv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra/rtadv.c b/zebra/rtadv.c index f3f1cee14b..93f0155fdb 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -619,7 +619,7 @@ rtadv_read (struct thread *thread) /* Register myself. */ rtadv_event (zns, RTADV_READ, sock); - len = rtadv_recv_packet (zns, sock, buf, BUFSIZ, &from, &ifindex, &hoplimit); + len = rtadv_recv_packet (zns, sock, buf, sizeof (buf), &from, &ifindex, &hoplimit); if (len < 0) { From 5abe0c9519f971a6ecfb7447217593d27f2cb5d7 Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 31 Aug 2016 12:58:46 +0000 Subject: [PATCH 03/11] quagga-reload.py should be importable Signed-off-by: Daniel Walton Reviewed-by: Don Slice Ticket: CM-12686 (cherry picked from commit a782e613dd44a4447e4a9ef08cfe014e09da2b2f) --- tools/quagga-reload.py | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/tools/quagga-reload.py b/tools/quagga-reload.py index 781086d9da..900ed55c43 100755 --- a/tools/quagga-reload.py +++ b/tools/quagga-reload.py @@ -23,6 +23,9 @@ from ipaddr import IPv6Address from pprint import pformat +log = logging.getLogger(__name__) + + class Context(object): """ @@ -80,12 +83,12 @@ class Config(object): The internal representation has been marked appropriately by passing it through vtysh with the -m parameter """ - logger.info('Loading Config object from file %s', filename) + log.info('Loading Config object from file %s', filename) try: file_output = subprocess.check_output(['/usr/bin/vtysh', '-m', '-f', filename]) except subprocess.CalledProcessError as e: - logger.error('vtysh marking of config file %s failed with error %s:', filename, str(e)) + log.error('vtysh marking of config file %s failed with error %s:', filename, str(e)) print "vtysh marking of file %s failed with error: %s" % (filename, str(e)) sys.exit(1) @@ -105,14 +108,14 @@ class Config(object): The internal representation has been marked appropriately by passing it through vtysh with the -m parameter """ - logger.info('Loading Config object from vtysh show running') + log.info('Loading Config object from vtysh show running') try: config_text = subprocess.check_output( "/usr/bin/vtysh -c 'show run' | /usr/bin/tail -n +4 | /usr/bin/vtysh -m -f -", shell=True) except subprocess.CalledProcessError as e: - logger.error('vtysh marking of running config failed with error %s:', str(e)) + log.error('vtysh marking of running config failed with error %s:', str(e)) print "vtysh marking of running config failed with error %s:" % (str(e)) sys.exit(1) @@ -259,13 +262,13 @@ end ctx_keys = [line, ] current_context_lines = [] - logger.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) + log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) self.save_contexts(ctx_keys, current_context_lines) new_ctx = True elif line == "end": self.save_contexts(ctx_keys, current_context_lines) - logger.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys) + log.debug('LINE %-50s: exiting old context, %-50s', line, ctx_keys) # Start a new context new_ctx = True @@ -281,7 +284,7 @@ end # Start a new context ctx_keys = copy.deepcopy(main_ctx_key) current_context_lines = [] - logger.debug('LINE %-50s: popping from subcontext to ctx%-50s', line, ctx_keys) + log.debug('LINE %-50s: popping from subcontext to ctx%-50s', line, ctx_keys) elif new_ctx is True: if not main_ctx_key: @@ -292,7 +295,7 @@ end current_context_lines = [] new_ctx = False - logger.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) + log.debug('LINE %-50s: entering new context, %-50s', line, ctx_keys) elif "address-family " in line: main_ctx_key = [] @@ -301,7 +304,7 @@ end self.save_contexts(ctx_keys, current_context_lines) current_context_lines = [] main_ctx_key = copy.deepcopy(ctx_keys) - logger.debug('LINE %-50s: entering sub-context, append to ctx_keys', line) + log.debug('LINE %-50s: entering sub-context, append to ctx_keys', line) if line == "address-family ipv6": ctx_keys.append("address-family ipv6 unicast") @@ -313,7 +316,7 @@ end else: # Continuing in an existing context, add non-commented lines to it current_context_lines.append(line) - logger.debug('LINE %-50s: append to current_context_lines, %-50s', line, ctx_keys) + log.debug('LINE %-50s: append to current_context_lines, %-50s', line, ctx_keys) # Save the context of the last one self.save_contexts(ctx_keys, current_context_lines) @@ -699,7 +702,7 @@ if __name__ == '__main__': # argparse should prevent this from happening but just to be safe... else: raise Exception('Must specify --reload or --test') - logger = logging.getLogger(__name__) + log = logging.getLogger(__name__) # Verify the new config file is valid if not os.path.isfile(args.filename): @@ -728,9 +731,9 @@ if __name__ == '__main__': sys.exit(1) if args.debug: - logger.setLevel(logging.DEBUG) + log.setLevel(logging.DEBUG) - logger.info('Called via "%s"', str(args)) + log.info('Called via "%s"', str(args)) # Create a Config object from the config generated by newconf newconf = Config() @@ -777,7 +780,7 @@ if __name__ == '__main__': elif args.reload: - logger.debug('New Quagga Config\n%s', newconf.get_lines()) + log.debug('New Quagga Config\n%s', newconf.get_lines()) # This looks a little odd but we have to do this twice...here is why # If the user had this running bgp config: @@ -804,7 +807,7 @@ if __name__ == '__main__': for x in range(2): running = Config() running.load_from_show_running() - logger.debug('Running Quagga Config (Pass #%d)\n%s', x, running.get_lines()) + log.debug('Running Quagga Config (Pass #%d)\n%s', x, running.get_lines()) (lines_to_add, lines_to_del) = compare_context_objects(newconf, running) @@ -844,17 +847,17 @@ if __name__ == '__main__': # 'no ip ospf authentication message-digest 1.1.1.1' in # our example above # - Split that last entry by whitespace and drop the last word - logger.warning('Failed to execute %s', ' '.join(cmd)) + log.warning('Failed to execute %s', ' '.join(cmd)) last_arg = cmd[-1].split(' ') if len(last_arg) <= 2: - logger.error('"%s" we failed to remove this command', original_cmd) + log.error('"%s" we failed to remove this command', original_cmd) break new_last_arg = last_arg[0:-1] cmd[-1] = ' '.join(new_last_arg) else: - logger.info('Executed "%s"', ' '.join(cmd)) + log.info('Executed "%s"', ' '.join(cmd)) break if lines_to_add: @@ -874,7 +877,7 @@ if __name__ == '__main__': string.digits) for _ in range(6)) filename = "/var/run/quagga/reload-%s.txt" % random_string - logger.info("%s content\n%s" % (filename, pformat(lines_to_configure))) + log.info("%s content\n%s" % (filename, pformat(lines_to_configure))) with open(filename, 'w') as fh: for line in lines_to_configure: From c80266bea253a2339de2130f132e7f92c5774ecb Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Mon, 29 Aug 2016 19:59:53 +0000 Subject: [PATCH 04/11] json support for "show ip route" for "show ipv6 route" Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-12633 (cherry picked from commit 18a4ded2a72cc5613f54845dd29c1ee7d05bbf04) --- zebra/zebra_vty.c | 360 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 297 insertions(+), 63 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index e9090cbed2..6d846c3ecb 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -35,13 +35,18 @@ #include "zebra/zebra_rnh.h" #include "zebra/redistribute.h" #include "zebra/zebra_routemap.h" +#include "lib/json.h" extern int allow_delete; -static int do_show_ip_route(struct vty *vty, const char *vrf_name, safi_t safi); +static int do_show_ip_route(struct vty *vty, const char *vrf_name, + safi_t safi, u_char use_json); static void vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast); +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND 60*60*24*7 + /* General function for static route. */ static int zebra_static_ipv4 (struct vty *vty, safi_t safi, int add_cmd, @@ -278,7 +283,7 @@ DEFUN (show_ip_rpf, IP_STR "Display RPF information for multicast source\n") { - return do_show_ip_route(vty, VRF_DEFAULT_NAME, SAFI_MULTICAST); + return do_show_ip_route(vty, VRF_DEFAULT_NAME, SAFI_MULTICAST, 0); } DEFUN (show_ip_rpf_addr, @@ -1944,8 +1949,6 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) vty_out (vty, ", reject"); vty_out (vty, "%s", VTY_NEWLINE); -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 if (rib->type == ZEBRA_ROUTE_RIP || rib->type == ZEBRA_ROUTE_OSPF || rib->type == ZEBRA_ROUTE_ISIS @@ -2048,12 +2051,151 @@ vty_show_ip_route_detail (struct vty *vty, struct route_node *rn, int mcast) } static void -vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) +vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib, + json_object *json) { struct nexthop *nexthop, *tnexthop; int recursing; int len = 0; char buf[BUFSIZ]; + json_object *json_nexthops = NULL; + json_object *json_nexthop = NULL; + json_object *json_route = NULL; + + if (json) + { + json_route = json_object_new_object(); + json_nexthops = json_object_new_array(); + + json_object_string_add(json_route, "prefix", prefix2str (&rn->p, buf, sizeof buf)); + json_object_string_add(json_route, "protocol", zebra_route_string(rib->type)); + + if (rib->instance) + json_object_int_add(json_route, "instance", rib->instance); + + if (rib->vrf_id) + json_object_int_add(json_route, "vrfId", rib->vrf_id); + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + json_object_boolean_true_add(json_route, "selected"); + + if (rib->type != ZEBRA_ROUTE_CONNECT && rib->type != ZEBRA_ROUTE_KERNEL) + { + json_object_int_add(json_route, "distance", rib->distance); + json_object_int_add(json_route, "metric", rib->metric); + } + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE)) + json_object_boolean_true_add(json_route, "blackhole"); + + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_REJECT)) + json_object_boolean_true_add(json_route, "reject"); + + if (rib->type == ZEBRA_ROUTE_RIP + || rib->type == ZEBRA_ROUTE_OSPF + || rib->type == ZEBRA_ROUTE_ISIS + || rib->type == ZEBRA_ROUTE_TABLE + || rib->type == ZEBRA_ROUTE_BGP) + { + time_t uptime; + struct tm *tm; + + uptime = time (NULL); + uptime -= rib->uptime; + tm = gmtime (&uptime); + + if (uptime < ONE_DAY_SECOND) + sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); + else if (uptime < ONE_WEEK_SECOND) + sprintf(buf, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour, tm->tm_min); + else + sprintf(buf, "%02dw%dd%02dh", tm->tm_yday/7, tm->tm_yday - ((tm->tm_yday/7) * 7), tm->tm_hour); + + json_object_string_add(json_route, "uptime", buf); + } + + for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) + { + json_nexthop = json_object_new_object(); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + json_object_boolean_true_add(json_nexthop, "fib"); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + json_object_string_add(json_nexthop, "ip", inet_ntoa (nexthop->gate.ipv4)); + json_object_string_add(json_nexthop, "afi", "ipv4"); + + if (nexthop->ifindex) + { + json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); + } + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + json_object_string_add(json_nexthop, "ip", inet_ntop (AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + json_object_string_add(json_nexthop, "afi", "ipv6"); + + if (nexthop->ifindex) + { + json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); + } + break; + + case NEXTHOP_TYPE_IFINDEX: + json_object_boolean_true_add(json_nexthop, "directlyConnected"); + json_object_int_add(json_nexthop, "interfaceIndex", nexthop->ifindex); + json_object_string_add(json_nexthop, "interfaceName", ifindex2ifname_vrf (nexthop->ifindex, rib->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + json_object_boolean_true_add(json_nexthop, "blackhole"); + break; + default: + break; + } + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + json_object_boolean_true_add(json_nexthop, "active"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ONLINK)) + json_object_boolean_true_add(json_nexthop, "onLink"); + + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + json_object_boolean_true_add(json_nexthop, "recursive"); + + switch (nexthop->type) + { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + if (nexthop->src.ipv4.s_addr) + { + if (inet_ntop(AF_INET, &nexthop->src.ipv4, buf, sizeof buf)) + json_object_string_add(json_nexthop, "source", buf); + } + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + if (!IPV6_ADDR_SAME(&nexthop->src.ipv6, &in6addr_any)) + { + if (inet_ntop(AF_INET6, &nexthop->src.ipv6, buf, sizeof buf)) + json_object_string_add(json_nexthop, "source", buf); + } + break; + default: + break; + } + + json_object_array_add(json_nexthops, json_nexthop); + } + + json_object_object_add(json_route, "nexthops", json_nexthops); + json_object_array_add(json, json_route); + return; + } /* Nexthop information. */ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing)) @@ -2160,9 +2302,6 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) uptime -= rib->uptime; tm = gmtime (&uptime); -#define ONE_DAY_SECOND 60*60*24 -#define ONE_WEEK_SECOND 60*60*24*7 - if (uptime < ONE_DAY_SECOND) vty_out (vty, ", %02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -2180,62 +2319,112 @@ vty_show_ip_route (struct vty *vty, struct route_node *rn, struct rib *rib) DEFUN (show_ip_route, show_ip_route_cmd, - "show ip route", + "show ip route {json}", SHOW_STR IP_STR "IP routing table\n") { - return do_show_ip_route (vty, VRF_DEFAULT_NAME, SAFI_UNICAST); + return do_show_ip_route (vty, VRF_DEFAULT_NAME, SAFI_UNICAST, use_json(argc, argv)); } static int -do_show_ip_route(struct vty *vty, const char *vrf_name, safi_t safi) +do_show_ip_route (struct vty *vty, const char *vrf_name, safi_t safi, + u_char use_json) { struct route_table *table; struct route_node *rn; struct rib *rib; int first = 1; struct zebra_vrf *zvrf = NULL; + char buf[BUFSIZ]; + json_object *json = NULL; + json_object *json_prefix = NULL; if (!(zvrf = zebra_vrf_list_lookup_by_name (vrf_name))) { - vty_out (vty, "vrf %s not defined%s", vrf_name, VTY_NEWLINE); + if (use_json) + vty_out (vty, "{}%s", VTY_NEWLINE); + else + vty_out (vty, "vrf %s not defined%s", vrf_name, VTY_NEWLINE); return CMD_SUCCESS; } if (zvrf->vrf_id == VRF_UNKNOWN) { - vty_out (vty, "vrf %s inactive%s", vrf_name, VTY_NEWLINE); + if (use_json) + vty_out (vty, "{}%s", VTY_NEWLINE); + else + vty_out (vty, "vrf %s inactive%s", vrf_name, VTY_NEWLINE); return CMD_SUCCESS; } table = zebra_vrf_table (AFI_IP, safi, zvrf->vrf_id); if (! table) - return CMD_SUCCESS; + { + if (use_json) + vty_out (vty, "{}%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (use_json) + { + json = json_object_new_object(); + + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + { + RNODE_FOREACH_RIB (rn, rib) + { + if (!json_prefix) + json_prefix = json_object_new_array(); + vty_show_ip_route (vty, rn, rib, json_prefix); + } + + if (json_prefix) + { + prefix2str (&rn->p, buf, sizeof buf); + json_object_object_add(json, buf, json_prefix); + json_prefix = NULL; + } + } + + vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE); + json_object_free(json); + } + else + { + /* Show all IPv4 routes. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + { + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V4_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib, NULL); + } + } + } - /* Show all IPv4 routes. */ - for (rn = route_top (table); rn; rn = route_next (rn)) - RNODE_FOREACH_RIB (rn, rib) - { - if (first) - { - vty_out (vty, SHOW_ROUTE_V4_HEADER); - first = 0; - } - vty_show_ip_route (vty, rn, rib); - } return CMD_SUCCESS; } DEFUN (show_ip_route_vrf, show_ip_route_vrf_cmd, - "show ip route " VRF_CMD_STR, + "show ip route " VRF_CMD_STR " {json}", SHOW_STR IP_STR "IP routing table\n" VRF_CMD_HELP_STR) { - return do_show_ip_route (vty, argv[0], SAFI_UNICAST); + u_char uj = use_json(argc, argv); + + if (argc == 1 && uj) + return do_show_ip_route (vty, NULL, SAFI_UNICAST, uj); + else + return do_show_ip_route (vty, argv[0], SAFI_UNICAST, uj); } DEFUN (show_ip_nht, @@ -2430,7 +2619,7 @@ DEFUN (show_ip_route_tag, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -2490,7 +2679,7 @@ DEFUN (show_ip_route_prefix_longer, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -2542,7 +2731,7 @@ DEFUN (show_ip_route_supernets, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } } return CMD_SUCCESS; @@ -2600,7 +2789,7 @@ DEFUN (show_ip_route_protocol, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -2645,7 +2834,7 @@ DEFUN (show_ip_route_ospf_instance, vty_out (vty, SHOW_ROUTE_V4_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -3014,7 +3203,7 @@ DEFUN (show_ip_route_vrf_all, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -3068,7 +3257,7 @@ DEFUN (show_ip_route_vrf_all_tag, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -3124,7 +3313,7 @@ DEFUN (show_ip_route_vrf_all_prefix_longer, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -3177,7 +3366,7 @@ DEFUN (show_ip_route_vrf_all_supernets, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } } vrf_header = 1; @@ -3233,7 +3422,7 @@ DEFUN (show_ip_route_vrf_all_protocol, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -4544,7 +4733,7 @@ DEFUN (no_ipv6_route_ifname_flags_pref_tag_vrf, DEFUN (show_ipv6_route, show_ipv6_route_cmd, - "show ipv6 route", + "show ipv6 route {json}", SHOW_STR IP_STR "IPv6 routing table\n") @@ -4555,18 +4744,28 @@ DEFUN (show_ipv6_route, int first = 1; vrf_id_t vrf_id = VRF_DEFAULT; struct zebra_vrf *zvrf = NULL; + char buf[BUFSIZ]; + json_object *json = NULL; + json_object *json_prefix = NULL; + u_char uj = use_json(argc, argv); - if (argc > 0) + if (argc > 0 && argv[0] && strcmp(argv[0], "json") != 0) { if (!(zvrf = zebra_vrf_list_lookup_by_name (argv[0]))) { - vty_out (vty, "vrf %s not defined%s", argv[0], VTY_NEWLINE); + if (uj) + vty_out (vty, "{}%s", VTY_NEWLINE); + else + vty_out (vty, "vrf %s not defined%s", argv[0], VTY_NEWLINE); return CMD_SUCCESS; } if (zvrf->vrf_id == VRF_UNKNOWN) { - vty_out (vty, "vrf %s inactive%s", argv[0], VTY_NEWLINE); + if (uj) + vty_out (vty, "{}%s", VTY_NEWLINE); + else + vty_out (vty, "vrf %s inactive%s", argv[0], VTY_NEWLINE); return CMD_SUCCESS; } else @@ -4575,25 +4774,60 @@ DEFUN (show_ipv6_route, table = zebra_vrf_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! table) - return CMD_SUCCESS; + { + if (uj) + vty_out (vty, "{}%s", VTY_NEWLINE); + return CMD_SUCCESS; + } + + if (uj) + { + json = json_object_new_object(); + + /* Show all IPv6 route. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + { + RNODE_FOREACH_RIB (rn, rib) + { + if (!json_prefix) + json_prefix = json_object_new_array(); + vty_show_ip_route (vty, rn, rib, json_prefix); + } + + if (json_prefix) + { + prefix2str (&rn->p, buf, sizeof buf); + json_object_object_add(json, buf, json_prefix); + json_prefix = NULL; + } + } + + vty_out (vty, "%s%s", json_object_to_json_string(json), VTY_NEWLINE); + json_object_free(json); + } + else + { + /* Show all IPv6 route. */ + for (rn = route_top (table); rn; rn = route_next (rn)) + { + RNODE_FOREACH_RIB (rn, rib) + { + if (first) + { + vty_out (vty, SHOW_ROUTE_V6_HEADER); + first = 0; + } + vty_show_ip_route (vty, rn, rib, NULL); + } + } + } - /* Show all IPv6 route. */ - for (rn = route_top (table); rn; rn = route_next (rn)) - RNODE_FOREACH_RIB (rn, rib) - { - if (first) - { - vty_out (vty, SHOW_ROUTE_V6_HEADER); - first = 0; - } - vty_show_ip_route (vty, rn, rib); - } return CMD_SUCCESS; } ALIAS (show_ipv6_route, show_ipv6_route_vrf_cmd, - "show ipv6 route " VRF_CMD_STR, + "show ipv6 route " VRF_CMD_STR " {json}", SHOW_STR IP_STR "IPv6 routing table\n" @@ -4639,7 +4873,7 @@ DEFUN (show_ipv6_route_tag, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -4699,7 +4933,7 @@ DEFUN (show_ipv6_route_prefix_longer, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -4757,7 +4991,7 @@ DEFUN (show_ipv6_route_protocol, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -4983,7 +5217,7 @@ DEFUN (show_ipv6_mroute, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } return CMD_SUCCESS; } @@ -5033,7 +5267,7 @@ DEFUN (show_ipv6_route_vrf_all, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -5087,7 +5321,7 @@ DEFUN (show_ipv6_route_vrf_all_tag, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -5144,7 +5378,7 @@ DEFUN (show_ipv6_route_vrf_all_prefix_longer, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -5199,7 +5433,7 @@ DEFUN (show_ipv6_route_vrf_all_protocol, vty_out (vty, "%sVRF %s:%s", VTY_NEWLINE, zvrf->name, VTY_NEWLINE); vrf_header = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } vrf_header = 1; } @@ -5343,7 +5577,7 @@ DEFUN (show_ipv6_mroute_vrf_all, vty_out (vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route (vty, rn, rib); + vty_show_ip_route (vty, rn, rib, NULL); } } return CMD_SUCCESS; From 9374cd9b5b395ee97d0c376f83add1f8950f060b Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 31 Aug 2016 12:31:47 +0000 Subject: [PATCH 05/11] Quagga won't advertise 0.0.0.0/0 with network statement Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-12561 (cherry picked from commit 337299a936d9db8951825dcbf3acc4bd3b89ac32) --- zebra/zebra_rnh.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 03ae466997..216a9d1cee 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -353,18 +353,17 @@ zebra_rnh_resolve_entry (vrf_id_t vrfid, int family, rnh_type_t type, if (!rn) return NULL; - /* Do not resolve over default route unless allowed && - * match route to be exact if so specified + /* When resolving nexthops, do not resolve via the default route unless + * 'ip nht resolve-via-default' is configured. */ if ((type == RNH_NEXTHOP_TYPE) && (is_default_prefix (&rn->p) && !nh_resolve_via_default(rn->p.family))) rib = NULL; - else if ((type == RNH_IMPORT_CHECK_TYPE) && - ((is_default_prefix(&rn->p)) || - ((CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) && - !prefix_same(&nrn->p, &rn->p)))) - rib = NULL; + else if ((type == RNH_IMPORT_CHECK_TYPE) && + CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH) && + !prefix_same(&nrn->p, &rn->p)) + rib = NULL; else { /* Identify appropriate route entry. */ From f4b6d7e9bf3e2e5c575c85060d86d1403a08bd30 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 5 Sep 2016 10:35:19 -0700 Subject: [PATCH 06/11] bgpd: Fix route install upon non-best nexthop change After BGP path selection, even if the best route entry selected has not changed, ensure that the route is installed again in zebra if any non-best but multipath route entry has a nexthop resolution change. In the absence of this fix, if a non-best multipath route entry had a nexthop resolution change (such as being resolved over two first hops instead of one), the route would get reinstalled into zebra only in some situations (i.e., when the best route entry had its IGP change flag set). If the route does not get reinstalled by BGP, the corresponding route in the zebra RIB would not have all the first hops. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Daniel Walton Reviewed-by: Sid Khot Ticket: CM-12390 Reviewed By: CCR-5134 Testing Done: Manual, bgp-smoke (cherry picked from commit 3064bf43a7d8162dadada2934132f915a45d2bcb) --- bgpd/bgp_nht.c | 2 -- bgpd/bgp_route.c | 55 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 9d8d8f3b52..23c64731aa 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -681,8 +681,6 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) if (CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_METRIC_CHANGED) || CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED)) SET_FLAG(path->flags, BGP_INFO_IGP_CHANGED); - else - UNSET_FLAG (path->flags, BGP_INFO_IGP_CHANGED); bgp_process(bgp, rn, afi, SAFI_UNICAST); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f47e2f6074..26b5ef86d6 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1657,7 +1657,7 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, if (debug) zlog_debug("%s: %s is the bestpath, add to the multipath list", pfx_buf, path_buf); - bgp_mp_list_add (&mp_list, ri); + bgp_mp_list_add (&mp_list, ri); continue; } @@ -1749,6 +1749,50 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, return 0; } +/* + * Clear IGP changed flag for a route (all paths). This is called at + * the end of route processing. + */ +static void +bgp_zebra_clear_route_change_flags (struct bgp_node *rn) +{ + struct bgp_info *ri; + + for (ri = rn->info; ri; ri = ri->next) + { + if (BGP_INFO_HOLDDOWN (ri)) + continue; + UNSET_FLAG (ri->flags, BGP_INFO_IGP_CHANGED); + } +} + +/* + * Has the route changed from the RIB's perspective? This is invoked only + * if the route selection returns the same best route as earlier - to + * determine if we need to update zebra or not. + */ +static int +bgp_zebra_has_route_changed (struct bgp_node *rn, struct bgp_info *selected) +{ + struct bgp_info *mpinfo; + + /* There is a multipath change or best path has some nexthop change. */ + if (CHECK_FLAG (selected->flags, BGP_INFO_IGP_CHANGED) || + CHECK_FLAG (selected->flags, BGP_INFO_MULTIPATH_CHG)) + return 1; + + /* If this is multipath, check all selected paths for any nexthop change */ + for (mpinfo = bgp_info_mpath_first (selected); mpinfo; + mpinfo = bgp_info_mpath_next (mpinfo)) + { + if (CHECK_FLAG (mpinfo->flags, BGP_INFO_IGP_CHANGED)) + return 1; + } + + /* Nothing has changed from the RIB's perspective. */ + return 0; +} + struct bgp_process_queue { struct bgp *bgp; @@ -1799,11 +1843,11 @@ bgp_process_main (struct work_queue *wq, void *data) !CHECK_FLAG(old_select->flags, BGP_INFO_ATTR_CHANGED) && !bgp->addpath_tx_used[afi][safi]) { - if (CHECK_FLAG (old_select->flags, BGP_INFO_IGP_CHANGED) || - CHECK_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG)) + if (bgp_zebra_has_route_changed (rn, old_select)) bgp_zebra_announce (p, old_select, bgp, afi, safi); UNSET_FLAG (old_select->flags, BGP_INFO_MULTIPATH_CHG); + bgp_zebra_clear_route_change_flags (rn); UNSET_FLAG (rn->flags, BGP_NODE_PROCESS_SCHEDULED); return WQ_SUCCESS; } @@ -1856,7 +1900,10 @@ bgp_process_main (struct work_queue *wq, void *data) bgp_zebra_withdraw (p, old_select, safi); } } - + + /* Clear any route change flags. */ + bgp_zebra_clear_route_change_flags (rn); + /* Reap old select bgp_info, if it has been removed */ if (old_select && CHECK_FLAG (old_select->flags, BGP_INFO_REMOVED)) bgp_info_reap (rn, old_select); From a60b9a3718274a065e825ca881eb4be32d38221c Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 5 Sep 2016 10:49:16 -0700 Subject: [PATCH 07/11] bgpd: Fix route install upon multipath nexthop change In multipath selection, there can be a scenario where the set of route entries selected as multipath can be the same (i.e., from the same peers) but one or more of these may have a change to the BGP next hop. In this case, the route needs to be installed again in zebra even if the best route entry selected has not changed, otherwise the zebra RIB may have a different set of next hops (and first hops) than what the routing protocol selected. This patch handles this scenario by re-installing the route if any BGP attribute has changed for any of the multipaths. Not all BGP attributes are of relevance to the zebra RIB, but this approach follows existing logic used in the code (e.g., when BGP attributes for the best route entry has changed). Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Daniel Walton Reviewed-by: Sid Khot Ticket: CM-12390 Reviewed By: CCR-5135 Testing Done: Manual, bgp-smoke (cherry picked from commit e10720512ef744483ffed8a6ef3b529ec97e130d) --- bgpd/bgp_route.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 26b5ef86d6..da50da9b1a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1750,8 +1750,8 @@ subgroup_process_announce_selected (struct update_subgroup *subgrp, } /* - * Clear IGP changed flag for a route (all paths). This is called at - * the end of route processing. + * Clear IGP changed flag and attribute changed flag for a route (all paths). + * This is called at the end of route processing. */ static void bgp_zebra_clear_route_change_flags (struct bgp_node *rn) @@ -1763,6 +1763,7 @@ bgp_zebra_clear_route_change_flags (struct bgp_node *rn) if (BGP_INFO_HOLDDOWN (ri)) continue; UNSET_FLAG (ri->flags, BGP_INFO_IGP_CHANGED); + UNSET_FLAG (ri->flags, BGP_INFO_ATTR_CHANGED); } } @@ -1776,7 +1777,12 @@ bgp_zebra_has_route_changed (struct bgp_node *rn, struct bgp_info *selected) { struct bgp_info *mpinfo; - /* There is a multipath change or best path has some nexthop change. */ + /* If this is multipath, check all selected paths for any nexthop change or + * attribute change. Some attribute changes (e.g., community) aren't of + * relevance to the RIB, but we'll update zebra to ensure we handle the + * case of BGP nexthop change. This is the behavior when the best path has + * an attribute change anyway. + */ if (CHECK_FLAG (selected->flags, BGP_INFO_IGP_CHANGED) || CHECK_FLAG (selected->flags, BGP_INFO_MULTIPATH_CHG)) return 1; @@ -1785,7 +1791,8 @@ bgp_zebra_has_route_changed (struct bgp_node *rn, struct bgp_info *selected) for (mpinfo = bgp_info_mpath_first (selected); mpinfo; mpinfo = bgp_info_mpath_next (mpinfo)) { - if (CHECK_FLAG (mpinfo->flags, BGP_INFO_IGP_CHANGED)) + if (CHECK_FLAG (mpinfo->flags, BGP_INFO_IGP_CHANGED) + || CHECK_FLAG (mpinfo->flags, BGP_INFO_ATTR_CHANGED)) return 1; } From 72a5e63bad506506073e06d452badcf35930f812 Mon Sep 17 00:00:00 2001 From: vivek Date: Mon, 5 Sep 2016 10:53:06 -0700 Subject: [PATCH 08/11] bgpd: Enhance path selection logs Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Daniel Walton Ticket: CM-12390 Reviewed By: CCR-5136 Testing Done: Manual (cherry picked from commit a6086ad4084a9dfbf930ef48e2987772767063bd) --- bgpd/bgp_mpath.c | 38 ++++++++++++++++++++++++++++++++------ bgpd/bgp_route.c | 32 +++++++++++++++++++++++++------- 2 files changed, 57 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 8397177f8f..2395a66689 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -467,6 +467,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, bgp_info_mpath_dequeue (old_best); } + if (debug) + zlog_debug("%s: starting mpath update, newbest %s num candidates %d old-mpath-count %d", + pfx_buf, new_best ? new_best->peer->host : "NONE", + listcount (mp_list), old_mpath_count); + /* * We perform an ordered walk through both lists in parallel. * The reason for the ordered walk is that if there are paths @@ -480,6 +485,8 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, */ while (mp_node || cur_mpath) { + struct bgp_info *tmp_info; + /* * We can bail out of this loop if all existing paths on the * multipath list have been visited (for cleanup purposes) and @@ -490,6 +497,12 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, mp_next_node = mp_node ? listnextnode (mp_node) : NULL; next_mpath = cur_mpath ? bgp_info_mpath_next (cur_mpath) : NULL; + tmp_info = mp_node ? listgetdata (mp_node) : NULL; + + if (debug) + zlog_debug("%s: comparing candidate %s with existing mpath %s", + pfx_buf, tmp_info ? tmp_info->peer->host : "NONE", + cur_mpath ? cur_mpath->peer->host : "NONE"); /* * If equal, the path was a multipath and is still a multipath. @@ -505,6 +518,12 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, bgp_info_mpath_enqueue (prev_mpath, cur_mpath); prev_mpath = cur_mpath; mpath_count++; + if (debug) + { + bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf); + zlog_debug("%s: %s is still multipath, cur count %d", + pfx_buf, path_buf, mpath_count); + } } else { @@ -512,10 +531,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, if (debug) { bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf); - zlog_debug ("%s remove mpath nexthop %s %s", pfx_buf, + zlog_debug ("%s: remove mpath %s nexthop %s, cur count %d", + pfx_buf, path_buf, inet_ntop (AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), - path_buf); + mpath_count); } } mp_node = mp_next_node; @@ -538,10 +558,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, if (debug) { bgp_info_path_with_addpath_rx_str(cur_mpath, path_buf); - zlog_debug ("%s remove mpath nexthop %s %s", pfx_buf, + zlog_debug ("%s: remove mpath %s nexthop %s, cur count %d", + pfx_buf, path_buf, inet_ntop (AF_INET, &cur_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), - path_buf); + mpath_count); } cur_mpath = next_mpath; } @@ -574,10 +595,11 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, if (debug) { bgp_info_path_with_addpath_rx_str(new_mpath, path_buf); - zlog_debug ("%s add mpath nexthop %s %s", pfx_buf, + zlog_debug ("%s: add mpath %s nexthop %s, cur count %d", + pfx_buf, path_buf, inet_ntop (AF_INET, &new_mpath->attr->nexthop, nh_buf[0], sizeof (nh_buf[0])), - path_buf); + mpath_count); } } mp_node = mp_next_node; @@ -586,6 +608,10 @@ bgp_info_mpath_update (struct bgp_node *rn, struct bgp_info *new_best, if (new_best) { + if (debug) + zlog_debug("%s: New mpath count (incl newbest) %d mpath-change %s", + pfx_buf, mpath_count, mpath_changed ? "YES" : "NO"); + bgp_info_mpath_count_set (new_best, mpath_count-1); if (mpath_changed || (bgp_info_mpath_count (new_best) != old_mpath_count)) SET_FLAG (new_best->flags, BGP_INFO_MULTIPATH_CHG); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index da50da9b1a..f767fae1a9 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -376,7 +376,11 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, } if (debug) - bgp_info_path_with_addpath_rx_str (exist, exist_buf); + { + bgp_info_path_with_addpath_rx_str (exist, exist_buf); + zlog_debug("%s: Comparing %s flags 0x%x with %s flags 0x%x", + pfx_buf, new_buf, new->flags, exist_buf, exist->flags); + } newattr = new->attr; existattr = exist->attr; @@ -705,6 +709,15 @@ bgp_info_cmp (struct bgp *bgp, struct bgp_info *new, struct bgp_info *exist, * TODO: If unequal cost ibgp multipath is enabled we can * mark the paths as equal here instead of returning */ + if (debug) + { + if (ret == 1) + zlog_debug("%s: %s wins over %s after IGP metric comparison", + pfx_buf, new_buf, exist_buf); + else + zlog_debug("%s: %s loses to %s after IGP metric comparison", + pfx_buf, new_buf, exist_buf); + } return ret; } @@ -1638,14 +1651,19 @@ bgp_best_selection (struct bgp *bgp, struct bgp_node *rn, /* Now that we know which path is the bestpath see if any of the other paths * qualify as multipaths */ + if (debug) + { + if (new_select) + bgp_info_path_with_addpath_rx_str (new_select, path_buf); + else + sprintf (path_buf, "NONE"); + zlog_debug("%s: After path selection, newbest is %s oldbest was %s", + pfx_buf, path_buf, + old_select ? old_select->peer->host : "NONE"); + } + if (do_mpath && new_select) { - if (debug) - { - bgp_info_path_with_addpath_rx_str (new_select, path_buf); - zlog_debug("%s: %s is the bestpath, now find multipaths", pfx_buf, path_buf); - } - for (ri = rn->info; (ri != NULL) && (nextri = ri->next, 1); ri = nextri) { From 80c2442a9b959afce944d75c62565a9659bf84f9 Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 8 Sep 2016 09:38:53 -0700 Subject: [PATCH 09/11] lib, bgpd: Log next hops Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Daniel Walton Ticket: CM-12390 Reviewed By: CCR-5156 Testing Done: Manual --- bgpd/bgp_nht.c | 19 +++++++++++++++++-- lib/nexthop.c | 33 +++++++++++++++++++++++++++++++++ lib/nexthop.h | 4 ++++ 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index 23c64731aa..caf6fc2b41 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -370,8 +370,8 @@ bgp_parse_nexthop_update (int command, vrf_id_t vrf_id) { char buf[PREFIX2STR_BUFFER]; prefix2str(&p, buf, sizeof (buf)); - zlog_debug("parse nexthop update(%s): metric=%d, #nexthop=%d", buf, - metric, nexthop_num); + zlog_debug("%d: NH update for %s - metric %d (cur %d) #nhops %d (cur %d)", + vrf_id, buf, metric, bnc->metric, nexthop_num, bnc->nexthop_num); } if (metric != bnc->metric) @@ -420,6 +420,13 @@ bgp_parse_nexthop_update (int command, vrf_id_t vrf_id) break; } + if (BGP_DEBUG(nht, NHT)) + { + char buf[NEXTHOP_STRLEN]; + zlog_debug(" nhop via %s", + nexthop2str (nexthop, buf, sizeof (buf))); + } + if (nhlist_tail) { nhlist_tail->next = nexthop; @@ -642,6 +649,14 @@ evaluate_paths (struct bgp_nexthop_cache *bnc) int afi; struct peer *peer = (struct peer *)bnc->nht_info; + if (BGP_DEBUG(nht, NHT)) + { + char buf[PREFIX2STR_BUFFER]; + bnc_str(bnc, buf, PREFIX2STR_BUFFER); + zlog_debug("NH update for %s - flags 0x%x chgflags 0x%x - evaluate paths", + buf, bnc->flags, bnc->change_flags); + } + LIST_FOREACH(path, &(bnc->paths), nh_thread) { if (!(path->type == ZEBRA_ROUTE_BGP && diff --git a/lib/nexthop.c b/lib/nexthop.c index 5853884218..14486ea157 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -153,3 +153,36 @@ nexthops_free (struct nexthop *nexthop) nexthop_free (nh); } } + +const char * +nexthop2str (struct nexthop *nexthop, char *str, int size) +{ + switch (nexthop->type) + { + case NEXTHOP_TYPE_IFINDEX: + snprintf (str, size, "if %u", nexthop->ifindex); + break; + case NEXTHOP_TYPE_IPV4: + snprintf (str, size, "%s", inet_ntoa (nexthop->gate.ipv4)); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + snprintf (str, size, "%s if %u", + inet_ntoa (nexthop->gate.ipv4), nexthop->ifindex); + break; + case NEXTHOP_TYPE_IPV6: + snprintf (str, size, "%s", inet6_ntoa (nexthop->gate.ipv6)); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + snprintf (str, size, "%s if %u", + inet6_ntoa (nexthop->gate.ipv6), nexthop->ifindex); + break; + case NEXTHOP_TYPE_BLACKHOLE: + snprintf (str, size, "blackhole"); + break; + default: + snprintf (str, size, "unknown"); + break; + } + + return str; +} diff --git a/lib/nexthop.h b/lib/nexthop.h index eb9b27ea9e..725eb537af 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -26,6 +26,9 @@ #include "prefix.h" +/* Maximum next hop string length - gateway + ifindex */ +#define NEXTHOP_STRLEN (INET6_ADDRSTRLEN + 30) + union g_addr { struct in_addr ipv4; struct in6_addr ipv6; @@ -97,4 +100,5 @@ void nexthops_free (struct nexthop *nexthop); extern const char *nexthop_type_to_str (enum nexthop_types_t nh_type); extern int nexthop_same_no_recurse (struct nexthop *next1, struct nexthop *next2); +extern const char * nexthop2str (struct nexthop *nexthop, char *str, int size); #endif /*_LIB_NEXTHOP_H */ From 8c4f63817a1861adf8dba97849c4ef60b17432bc Mon Sep 17 00:00:00 2001 From: vivek Date: Thu, 8 Sep 2016 10:03:30 -0700 Subject: [PATCH 10/11] bgpd: Process directly connected IBGP peers upon interface down When we have a single-hop BFD session for any peering, it really means that the peering is directly connected (maybe over a L2 network), whether it is IBGP or EBGP. In such a case, upon link down, immediately process IBGP peers too (and bring them down), not just EBGP peers. This change eliminates some peculiar state transitions in specific IBGP topologies, thus getting rid of the problem of nexthops remaining inactive in the zebra RIB. Signed-off-by: Vivek Venkatraman Reviewed-by: Donald Sharp Reviewed-by: Daniel Walton Ticket: CM-12390 Reviewed By: CCR-5156 Testing Done: Manual, bgp-smoke --- bgpd/bgp_bfd.c | 2 +- bgpd/bgp_bfd.h | 3 +++ bgpd/bgp_zebra.c | 10 ++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index b8b0053695..aeac93e7b3 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -71,7 +71,7 @@ bgp_bfd_peer_group2peer_copy(struct peer *conf, struct peer *peer) /* * bgp_bfd_is_peer_multihop - returns whether BFD peer is multi-hop or single hop. */ -static int +int bgp_bfd_is_peer_multihop(struct peer *peer) { struct bfd_info *bfd_info; diff --git a/bgpd/bgp_bfd.h b/bgpd/bgp_bfd.h index 4e554af696..e872637e3e 100644 --- a/bgpd/bgp_bfd.h +++ b/bgpd/bgp_bfd.h @@ -42,4 +42,7 @@ bgp_bfd_peer_config_write(struct vty *vty, struct peer *peer, char *addr); extern void bgp_bfd_show_info(struct vty *vty, struct peer *peer, u_char use_json, json_object *json_neigh); +extern int +bgp_bfd_is_peer_multihop(struct peer *peer); + #endif /* _QUAGGA_BGP_BFD_H */ diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index b4bac840e3..6e17d778ab 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -44,6 +44,7 @@ Boston, MA 02111-1307, USA. */ #include "bgpd/bgp_mpath.h" #include "bgpd/bgp_nexthop.h" #include "bgpd/bgp_nht.h" +#include "bgpd/bgp_bfd.h" /* All information about zebra. */ struct zclient *zclient = NULL; @@ -358,7 +359,16 @@ bgp_interface_down (int command, struct zclient *zclient, zebra_size_t length, for (ALL_LIST_ELEMENTS (bgp->peer, node, nnode, peer)) { +#if defined(HAVE_CUMULUS) + /* Take down directly connected EBGP peers as well as 1-hop BFD + * tracked (directly connected) IBGP peers. + */ + if ((peer->ttl != 1) && (peer->gtsm_hops != 1) && + (!peer->bfd_info || bgp_bfd_is_peer_multihop(peer))) +#else + /* Take down directly connected EBGP peers */ if ((peer->ttl != 1) && (peer->gtsm_hops != 1)) +#endif continue; if (ifp == peer->nexthop.ifp) From dcaf0c593f8967cc2d9b3960abc525632d217c6c Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Thu, 8 Sep 2016 13:16:25 +0000 Subject: [PATCH 11/11] quagga-reload.py fails for "net add debug ospf6 lsa as-ext" Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-12773 - change "as-ext" to "as-external" - drop "grp-mbr" option, it does not have a handler - drop "type7" option, it does not have a handler (cherry picked from commit 51f2d198c24107a91a32764bf0930c2d50954574) --- ospf6d/ospf6_lsa.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index 3f008d3d9f..35e5a91544 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -818,7 +818,7 @@ ospf6_lsa_handler_name (struct ospf6_lsa_handler *h) DEFUN (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_cmd, - "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", + "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" @@ -862,7 +862,7 @@ DEFUN (debug_ospf6_lsa_type, ALIAS (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_detail_cmd, - "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown) (originate|examine|flooding)", + "debug ospf6 lsa (router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown) (originate|examine|flooding)", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" @@ -871,7 +871,7 @@ ALIAS (debug_ospf6_lsa_type, DEFUN (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_cmd, - "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix|unknown)", + "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown)", NO_STR DEBUG_STR OSPF6_STR @@ -915,7 +915,7 @@ DEFUN (no_debug_ospf6_lsa_type, ALIAS (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_detail_cmd, - "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-ext|grp-mbr|type7|link|intra-prefix) (originate|examine|flooding)", + "no debug ospf6 lsa (router|network|inter-prefix|inter-router|as-external|link|intra-prefix) (originate|examine|flooding)", NO_STR DEBUG_STR OSPF6_STR