summaryrefslogtreecommitdiff
path: root/zebra/zebra_rib.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_rib.c')
-rw-r--r--zebra/zebra_rib.c264
1 files changed, 176 insertions, 88 deletions
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 4dd8551a..e39976ee 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -202,20 +202,26 @@ nexthop_type_to_str (enum nexthop_types_t nh_type)
return desc[nh_type];
}
-/* Add nexthop to the end of the list. */
+/* Add nexthop to the end of a nexthop list. */
static void
-nexthop_add (struct rib *rib, struct nexthop *nexthop)
+_nexthop_add (struct nexthop **target, struct nexthop *nexthop)
{
struct nexthop *last;
- for (last = rib->nexthop; last && last->next; last = last->next)
+ for (last = *target; last && last->next; last = last->next)
;
if (last)
last->next = nexthop;
else
- rib->nexthop = nexthop;
+ *target = nexthop;
nexthop->prev = last;
+}
+/* Add nexthop to the end of a rib node's nexthop list */
+static void
+nexthop_add (struct rib *rib, struct nexthop *nexthop)
+{
+ _nexthop_add(&rib->nexthop, nexthop);
rib->nexthop_num++;
}
@@ -232,15 +238,32 @@ nexthop_delete (struct rib *rib, struct nexthop *nexthop)
rib->nexthop_num--;
}
+static void nexthops_free(struct nexthop *nexthop);
+
/* Free nexthop. */
static void
nexthop_free (struct nexthop *nexthop)
{
if (nexthop->ifname)
XFREE (0, nexthop->ifname);
+ if (nexthop->resolved)
+ nexthops_free(nexthop->resolved);
XFREE (MTYPE_NEXTHOP, nexthop);
}
+/* Frees a list of nexthops */
+static void
+nexthops_free (struct nexthop *nexthop)
+{
+ struct nexthop *nh, *next;
+
+ for (nh = nexthop; nh; nh = next)
+ {
+ next = nh->next;
+ nexthop_free (nh);
+ }
+}
+
struct nexthop *
nexthop_ifindex_add (struct rib *rib, unsigned int ifindex)
{
@@ -365,6 +388,24 @@ nexthop_blackhole_add (struct rib *rib)
return nexthop;
}
+/* This method checks whether a recursive nexthop has at
+ * least one resolved nexthop in the fib.
+ */
+int
+nexthop_has_fib_child(struct nexthop *nexthop)
+{
+ struct nexthop *nh;
+
+ if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ return 0;
+
+ for (nh = nexthop->resolved; nh; nh = nh->next)
+ if (CHECK_FLAG (nh->flags, NEXTHOP_FLAG_FIB))
+ return 1;
+
+ return 0;
+}
+
/* If force flag is not set, do not modify falgs at all for uninstall
the route from FIB. */
static int
@@ -375,13 +416,19 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
struct route_table *table;
struct route_node *rn;
struct rib *match;
+ int resolved;
struct nexthop *newhop;
+ struct nexthop *resolved_hop;
if (nexthop->type == NEXTHOP_TYPE_IPV4)
nexthop->ifindex = 0;
if (set)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ {
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ nexthops_free(nexthop->resolved);
+ nexthop->resolved = NULL;
+ }
/* Make lookup prefix. */
memset (&p, 0, sizeof (struct prefix_ipv4));
@@ -436,6 +483,7 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
}
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
{
+ resolved = 0;
for (newhop = match->nexthop; newhop; newhop = newhop->next)
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -443,18 +491,25 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
- nexthop->rtype = newhop->type;
+
+ resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
+ SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
+
+ resolved_hop->type = newhop->type;
if (newhop->type == NEXTHOP_TYPE_IPV4 ||
newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
- nexthop->rgate.ipv4 = newhop->gate.ipv4;
+ resolved_hop->gate.ipv4 = newhop->gate.ipv4;
+
if (newhop->type == NEXTHOP_TYPE_IFINDEX
|| newhop->type == NEXTHOP_TYPE_IFNAME
|| newhop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
- nexthop->rifindex = newhop->ifindex;
+ resolved_hop->ifindex = newhop->ifindex;
+
+ _nexthop_add(&nexthop->resolved, resolved_hop);
}
- return 1;
+ resolved = 1;
}
- return 0;
+ return resolved;
}
else
{
@@ -476,13 +531,19 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
struct route_table *table;
struct route_node *rn;
struct rib *match;
+ int resolved;
struct nexthop *newhop;
+ struct nexthop *resolved_hop;
if (nexthop->type == NEXTHOP_TYPE_IPV6)
nexthop->ifindex = 0;
if (set)
- UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ {
+ UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
+ nexthops_free(nexthop->resolved);
+ nexthop->resolved = NULL;
+ }
/* Make lookup prefix. */
memset (&p, 0, sizeof (struct prefix_ipv6));
@@ -538,6 +599,7 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
}
else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
{
+ resolved = 0;
for (newhop = match->nexthop; newhop; newhop = newhop->next)
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB)
&& ! CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -545,20 +607,27 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set,
if (set)
{
SET_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE);
- nexthop->rtype = newhop->type;
+
+ resolved_hop = XCALLOC(MTYPE_NEXTHOP, sizeof (struct nexthop));
+ SET_FLAG (resolved_hop->flags, NEXTHOP_FLAG_ACTIVE);
+
+ resolved_hop->type = newhop->type;
if (newhop->type == NEXTHOP_TYPE_IPV6
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
- nexthop->rgate.ipv6 = newhop->gate.ipv6;
+ resolved_hop->gate.ipv6 = newhop->gate.ipv6;
+
if (newhop->type == NEXTHOP_TYPE_IFINDEX
|| newhop->type == NEXTHOP_TYPE_IFNAME
|| newhop->type == NEXTHOP_TYPE_IPV6_IFINDEX
|| newhop->type == NEXTHOP_TYPE_IPV6_IFNAME)
- nexthop->rifindex = newhop->ifindex;
+ resolved_hop->ifindex = newhop->ifindex;
+
+ _nexthop_add(&nexthop->resolved, resolved_hop);
}
- return 1;
+ resolved = 1;
}
- return 0;
+ return resolved;
}
else
{
@@ -577,7 +646,8 @@ rib_match_ipv4 (struct in_addr addr)
struct route_table *table;
struct route_node *rn;
struct rib *match;
- struct nexthop *newhop;
+ struct nexthop *newhop, *tnewhop;
+ int recursing;
/* Lookup table. */
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
@@ -622,7 +692,7 @@ rib_match_ipv4 (struct in_addr addr)
return match;
else
{
- for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
return match;
return NULL;
@@ -638,7 +708,8 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p)
struct route_table *table;
struct route_node *rn;
struct rib *match;
- struct nexthop *nexthop;
+ struct nexthop *nexthop, *tnexthop;
+ int recursing;
/* Lookup table. */
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
@@ -668,7 +739,7 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p)
if (match->type == ZEBRA_ROUTE_CONNECT)
return match;
- for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
+ for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing))
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
return match;
@@ -693,7 +764,9 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
struct route_table *table;
struct route_node *rn;
struct rib *match;
- struct nexthop *nexthop;
+ struct nexthop *nexthop, *tnexthop;
+ int recursing;
+ int nexthops_active;
/* Lookup table. */
table = vrf_table (AFI_IP, SAFI_UNICAST, 0);
@@ -727,26 +800,25 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate)
return ZEBRA_RIB_FOUND_CONNECTED;
/* Ok, we have a cood candidate, let's check it's nexthop list... */
- for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next)
+ nexthops_active = 0;
+ for (ALL_NEXTHOPS_RO(match->nexthop, nexthop, tnexthop, recursing))
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
- {
- /* We are happy with either direct or recursive hexthop */
- if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate) ||
- nexthop->rgate.ipv4.s_addr == sockunion2ip (qgate))
- return ZEBRA_RIB_FOUND_EXACT;
- else
{
+ nexthops_active = 1;
+ if (nexthop->gate.ipv4.s_addr == sockunion2ip (qgate))
+ return ZEBRA_RIB_FOUND_EXACT;
if (IS_ZEBRA_DEBUG_RIB)
- {
- char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
- inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
- inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN);
- inet_ntop (AF_INET, &sockunion2ip (qgate), qgate_buf, INET_ADDRSTRLEN);
- zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf);
- }
- return ZEBRA_RIB_FOUND_NOGATE;
+ {
+ char gate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN];
+ inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN);
+ inet_ntop (AF_INET, &sockunion2ip(qgate), qgate_buf, INET_ADDRSTRLEN);
+ zlog_debug ("%s: qgate == %s, %s == %s", __func__,
+ qgate_buf, recursing ? "rgate" : "gate", gate_buf);
+ }
}
- }
+
+ if (nexthops_active)
+ return ZEBRA_RIB_FOUND_NOGATE;
return ZEBRA_RIB_NOTFOUND;
}
@@ -759,7 +831,8 @@ rib_match_ipv6 (struct in6_addr *addr)
struct route_table *table;
struct route_node *rn;
struct rib *match;
- struct nexthop *newhop;
+ struct nexthop *newhop, *tnewhop;
+ int recursing;
/* Lookup table. */
table = vrf_table (AFI_IP6, SAFI_UNICAST, 0);
@@ -804,7 +877,7 @@ rib_match_ipv6 (struct in6_addr *addr)
return match;
else
{
- for (newhop = match->nexthop; newhop; newhop = newhop->next)
+ for (ALL_NEXTHOPS_RO(match->nexthop, newhop, tnewhop, recursing))
if (CHECK_FLAG (newhop->flags, NEXTHOP_FLAG_FIB))
return match;
return NULL;
@@ -966,7 +1039,8 @@ static void
rib_install_kernel (struct route_node *rn, struct rib *rib)
{
int ret = 0;
- struct nexthop *nexthop;
+ struct nexthop *nexthop, *tnexthop;
+ int recursing;
/*
* Make sure we update the FPM any time we send new information to
@@ -988,7 +1062,7 @@ rib_install_kernel (struct route_node *rn, struct rib *rib)
/* This condition is never met, if we are using rt_socket.c */
if (ret < 0)
{
- for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
}
}
@@ -998,7 +1072,8 @@ static int
rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
{
int ret = 0;
- struct nexthop *nexthop;
+ struct nexthop *nexthop, *tnexthop;
+ int recursing;
/*
* Make sure we update the FPM any time we send new information to
@@ -1018,7 +1093,7 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib)
#endif /* HAVE_IPV6 */
}
- for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
+ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
return ret;
@@ -1114,7 +1189,8 @@ rib_process (struct route_node *rn)
struct rib *select = NULL;
struct rib *del = NULL;
int installed = 0;
- struct nexthop *nexthop = NULL;
+ struct nexthop *nexthop = NULL, *tnexthop;
+ int recursing;
char buf[INET6_ADDRSTRLEN];
assert (rn);
@@ -1237,7 +1313,7 @@ rib_process (struct route_node *rn)
This makes sure the routes are IN the kernel.
*/
- for (nexthop = select->nexthop; nexthop; nexthop = nexthop->next)
+ for (ALL_NEXTHOPS_RO(select->nexthop, nexthop, tnexthop, recursing))
if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB))
{
installed = 1;
@@ -1626,7 +1702,6 @@ rib_addnode (struct route_node *rn, struct rib *rib)
static void
rib_unlink (struct route_node *rn, struct rib *rib)
{
- struct nexthop *nexthop, *next;
char buf[INET6_ADDRSTRLEN];
rib_dest_t *dest;
@@ -1652,11 +1727,7 @@ rib_unlink (struct route_node *rn, struct rib *rib)
}
/* free RIB and nexthops */
- for (nexthop = rib->nexthop; nexthop; nexthop = next)
- {
- next = nexthop->next;
- nexthop_free (nexthop);
- }
+ nexthops_free(rib->nexthop);
XFREE (MTYPE_RIB, rib);
}
@@ -1786,11 +1857,12 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p,
void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib * rib)
{
- char straddr1[INET_ADDRSTRLEN], straddr2[INET_ADDRSTRLEN];
- struct nexthop *nexthop;
+ char straddr[INET_ADDRSTRLEN];
+ struct nexthop *nexthop, *tnexthop;
+ int recursing;
- inet_ntop (AF_INET, &p->prefix, straddr1, INET_ADDRSTRLEN);
- zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen);
+ inet_ntop (AF_INET, &p->prefix, straddr, INET_ADDRSTRLEN);
+ zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr, p->prefixlen);
zlog_debug
(
"%s: refcnt == %lu, uptime == %lu, type == %u, table == %d",
@@ -1817,21 +1889,20 @@ void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib
rib->nexthop_active_num,
rib->nexthop_fib_num
);
- for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
- {
- inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN);
- inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN);
- zlog_debug
- (
- "%s: NH %s (%s) with flags %s%s%s",
- func,
- straddr1,
- straddr2,
- (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""),
- (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""),
- (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "")
- );
- }
+ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
+ {
+ inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr, INET_ADDRSTRLEN);
+ zlog_debug
+ (
+ "%s: %s %s with flags %s%s%s",
+ func,
+ (recursing ? " NH" : "NH"),
+ straddr,
+ (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""),
+ (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""),
+ (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "")
+ );
+ }
zlog_debug ("%s: dump complete", func);
}
@@ -2018,7 +2089,8 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
struct rib *rib;
struct rib *fib = NULL;
struct rib *same = NULL;
- struct nexthop *nexthop;
+ struct nexthop *nexthop, *tnexthop;
+ int recursing;
char buf1[INET_ADDRSTRLEN];
char buf2[INET_ADDRSTRLEN];
@@ -2085,16 +2157,23 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p,
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))))
+ else
{
- same = rib;
- break;
- }
+ if (gate == NULL)
+ {
+ same = rib;
+ break;
+ }
+ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
+ if (IPV4_ADDR_SAME (&nexthop->gate.ipv4, gate))
+ {
+ same = rib;
+ break;
+ }
+ if (same)
+ break;
+ }
}
-
/* If same type of route can't be found and this message is from
kernel. */
if (! same)
@@ -2576,7 +2655,8 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
struct rib *rib;
struct rib *fib = NULL;
struct rib *same = NULL;
- struct nexthop *nexthop;
+ struct nexthop *nexthop, *tnexthop;
+ int recursing;
char buf1[INET6_ADDRSTRLEN];
char buf2[INET6_ADDRSTRLEN];
@@ -2636,14 +2716,22 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p,
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;
- }
+ else
+ {
+ if (gate == NULL)
+ {
+ same = rib;
+ break;
+ }
+ for (ALL_NEXTHOPS_RO(rib->nexthop, nexthop, tnexthop, recursing))
+ if (IPV6_ADDR_SAME (&nexthop->gate.ipv6, gate))
+ {
+ same = rib;
+ break;
+ }
+ if (same)
+ break;
+ }
}
/* If same type of route can't be found and this message is from