summaryrefslogtreecommitdiffstats
path: root/zebra/zebra_rib.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_rib.c')
-rw-r--r--zebra/zebra_rib.c294
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);
}