diff options
Diffstat (limited to 'zebra/zebra_rib.c')
-rw-r--r-- | zebra/zebra_rib.c | 294 |
1 files changed, 235 insertions, 59 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 12f3fa5a..a10ca84b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -67,6 +67,7 @@ static const struct {ZEBRA_ROUTE_OSPF6, 110}, {ZEBRA_ROUTE_ISIS, 115}, {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */} + /* no entry/default: 150 */ }; /* Vector for routing table. */ @@ -298,7 +299,6 @@ nexthop_blackhole_add (struct rib *rib) nexthop = XCALLOC (MTYPE_NEXTHOP, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_BLACKHOLE; - SET_FLAG (rib->flags, ZEBRA_FLAG_BLACKHOLE); nexthop_add (rib, nexthop); @@ -352,6 +352,17 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, break; } + if (IS_ZEBRA_DEBUG_RIB) { + char buf[INET6_ADDRSTRLEN]; + inet_ntop(rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); + zlog_debug("%s: %s/%d: nexthop match %p: %s type=%d sel=%d int=%d", + __func__, buf, rn->p.prefixlen, match, + match ? zebra_route_string(match->type) : "<?>", + match ? match->type : -1, + match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED) : -1, + match ? CHECK_FLAG(match->flags, ZEBRA_FLAG_INTERNAL) : -1); + } + /* If there is no selected route or matched route is EGP, go up tree. */ if (! match @@ -365,7 +376,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, } else { - if (match->type == ZEBRA_ROUTE_CONNECT) + if (match->type == ZEBRA_ROUTE_CONNECT + || (match->nexthop && match->nexthop->type == NEXTHOP_TYPE_IFINDEX)) { /* Directly point connected route. */ newhop = match->nexthop; @@ -374,7 +386,8 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, return 1; } - else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL)) + else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) || + match->type == ZEBRA_ROUTE_KERNEL) { for (newhop = match->nexthop; newhop; newhop = newhop->next) if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB) @@ -755,6 +768,43 @@ rib_match_ipv6 (struct in6_addr *addr) } #endif /* HAVE_IPV6 */ +static void nexthop_dump(struct nexthop *nexthop, + char *type_str_buf, + int type_str_buf_size, + char *addr_str_buf, + int addr_str_buf_size, + char *via_str_buf, + int via_str_buf_size) +{ + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + snprintf(type_str_buf, type_str_buf_size, "ipv4"); + snprintf(addr_str_buf, addr_str_buf_size, "%s", inet_ntoa(nexthop->gate.ipv4)); + snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifindex ? ifindex2ifname(nexthop->ifindex) : "<?>"); + break; + case NEXTHOP_TYPE_IFINDEX: + snprintf(type_str_buf, type_str_buf_size, "connected"); + snprintf(addr_str_buf, addr_str_buf_size, "<connected>"); + snprintf(via_str_buf, via_str_buf_size, "%s", ifindex2ifname(nexthop->ifindex)); + break; + case NEXTHOP_TYPE_IFNAME: + snprintf(type_str_buf, type_str_buf_size, "connected"); + snprintf(addr_str_buf, addr_str_buf_size, "<connected>"); + snprintf(via_str_buf, via_str_buf_size, "%s", nexthop->ifname); + break; + case NEXTHOP_TYPE_BLACKHOLE: + snprintf(type_str_buf, type_str_buf_size, "blackhole"); + snprintf(addr_str_buf, addr_str_buf_size, "<blackhole>"); + snprintf(via_str_buf, via_str_buf_size, "Null0"); + break; + default: + snprintf(type_str_buf, type_str_buf_size, "unknown"); + snprintf(addr_str_buf, addr_str_buf_size, "<unknown>"); + snprintf(via_str_buf, via_str_buf_size, "<?>"); + } +} + #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) @@ -808,10 +858,27 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: family = AFI_IP; - if (nexthop_active_ipv4 (rib, nexthop, set, rn)) - SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - else - UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + { + int nh_active = nexthop_active_ipv4 (rib, nexthop, set, rn); + if (IS_ZEBRA_DEBUG_RIB) { + char type_str_buf[100]; + char addr_str_buf[100]; + char via_str_buf[100]; + nexthop_dump(nexthop, + type_str_buf, sizeof(type_str_buf), + addr_str_buf, sizeof(addr_str_buf), + via_str_buf, sizeof(via_str_buf)); + zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d nexthop_active_ipv4=%d", + __func__, rib, nexthop, + nexthop->type, type_str_buf, + addr_str_buf, via_str_buf, nexthop->ifindex, + nh_active); + } + if (nh_active) + SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + else + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + } break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: @@ -891,8 +958,23 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); prev_index = nexthop->ifindex; - if ((new_active = nexthop_active_check (rn, rib, nexthop, set))) + new_active = nexthop_active_check (rn, rib, nexthop, set); + if (new_active) rib->nexthop_active_num++; + if (IS_ZEBRA_DEBUG_RIB) { + char type_str_buf[100]; + char addr_str_buf[100]; + char via_str_buf[100]; + nexthop_dump(nexthop, + type_str_buf, sizeof(type_str_buf), + addr_str_buf, sizeof(addr_str_buf), + via_str_buf, sizeof(via_str_buf)); + zlog_debug("%s: rib %p nexthop %p type=%d %s %s via %s ifindex=%d act=%d total_act=%d", + __func__, rib, nexthop, + nexthop->type, type_str_buf, + addr_str_buf, via_str_buf, nexthop->ifindex, + new_active, rib->nexthop_active_num); + } if (prev_active != new_active || prev_index != nexthop->ifindex) SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); @@ -992,6 +1074,15 @@ rib_process (struct route_node *rn) * may be passed to rib_unlink() in the middle of iteration. */ next = rib->next; + + if (IS_ZEBRA_DEBUG_RIB) { + zlog_debug("%s: %s/%d: scan rib %p: type=%d sel=%d rem=%d nh_act=%d dist=%d", + __func__, buf, rn->p.prefixlen, rib, rib->type, + CHECK_FLAG(rib->flags, ZEBRA_FLAG_SELECTED), + CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED), + nexthop_active_update(rn, rib, 0), + rib->distance); + } /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) @@ -1332,7 +1423,6 @@ rib_queue_init (struct zebra_t *zebra) zebra->ribq->spec.errorfunc = NULL; /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; - zebra->ribq->spec.hold = rib_process_hold_time; if (!(zebra->mq = meta_queue_new ())) zlog_err ("%s: could not initialise meta queue!", __func__); @@ -1511,7 +1601,10 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Set default distance by route type. */ if (distance == 0) { - distance = route_info[type].distance; + if ((unsigned)type >= sizeof(route_info) / sizeof(route_info[0])) + distance = 150; + else + distance = route_info[type].distance; /* iBGP distance is 200. */ if (type == ZEBRA_ROUTE_BGP && CHECK_FLAG (flags, ZEBRA_FLAG_IBGP)) @@ -1551,13 +1644,16 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, rib->type = type; rib->distance = distance; rib->flags = flags; + rib->zflags = flags >> 8; rib->metric = metric; rib->table = vrf_id; rib->nexthop_num = 0; rib->uptime = time (NULL); /* Nexthop settings. */ - if (gate) + if (RIB_ZF_BLACKHOLE_FLAGS (rib->zflags)) + nexthop_blackhole_add (rib); + else if (gate) { if (ifindex) nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); @@ -1830,6 +1926,7 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, struct nexthop *nexthop; char buf1[INET_ADDRSTRLEN]; char buf2[INET_ADDRSTRLEN]; + unsigned discard = RIB_ZF_BLACKHOLE_FLAGS (flags >> 8); /* Lookup table. */ table = vrf_table (AFI_IP, SAFI_UNICAST, 0); @@ -1839,12 +1936,19 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Apply mask. */ apply_mask_ipv4 (p); - if (IS_ZEBRA_DEBUG_KERNEL && gate) - zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", - inet_ntop (AF_INET, &p->prefix, buf1, INET_ADDRSTRLEN), - p->prefixlen, - inet_ntoa (*gate), - ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) + if (gate) + zlog_debug ("rib_delete_ipv4(): route delete %s/%d via %s ifindex %d", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + inet_ntoa (*gate), + ifindex); + else + zlog_debug ("rib_delete_ipv4(): route delete %s/%d ifname %s ifindex %d", + inet_ntop (AF_INET, &p->prefix, buf1, BUFSIZ), + p->prefixlen, + ifindex2ifname(ifindex), + ifindex); /* Lookup route node. */ rn = route_node_lookup (table, (struct prefix *) p); @@ -1878,11 +1982,37 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (rib->type != type) continue; - if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex) + + if (rib->zflags == discard) { - if (rib->refcnt) + same = rib; + break; + } + if (gate) + { + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || + IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)) + /* make sure ifindex matches if specified */ + if (!ifindex || ifindex == nexthop->ifindex) + break; + + if (nexthop) { + same = rib; + break; + } + } + else + { + nexthop = rib->nexthop; + if (nexthop && nexthop->ifindex != ifindex) + continue; + if (nexthop && + rib->type == ZEBRA_ROUTE_CONNECT && + nexthop->type == NEXTHOP_TYPE_IFINDEX && + rib->refcnt) + { /* Duplicated connected route. */ rib->refcnt--; route_unlock_node (rn); route_unlock_node (rn); @@ -1891,15 +2021,6 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, same = rib; break; } - /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || - ((nexthop = rib->nexthop) && - (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate) || - IPV4_ADDR_SAME (&nexthop->rgate.ipv4, gate)))) - { - same = rib; - break; - } } /* If same type of route can't be found and this message is from @@ -2011,7 +2132,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) } /* Save the flags of this static routes (reject, blackhole) */ - rib->flags = si->flags; + rib->zflags = si->zflags; /* Link this rib to the tree. */ rib_addnode (rn, rib); @@ -2099,7 +2220,7 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) /* Add static route into static route configuration. */ int static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, - u_char flags, u_char distance, u_int32_t vrf_id) + unsigned zflags, u_char distance, u_int32_t vrf_id) { u_char type = 0; struct route_node *rn; @@ -2118,12 +2239,14 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, rn = route_node_get (stable, p); /* Make flags. */ - if (gate) + if (RIB_ZF_BLACKHOLE_FLAGS (zflags)) + type = STATIC_IPV4_BLACKHOLE; + else if (gate) type = STATIC_IPV4_GATEWAY; else if (ifname) type = STATIC_IPV4_IFNAME; else - type = STATIC_IPV4_BLACKHOLE; + return -1; /* Do nothing if there is a same static route. */ for (si = rn->info; si; si = si->next) @@ -2151,7 +2274,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, si->type = type; si->distance = distance; - si->flags = flags; + si->zflags = zflags; if (gate) si->gate.ipv4 = *gate; @@ -2340,6 +2463,7 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, rib->type = type; rib->distance = distance; rib->flags = flags; + rib->zflags = flags >> 8; rib->metric = metric; rib->table = vrf_id; rib->nexthop_num = 0; @@ -2385,6 +2509,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, struct nexthop *nexthop; char buf1[INET6_ADDRSTRLEN]; char buf2[INET6_ADDRSTRLEN]; + unsigned discard = RIB_ZF_BLACKHOLE_FLAGS (flags >> 8); /* Apply mask. */ apply_mask_ipv6 (p); @@ -2426,11 +2551,37 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, if (rib->type != type) continue; - if (rib->type == ZEBRA_ROUTE_CONNECT && (nexthop = rib->nexthop) && - nexthop->type == NEXTHOP_TYPE_IFINDEX && nexthop->ifindex == ifindex) + + if (rib->zflags == discard) + { + same = rib; + break; + } + if (gate) { - if (rib->refcnt) + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + if (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) || + IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate)) + /* make sure ifindex matches if specified */ + if (!ifindex || ifindex == nexthop->ifindex) + break; + + if (nexthop) { + same = rib; + break; + } + } + else + { + nexthop = rib->nexthop; + if (nexthop && nexthop->ifindex != ifindex) + continue; + if (nexthop && + rib->type == ZEBRA_ROUTE_CONNECT && + nexthop->type == NEXTHOP_TYPE_IFINDEX && + rib->refcnt) + { /* Duplicated connected route. */ rib->refcnt--; route_unlock_node (rn); route_unlock_node (rn); @@ -2439,15 +2590,7 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, same = rib; break; } - /* Make sure that the route found has the same gateway. */ - else if (gate == NULL || - ((nexthop = rib->nexthop) && - (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate) || - IPV6_ADDR_SAME (&nexthop->rgate.ipv6, gate)))) - { - same = rib; - break; - } + } /* If same type of route can't be found and this message is from @@ -2533,6 +2676,9 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) case STATIC_IPV6_GATEWAY_IFNAME: nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); break; + case STATIC_IPV6_BLACKHOLE: + nexthop_blackhole_add (rib); + break; } rib_queue_add (&zebrad, rn); } @@ -2557,10 +2703,13 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) case STATIC_IPV6_GATEWAY_IFNAME: nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); break; + case STATIC_IPV6_BLACKHOLE: + nexthop_blackhole_add (rib); + break; } /* Save the flags of this static routes (reject, blackhole) */ - rib->flags = si->flags; + rib->zflags = si->zflags; /* Link this rib to the tree. */ rib_addnode (rn, rib); @@ -2583,6 +2732,9 @@ static_ipv6_nexthop_same (struct nexthop *nexthop, struct static_ipv6 *si) && IPV6_ADDR_SAME (&nexthop->gate.ipv6, &si->ipv6) && strcmp (nexthop->ifname, si->ifname) == 0) return 1; + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE + && si->type == STATIC_IPV6_BLACKHOLE) + return 1; return 0; } @@ -2651,7 +2803,7 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) /* Add static route into static route configuration. */ int static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, - const char *ifname, u_char flags, u_char distance, + const char *ifname, unsigned zflags, u_char distance, u_int32_t vrf_id) { struct route_node *rn; @@ -2694,7 +2846,7 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, si->type = type; si->distance = distance; - si->flags = flags; + si->zflags = zflags; switch (type) { @@ -2708,6 +2860,8 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, si->ipv6 = *gate; si->ifname = XSTRDUP (0, ifname); break; + case STATIC_IPV6_BLACKHOLE: + break; } /* Add new static route information to the tree with sort by @@ -2791,23 +2945,45 @@ static_delete_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, #endif /* HAVE_IPV6 */ /* RIB update function. */ -void -rib_update (void) +static void +rib_update_table (struct table *table) { struct route_node *rn; - struct route_table *table; - - table = vrf_table (AFI_IP, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rn->info) rib_queue_add (&zebrad, rn); +} - table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); - if (table) - for (rn = route_top (table); rn; rn = route_next (rn)) - if (rn->info) - rib_queue_add (&zebrad, rn); +void +rib_update (void) +{ + if (zebrad.update) + { + thread_cancel (zebrad.update); + zebrad.update = NULL; + } + + rib_update_table (vrf_table (AFI_IP, SAFI_UNICAST, 0)); + +#ifdef HAVE_IPV6 + rib_update_table (vrf_table (AFI_IP6, SAFI_UNICAST, 0)); +#endif +} + +static int +rib_update_thread (struct thread *self) +{ + rib_update (); + return 0; +} + +void +rib_update_background (void) +{ + if (!zebrad.update) + zebrad.update = thread_add_background (zebrad.master, rib_update_thread, + NULL, rib_process_hold_time); } |