summaryrefslogtreecommitdiff
path: root/zebra/zebra_rnh.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_rnh.c')
-rw-r--r--zebra/zebra_rnh.c70
1 files changed, 47 insertions, 23 deletions
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 0a531990dc..c3781888b1 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -36,6 +36,7 @@
#include "nexthop.h"
#include "vrf.h"
+#include "zebra/zebra_router.h"
#include "zebra/rib.h"
#include "zebra/rt.h"
#include "zebra/zserv.h"
@@ -177,11 +178,15 @@ void zebra_free_rnh(struct rnh *rnh)
XFREE(MTYPE_RNH, rnh);
}
-void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type)
+static void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type)
{
struct route_node *rn;
- if (!rnh || (rnh->flags & ZEBRA_NHT_DELETED) || !(rn = rnh->node))
+ if (!list_isempty(rnh->client_list)
+ || !list_isempty(rnh->zebra_pseudowire_list))
+ return;
+
+ if ((rnh->flags & ZEBRA_NHT_DELETED) || !(rn = rnh->node))
return;
if (IS_ZEBRA_DEBUG_NHT) {
@@ -212,10 +217,14 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
zebra_route_string(client->proto),
rnh_str(rnh, buf, sizeof(buf)), type);
}
- if (!listnode_lookup(rnh->client_list, client)) {
+ if (!listnode_lookup(rnh->client_list, client))
listnode_add(rnh->client_list, client);
- send_client(rnh, client, type, vrf_id);
- }
+
+ /*
+ * We always need to respond with known information,
+ * currently multiple daemons expect this behavior
+ */
+ send_client(rnh, client, type, vrf_id);
}
void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
@@ -228,9 +237,7 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
rnh_str(rnh, buf, sizeof(buf)), type);
}
listnode_delete(rnh->client_list, client);
- if (list_isempty(rnh->client_list)
- && list_isempty(rnh->zebra_pseudowire_list))
- zebra_delete_rnh(rnh, type);
+ zebra_delete_rnh(rnh, type);
}
/* XXX move this utility function elsewhere? */
@@ -286,9 +293,7 @@ void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
listnode_delete(rnh->zebra_pseudowire_list, pw);
pw->rnh = NULL;
- if (list_isempty(rnh->client_list)
- && list_isempty(rnh->zebra_pseudowire_list))
- zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
+ zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE);
}
/* Apply the NHT route-map for a client to the route (and nexthops)
@@ -469,12 +474,11 @@ static void zebra_rnh_process_pbr_tables(int family,
struct route_node *prn,
struct route_entry *re)
{
- struct zebra_ns_table *znst;
+ struct zebra_router_table *zrt;
struct route_entry *o_re;
struct route_node *o_rn;
struct listnode *node;
struct zserv *client;
- struct zebra_ns *zns;
afi_t afi = AFI_IP;
if (family == AF_INET6)
@@ -492,13 +496,12 @@ static void zebra_rnh_process_pbr_tables(int family,
if (!client)
return;
- zns = zebra_ns_lookup(NS_DEFAULT);
- RB_FOREACH (znst, zebra_ns_table_head, &zns->ns_tables) {
- if (afi != znst->afi)
+ RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
+ if (afi != zrt->afi)
continue;
- for (o_rn = route_top(znst->table);
- o_rn; o_rn = srcdest_route_next(o_rn)) {
+ for (o_rn = route_top(zrt->table); o_rn;
+ o_rn = srcdest_route_next(o_rn)) {
RNODE_FOREACH_RE (o_rn, o_re) {
if (o_re->type == ZEBRA_ROUTE_PBR)
break;
@@ -519,6 +522,17 @@ static void zebra_rnh_process_pbr_tables(int family,
}
/*
+ * Utility to determine whether a candidate nexthop is useable. We make this
+ * check in a couple of places, so this is a single home for the logic we
+ * use.
+ */
+static bool rnh_nexthop_valid(const struct nexthop *nh)
+{
+ return (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
+ && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE));
+}
+
+/*
* Determine appropriate route (route entry) resolving a tracked
* nexthop.
*/
@@ -530,6 +544,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, int family,
struct route_table *route_table;
struct route_node *rn;
struct route_entry *re;
+ struct nexthop *nexthop;
*prn = NULL;
@@ -562,12 +577,22 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, int family,
if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
continue;
+ /* Just being SELECTED isn't quite enough - must
+ * have an installed nexthop to be useful.
+ */
+ for (ALL_NEXTHOPS(re->ng, nexthop)) {
+ if (rnh_nexthop_valid(nexthop))
+ break;
+ }
+
+ if (nexthop == NULL)
+ continue;
+
if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) {
if ((re->type == ZEBRA_ROUTE_CONNECT)
|| (re->type == ZEBRA_ROUTE_STATIC))
break;
if (re->type == ZEBRA_ROUTE_NHRP) {
- struct nexthop *nexthop;
for (nexthop = re->ng.nexthop; nexthop;
nexthop = nexthop->next)
@@ -888,10 +913,9 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
num = 0;
nump = stream_get_endp(s);
stream_putc(s, 0);
- for (nh = re->ng.nexthop; nh; nh = nh->next)
- if ((CHECK_FLAG(nh->flags, NEXTHOP_FLAG_FIB)
- || CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
- && CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ACTIVE)) {
+ for (ALL_NEXTHOPS(re->ng, nh))
+ if (rnh_nexthop_valid(nh)) {
+ stream_putl(s, nh->vrf_id);
stream_putc(s, nh->type);
switch (nh->type) {
case NEXTHOP_TYPE_IPV4: