From 1f1d24a8f1f183d6d0a4598b854b459f5b5d7e5c Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 12 Sep 2017 08:14:50 -0400 Subject: [PATCH 1/3] zebra: Allow recursively resolved blackhole routes to be installed So the current code for a blackhole route assumed that you would never want a recursively resolved blackhole to work. Suppose you have this setup: 1) ip route 192.0.2.1/32 Null0 2) BGP installed with a route-map that rewrites the nexthop to 192.0.2.1. Zebra will end up with a recursive nexthop that resolves to the blackhole. The original rib install function assumed that we would never want the ability to recursively resolve a blackhole route. Instead just handle the blackhole as part of the nexthop_num = 1 case. Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 12b6185395..ef59f26f21 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1321,23 +1321,6 @@ static int netlink_route_multipath(int cmd, struct prefix *p, req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_type = RTN_UNICAST; - if (re->nexthop_num == 1 - && re->nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { - discard = 1; - - switch (re->nexthop->bh_type) { - case BLACKHOLE_ADMINPROHIB: - req.r.rtm_type = RTN_PROHIBIT; - break; - case BLACKHOLE_REJECT: - req.r.rtm_type = RTN_UNREACHABLE; - break; - default: - req.r.rtm_type = RTN_BLACKHOLE; - break; - } - } - addattr_l(&req.n, sizeof req, RTA_DST, &p->u.prefix, bytelen); if (src_p) addattr_l(&req.n, sizeof req, RTA_SRC, &src_p->u.prefix, @@ -1396,6 +1379,27 @@ static int netlink_route_multipath(int cmd, struct prefix *p, if (nexthop_num == 1 || multipath_num == 1) { nexthop_num = 0; for (ALL_NEXTHOPS(re->nexthop, nexthop)) { + /* + * So we want to cover 2 types of blackhole + * routes here: + * 1) A normal blackhole route( ala from a static + * install. + * 2) A recursively resolved blackhole route + */ + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { + switch (nexthop->bh_type) { + case BLACKHOLE_ADMINPROHIB: + req.r.rtm_type = RTN_PROHIBIT; + break; + case BLACKHOLE_REJECT: + req.r.rtm_type = RTN_UNREACHABLE; + break; + default: + req.r.rtm_type = RTN_BLACKHOLE; + break; + } + goto skip; + } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { if (!setsrc) { From 59693377a9443a2c0eec2c4607d2895db9c39100 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 12 Sep 2017 08:18:39 -0400 Subject: [PATCH 2/3] zebra: Allow recursive nexthop resolution to consider blackholes When we get a route install for a route that needs to be recursively resolved allow the blackhole to be considered and used if it is available. This allows bgp to install a route that will be blackholed. Signed-off-by: Donald Sharp --- zebra/zebra_rib.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c4c80b156b..d947db066f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -357,6 +357,10 @@ static void nexthop_set_resolved(afi_t afi, struct nexthop *newhop, resolved_hop->ifindex = newhop->ifindex; } + if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) { + resolved_hop->type = NEXTHOP_TYPE_BLACKHOLE; + resolved_hop->bh_type = nexthop->bh_type; + } resolved_hop->rparent = nexthop; nexthop_add(&nexthop->resolved, resolved_hop); } @@ -484,8 +488,6 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) { resolved = 0; for (ALL_NEXTHOPS(match->nexthop, newhop)) { - if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) - continue; if (!CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_FIB)) continue; @@ -509,8 +511,6 @@ static int nexthop_active(afi_t afi, struct route_entry *re, } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; for (ALL_NEXTHOPS(match->nexthop, newhop)) { - if (newhop->type == NEXTHOP_TYPE_BLACKHOLE) - continue; if (!CHECK_FLAG(newhop->flags, NEXTHOP_FLAG_FIB)) continue; From e22ac3eec4f1b2072d169fcc84a16e040e376f74 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 12 Sep 2017 08:24:27 -0400 Subject: [PATCH 3/3] bgpd: Fix bgp display of blackhole nexthops Allow BGP to tell the user that a particular nexthop is a blackhole nexthop. Signed-off-by: Donald Sharp --- bgpd/bgp_nexthop.c | 120 +++++++++++++++++++++------------------------ 1 file changed, 55 insertions(+), 65 deletions(-) diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 1200d74d6a..2b3984d757 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -430,12 +430,59 @@ int bgp_multiaccess_check_v4(struct in_addr nexthop, struct peer *peer) return (ret); } +static void bgp_show_nexthops_detail(struct vty *vty, + struct bgp *bgp, + struct bgp_nexthop_cache *bnc) +{ + char buf[PREFIX2STR_BUFFER]; + struct nexthop *nexthop; + + for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV6: + vty_out(vty, " gate %s\n", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, + buf, sizeof(buf))); + break; + case NEXTHOP_TYPE_IPV6_IFINDEX: + vty_out(vty, " gate %s, if %s\n", + inet_ntop(AF_INET6, &nexthop->gate.ipv6, + buf, sizeof(buf)), + ifindex2ifname(nexthop->ifindex, + bgp->vrf_id)); + break; + case NEXTHOP_TYPE_IPV4: + vty_out(vty, " gate %s\n", + inet_ntop(AF_INET, &nexthop->gate.ipv4, + buf, sizeof(buf))); + break; + case NEXTHOP_TYPE_IFINDEX: + vty_out(vty, " if %s\n", + ifindex2ifname(nexthop->ifindex, + bgp->vrf_id)); + break; + case NEXTHOP_TYPE_IPV4_IFINDEX: + vty_out(vty, " gate %s, if %s\n", + inet_ntop(AF_INET, &nexthop->gate.ipv4, + buf, sizeof(buf)), + ifindex2ifname(nexthop->ifindex, + bgp->vrf_id)); + break; + case NEXTHOP_TYPE_BLACKHOLE: + vty_out(vty, " blackhole\n"); + break; + default: + vty_out(vty, + " invalid nexthop type %u\n", + nexthop->type); + } +} + static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail) { struct bgp_node *rn; struct bgp_nexthop_cache *bnc; char buf[PREFIX2STR_BUFFER]; - struct nexthop *nexthop; time_t tbuf; afi_t afi; @@ -454,70 +501,13 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail) &rn->p.u.prefix, buf, sizeof(buf)), bnc->metric, bnc->path_count); - if (detail) - for (nexthop = bnc->nexthop; - nexthop; - nexthop = nexthop->next) - switch (nexthop->type) { - case NEXTHOP_TYPE_IPV6: - vty_out(vty, - " gate %s\n", - inet_ntop( - AF_INET6, - &nexthop->gate - .ipv6, - buf, - sizeof(buf))); - break; - case NEXTHOP_TYPE_IPV6_IFINDEX: - vty_out(vty, - " gate %s, if %s\n", - inet_ntop( - AF_INET6, - &nexthop->gate - .ipv6, - buf, - sizeof(buf)), - ifindex2ifname( - nexthop->ifindex, - bgp->vrf_id)); - break; - case NEXTHOP_TYPE_IPV4: - vty_out(vty, - " gate %s\n", - inet_ntop( - AF_INET, - &nexthop->gate - .ipv4, - buf, - sizeof(buf))); - break; - case NEXTHOP_TYPE_IFINDEX: - vty_out(vty, - " if %s\n", - ifindex2ifname( - nexthop->ifindex, - bgp->vrf_id)); - break; - case NEXTHOP_TYPE_IPV4_IFINDEX: - vty_out(vty, - " gate %s, if %s\n", - inet_ntop( - AF_INET, - &nexthop->gate - .ipv4, - buf, - sizeof(buf)), - ifindex2ifname( - nexthop->ifindex, - bgp->vrf_id)); - break; - default: - vty_out(vty, - " invalid nexthop type %u\n", - nexthop->type); - } - } else { + + if (!detail) + continue; + + bgp_show_nexthops_detail(vty, bgp, bnc); + + } else{ vty_out(vty, " %s invalid\n", inet_ntop(rn->p.family, &rn->p.u.prefix, buf,