diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index 1117f6269d..a279674af2 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -99,6 +99,9 @@ struct attr_extra /* MP Nexthop length */ u_char mp_nexthop_len; + /* MP Nexthop preference */ + u_char mp_nexthop_prefer_global; + /* route tag */ u_short tag; diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 1f2f7f86ce..a5f066bff0 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -317,6 +317,7 @@ bgp_vrf_enable (vrf_id_t vrf_id, const char *name, void **info) { struct vrf *vrf; struct bgp *bgp; + vrf_id_t old_vrf_id; vrf = vrf_lookup (vrf_id); if (!vrf) // unexpected @@ -328,8 +329,13 @@ bgp_vrf_enable (vrf_id_t vrf_id, const char *name, void **info) bgp = bgp_lookup_by_name(name); if (bgp) { + old_vrf_id = bgp->vrf_id; /* We have instance configured, link to VRF and make it "up". */ bgp_vrf_link (bgp, vrf); + + /* Update any redistribute vrf bitmaps if the vrf_id changed */ + if (old_vrf_id != bgp->vrf_id) + bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); bgp_instance_up (bgp); } @@ -341,6 +347,7 @@ bgp_vrf_disable (vrf_id_t vrf_id, const char *name, void **info) { struct vrf *vrf; struct bgp *bgp; + vrf_id_t old_vrf_id; if (vrf_id == VRF_DEFAULT) return 0; @@ -355,8 +362,12 @@ bgp_vrf_disable (vrf_id_t vrf_id, const char *name, void **info) bgp = bgp_lookup_by_name(name); if (bgp) { + old_vrf_id = bgp->vrf_id; /* We have instance configured, unlink from VRF and make it "down". */ bgp_vrf_unlink (bgp, vrf); + /* Update any redistribute vrf bitmaps if the vrf_id changed */ + if (old_vrf_id != bgp->vrf_id) + bgp_update_redist_vrf_bitmaps(bgp, old_vrf_id); bgp_instance_down (bgp); } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index fc6db0863d..f47e2f6074 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -5873,7 +5873,7 @@ route_vty_out (struct vty *vty, struct prefix *p, vty_out (vty, "%-16s", inet_ntoa (attr->nexthop)); } } -#ifdef HAVE_IPV6 + /* IPv6 Next Hop */ else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { @@ -5901,8 +5901,9 @@ route_vty_out (struct vty *vty, struct prefix *p, json_object_string_add(json_nexthop_ll, "afi", "ipv6"); json_object_string_add(json_nexthop_ll, "scope", "link-local"); - if (IPV6_ADDR_CMP (&attr->extra->mp_nexthop_global, - &attr->extra->mp_nexthop_local) != 0) + if ((IPV6_ADDR_CMP (&attr->extra->mp_nexthop_global, + &attr->extra->mp_nexthop_local) != 0) && + !attr->extra->mp_nexthop_prefer_global) json_object_boolean_true_add(json_nexthop_ll, "used"); else json_object_boolean_true_add(json_nexthop_global, "used"); @@ -5912,7 +5913,10 @@ route_vty_out (struct vty *vty, struct prefix *p, } else { - if ((attr->extra->mp_nexthop_len == 32) || (binfo->peer->conf_if)) + /* Display LL if LL/Global both in table unless prefer-global is set */ + if (((attr->extra->mp_nexthop_len == 32) && + !attr->extra->mp_nexthop_prefer_global) || + (binfo->peer->conf_if)) { if (binfo->peer->conf_if) { @@ -5954,7 +5958,6 @@ route_vty_out (struct vty *vty, struct prefix *p, } } } -#endif /* HAVE_IPV6 */ /* MED/Metric */ if (attr->flag & ATTR_FLAG_BIT (BGP_ATTR_MULTI_EXIT_DISC)) @@ -6635,7 +6638,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (json_paths) json_object_string_add(json_nexthop_global, "afi", "ipv4"); } -#ifdef HAVE_IPV6 else { assert (attr->extra); @@ -6654,8 +6656,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, buf, INET6_ADDRSTRLEN)); } } -#endif /* HAVE_IPV6 */ - /* Display the IGP cost or 'inaccessible' */ if (! CHECK_FLAG (binfo->flags, BGP_INFO_VALID)) @@ -6761,7 +6761,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (!json_paths) vty_out (vty, "%s", VTY_NEWLINE); -#ifdef HAVE_IPV6 /* display the link-local nexthop */ if (attr->extra && attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { @@ -6775,13 +6774,19 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, json_object_string_add(json_nexthop_ll, "scope", "link-local"); json_object_boolean_true_add(json_nexthop_ll, "accessible"); - json_object_boolean_true_add(json_nexthop_ll, "used"); + + if (!attr->extra->mp_nexthop_prefer_global) + json_object_boolean_true_add(json_nexthop_ll, "used"); + else + json_object_boolean_true_add(json_nexthop_global, "used"); } else { - vty_out (vty, " (%s) (used)%s", - inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, + vty_out (vty, " (%s) %s%s", + inet_ntop (AF_INET6, &attr->extra->mp_nexthop_local, buf, INET6_ADDRSTRLEN), + attr->extra->mp_nexthop_prefer_global ? + "(prefer-global)" : "(used)", VTY_NEWLINE); } } @@ -6791,7 +6796,6 @@ route_vty_out_detail (struct vty *vty, struct bgp *bgp, struct prefix *p, if (json_paths) json_object_boolean_true_add(json_nexthop_global, "used"); } -#endif /* HAVE_IPV6 */ /* Line 3 display Origin, Med, Locpref, Weight, Tag, valid, Int/Ext/Local, Atomic, best */ if (json_paths) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 3018d074fc..2a4d416633 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -103,6 +103,7 @@ o Cisco route-map o Local extensions set ipv6 next-hop global: Done + set ipv6 next-hop prefer-global: Done set ipv6 next-hop local : Done set as-path exclude : Done @@ -2192,6 +2193,61 @@ struct route_map_rule_cmd route_set_ipv6_nexthop_global_cmd = route_set_ipv6_nexthop_global_free }; +/* Set next-hop preference value. */ +static route_map_result_t +route_set_ipv6_nexthop_prefer_global (void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + struct bgp_info *bgp_info; + struct peer *peer; + + if (type == RMAP_BGP) + { + /* Fetch routemap's rule information. */ + bgp_info = object; + peer = bgp_info->peer; + + if ((CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IN) || + CHECK_FLAG (peer->rmap_type, PEER_RMAP_TYPE_IMPORT)) + && peer->su_remote + && sockunion_family (peer->su_remote) == AF_INET6) + { + /* 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); + } + } + return RMAP_OKAY; +} + +static void * +route_set_ipv6_nexthop_prefer_global_compile (const char *arg) +{ + int *rins = NULL; + + rins = XCALLOC (MTYPE_ROUTE_MAP_COMPILED, sizeof (int)); + *rins = 1; + + return rins; +} + +/* Free route map's compiled `ip next-hop' value. */ +static void +route_set_ipv6_nexthop_prefer_global_free (void *rule) +{ + XFREE (MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for ip nexthop set preferred. */ +struct route_map_rule_cmd route_set_ipv6_nexthop_prefer_global_cmd = +{ + "ipv6 next-hop prefer-global", + route_set_ipv6_nexthop_prefer_global, + route_set_ipv6_nexthop_prefer_global_compile, + route_set_ipv6_nexthop_prefer_global_free +}; + /* `set ipv6 nexthop local IP_ADDRESS' */ /* Set nexthop to object. ojbect must be pointer to struct attr. */ @@ -4366,11 +4422,34 @@ DEFUN (no_set_ipv6_nexthop_peer, SET_STR IPV6_STR "IPv6 next-hop address\n" - ) + "Use peer address (for BGP only)\n") { return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop peer-address", NULL); } +DEFUN (set_ipv6_nexthop_prefer_global, + set_ipv6_nexthop_prefer_global_cmd, + "set ipv6 next-hop prefer-global", + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "Prefer global over link-local if both exist\n") +{ + return bgp_route_set_add (vty, vty->index, "ipv6 next-hop prefer-global", NULL);; +} + +DEFUN (no_set_ipv6_nexthop_prefer_global, + no_set_ipv6_nexthop_prefer_global_cmd, + "no set ipv6 next-hop prefer-global", + NO_STR + SET_STR + IPV6_STR + "IPv6 next-hop address\n" + "Prefer global over link-local if both exist\n") +{ + return bgp_route_set_delete (vty, vty->index, "ipv6 next-hop prefer-global", NULL); +} + DEFUN (set_ipv6_nexthop_global, set_ipv6_nexthop_global_cmd, "set ipv6 next-hop global X:X::X:X", @@ -4704,6 +4783,7 @@ bgp_route_map_init (void) route_map_install_match (&route_match_ipv6_next_hop_cmd); route_map_install_match (&route_match_ipv6_address_prefix_list_cmd); route_map_install_set (&route_set_ipv6_nexthop_global_cmd); + route_map_install_set (&route_set_ipv6_nexthop_prefer_global_cmd); route_map_install_set (&route_set_ipv6_nexthop_local_cmd); route_map_install_set (&route_set_ipv6_nexthop_peer_cmd); @@ -4716,6 +4796,8 @@ bgp_route_map_init (void) install_element (RMAP_NODE, &set_ipv6_nexthop_global_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_global_val_cmd); + install_element (RMAP_NODE, &set_ipv6_nexthop_prefer_global_cmd); + install_element (RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_cmd); install_element (RMAP_NODE, &set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_cmd); install_element (RMAP_NODE, &no_set_ipv6_nexthop_local_val_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 68f6cede8b..b4bac840e3 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1136,12 +1136,18 @@ bgp_info_to_ipv6_nexthop (struct bgp_info *info) /* If both global and link-local address present. */ if (info->attr->extra->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { - /* Workaround for Cisco's nexthop bug. */ - if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global) - && info->peer->su_remote->sa.sa_family == AF_INET6) - nexthop = &info->peer->su_remote->sin6.sin6_addr; + /* Check if route-map is set to prefer global over link-local */ + if (info->attr->extra->mp_nexthop_prefer_global) + nexthop = &info->attr->extra->mp_nexthop_global; else - nexthop = &info->attr->extra->mp_nexthop_local; + { + /* Workaround for Cisco's nexthop bug. */ + if (IN6_IS_ADDR_UNSPECIFIED (&info->attr->extra->mp_nexthop_global) + && info->peer->su_remote->sa.sa_family == AF_INET6) + nexthop = &info->peer->su_remote->sin6.sin6_addr; + else + nexthop = &info->attr->extra->mp_nexthop_local; + } } return nexthop; @@ -1959,6 +1965,24 @@ bgp_redistribute_unset (struct bgp *bgp, afi_t afi, int type, u_short instance) return CMD_SUCCESS; } +/* Update redistribute vrf bitmap during triggers like + restart networking or delete/add VRFs */ +void +bgp_update_redist_vrf_bitmaps (struct bgp *bgp, vrf_id_t old_vrf_id) +{ + int i; + afi_t afi; + + for (afi = AFI_IP; afi < AFI_MAX; afi++) + for (i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (vrf_bitmap_check (zclient->redist[afi][i], old_vrf_id)) + { + vrf_bitmap_unset (zclient->redist[afi][i], old_vrf_id); + vrf_bitmap_set (zclient->redist[afi][i], bgp->vrf_id); + } + return; +} + void bgp_zclient_reset (void) { diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 1603ed2614..991afdf7cc 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1504,4 +1504,5 @@ bgp_vrf_unlink (struct bgp *bgp, struct vrf *vrf) bgp->vrf_id = VRF_UNKNOWN; } +extern void bgp_update_redist_vrf_bitmaps (struct bgp*, vrf_id_t); #endif /* _QUAGGA_BGPD_H */ diff --git a/configure.ac b/configure.ac index 792cacd0c3..9cdf1903d3 100755 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ ## AC_PREREQ(2.60) -AC_INIT(Quagga, 0.99.24+cl3u2, [https://bugzilla.quagga.net]) +AC_INIT(Quagga, 0.99.24+cl3u3, [https://bugzilla.quagga.net]) CONFIG_ARGS="$*" AC_SUBST(CONFIG_ARGS) AC_CONFIG_SRCDIR(lib/zebra.h) diff --git a/debian/changelog b/debian/changelog index b83daec10a..3114db3fd1 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,12 @@ -quagga (0.99.23.1-1+cl3u2) Release; urgency=medium +quagga (0.99.24+cl3u3) RELEASED; urgency=medium + + * New Enabled: Merge up-to 0.99.24 code from upstream + * New Enabled: Additional CLI simplification + * New Enabled: Various Bug Fixes + + -- dev-support Thu, 04 Aug 2016 08:43:36 -0700 + +quagga (0.99.23.1-1+cl3u2) RELEASED; urgency=medium * New Enabled: VRF - See Documentation for how to use * New Enabled: Improved interface statistics diff --git a/lib/vty.h b/lib/vty.h index 81251e07bb..599882a382 100644 --- a/lib/vty.h +++ b/lib/vty.h @@ -220,7 +220,7 @@ do { \ #define VTY_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX) \ do { \ - unsigned long tmpl; \ + unsigned long long tmpl; \ VTY_GET_INTEGER_RANGE_HEART(NAME,tmpl,STR,MIN,MAX); \ (V) = tmpl; \ } while (0) diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index 861f9d3516..65d6e09b6d 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -2133,6 +2133,7 @@ config_write_debug (struct vty *vty) struct ospf *ospf; char str[16]; + memset (str, 0, 16); if ((ospf = ospf_lookup()) == NULL) return CMD_SUCCESS;