From 8cbeaaa2286b856ec66bc353c43cad882262fff9 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 30 Jun 2017 12:26:04 -0300 Subject: [PATCH] zebra: add nexthop tracking for pseudowires If the remote end of a pseudowire becomes unreachable (no route or an unlabeled route), then it must be uninstalled. In the same way, when the remote end becomes reachable, the pseudowire must be installed. Signed-off-by: Renato Westphal --- zebra/zebra_pw.c | 9 +++++- zebra/zebra_pw.h | 1 + zebra/zebra_rnh.c | 81 +++++++++++++++++++++++++++++++++++++++++++++-- zebra/zebra_rnh.h | 3 ++ 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index b8ce1826d3..bb8682b52a 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -27,6 +27,7 @@ #include "zebra/debug.h" #include "zebra/rib.h" #include "zebra/zserv.h" +#include "zebra/zebra_rnh.h" #include "zebra/zebra_vrf.h" #include "zebra/zebra_pw.h" @@ -78,6 +79,9 @@ void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw) zlog_debug("%u: deleting pseudowire %s protocol %s", pw->vrf_id, pw->ifname, zebra_route_string(pw->protocol)); + /* remove nexthop tracking */ + zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); + /* uninstall */ if (pw->status == PW_STATUS_UP) hook_call(pw_uninstall, pw); @@ -94,6 +98,8 @@ void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af, uint32_t remote_label, uint8_t flags, union pw_protocol_fields *data) { + zebra_deregister_rnh_pseudowire(pw->vrf_id, pw); + pw->ifindex = ifindex; pw->type = type; pw->af = af; @@ -104,7 +110,7 @@ void zebra_pw_change(struct zebra_pw *pw, ifindex_t ifindex, int type, int af, pw->data = *data; if (pw->enabled) - zebra_pw_update(pw); + zebra_register_rnh_pseudowire(pw->vrf_id, pw); else zebra_pw_uninstall(pw); } @@ -120,6 +126,7 @@ void zebra_pw_update(struct zebra_pw *pw) { if (zebra_pw_check_reachability(pw) < 0) { zebra_pw_uninstall(pw); + /* wait for NHT and try again later */ } else { /* * Install or reinstall the pseudowire (e.g. to update diff --git a/zebra/zebra_pw.h b/zebra/zebra_pw.h index 9cd2b999ac..9cb6ab416f 100644 --- a/zebra/zebra_pw.h +++ b/zebra/zebra_pw.h @@ -43,6 +43,7 @@ struct zebra_pw { int status; uint8_t protocol; struct zserv *client; + struct rnh *rnh; struct thread *install_retry_timer; }; diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 5096e95395..2a1f69d7b8 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -131,6 +131,7 @@ zebra_add_rnh (struct prefix *p, vrf_id_t vrfid, rnh_type_t type) rnh->client_list = list_new(); rnh->vrf_id = vrfid; rnh->zebra_static_route_list = list_new(); + rnh->zebra_pseudowire_list = list_new(); route_lock_node (rn); rn->info = rnh; rnh->node = rn; @@ -168,6 +169,7 @@ zebra_free_rnh (struct rnh *rnh) rnh->flags |= ZEBRA_NHT_DELETED; list_free (rnh->client_list); list_free (rnh->zebra_static_route_list); + list_free (rnh->zebra_pseudowire_list); free_state (rnh->vrf_id, rnh->state, rnh->node); XFREE (MTYPE_RNH, rnh); } @@ -222,7 +224,8 @@ zebra_remove_rnh_client (struct rnh *rnh, struct zserv *client, rnh_type_t type) } listnode_delete(rnh->client_list, client); if (list_isempty(rnh->client_list) && - list_isempty(rnh->zebra_static_route_list)) + list_isempty(rnh->zebra_static_route_list) && + list_isempty(rnh->zebra_pseudowire_list)) zebra_delete_rnh(rnh, type); } @@ -252,7 +255,8 @@ zebra_deregister_rnh_static_nh(vrf_id_t vrf_id, struct prefix *nh, listnode_delete(rnh->zebra_static_route_list, static_rn); if (list_isempty(rnh->client_list) && - list_isempty(rnh->zebra_static_route_list)) + list_isempty(rnh->zebra_static_route_list) && + list_isempty(rnh->zebra_pseudowire_list)) zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); } @@ -301,6 +305,62 @@ zebra_deregister_rnh_static_nexthops (vrf_id_t vrf_id, struct nexthop *nexthop, } } +/* XXX move this utility function elsewhere? */ +static void +addr2hostprefix (int af, const union g_addr *addr, struct prefix *prefix) +{ + switch (af) + { + case AF_INET: + prefix->family = AF_INET; + prefix->prefixlen = IPV4_MAX_BITLEN; + prefix->u.prefix4 = addr->ipv4; + break; + case AF_INET6: + prefix->family = AF_INET6; + prefix->prefixlen = IPV6_MAX_BITLEN; + prefix->u.prefix6 = addr->ipv6; + break; + default: + zlog_warn ("%s: unknown address family %d", __func__, af); + break; + } +} + +void +zebra_register_rnh_pseudowire (vrf_id_t vrf_id, struct zebra_pw *pw) +{ + struct prefix nh; + struct rnh *rnh; + + addr2hostprefix (pw->af, &pw->nexthop, &nh); + rnh = zebra_add_rnh (&nh, vrf_id, RNH_NEXTHOP_TYPE); + if (rnh && !listnode_lookup (rnh->zebra_pseudowire_list, pw)) + { + listnode_add (rnh->zebra_pseudowire_list, pw); + pw->rnh = rnh; + zebra_evaluate_rnh (vrf_id, pw->af, 1, RNH_NEXTHOP_TYPE, &nh); + } +} + +void +zebra_deregister_rnh_pseudowire (vrf_id_t vrf_id, struct zebra_pw *pw) +{ + struct rnh *rnh; + + rnh =pw->rnh; + if (!rnh) + return; + + listnode_delete (rnh->zebra_pseudowire_list, pw); + pw->rnh = NULL; + + if (list_isempty (rnh->client_list) && + list_isempty (rnh->zebra_static_route_list) && + list_isempty (rnh->zebra_pseudowire_list)) + zebra_delete_rnh (rnh, RNH_NEXTHOP_TYPE); +} + /* Apply the NHT route-map for a client to the route (and nexthops) * resolving a NH. */ @@ -611,6 +671,16 @@ zebra_rnh_process_static_routes (vrf_id_t vrfid, int family, } } +static void +zebra_rnh_process_pseudowires (vrf_id_t vrfid, struct rnh *rnh) +{ + struct zebra_pw *pw; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO (rnh->zebra_pseudowire_list, node, pw)) + zebra_pw_update (pw); +} + /* * See if a tracked nexthop entry has undergone any change, and if so, * take appropriate action; this involves notifying any clients and/or @@ -655,6 +725,9 @@ zebra_rnh_eval_nexthop_entry (vrf_id_t vrfid, int family, int force, /* Process static routes attached to this nexthop */ zebra_rnh_process_static_routes (vrfid, family, nrn, rnh, prn, rnh->state); + + /* Process pseudowires attached to this nexthop */ + zebra_rnh_process_pseudowires (vrfid, rnh); } } @@ -1030,6 +1103,8 @@ print_rnh (struct route_node *rn, struct vty *vty) vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto), client->sock, rnh->filtered[client->proto] ? "(filtered)" : ""); if (!list_isempty(rnh->zebra_static_route_list)) - vty_out(vty, " zebra%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : ""); + vty_out(vty, " zebra[static routes]%s", rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : ""); + if (!list_isempty(rnh->zebra_pseudowire_list)) + vty_out(vty, " zebra[pseudowires]"); vty_out(vty, "%s", VTY_NEWLINE); } diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 4394fde4f3..9da5138e93 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -42,6 +42,7 @@ struct rnh struct prefix resolved_route; struct list *client_list; struct list *zebra_static_route_list; /* static routes dependent on this NH */ + struct list *zebra_pseudowire_list; /* pseudowires dependent on this NH */ struct route_node *node; int filtered[ZEBRA_ROUTE_MAX]; /* if this has been filtered for client */ }; @@ -67,6 +68,8 @@ extern void zebra_register_rnh_static_nh(vrf_id_t, struct prefix *, struct route extern void zebra_deregister_rnh_static_nexthops (vrf_id_t, struct nexthop *nexthop, struct route_node *rn); extern void zebra_deregister_rnh_static_nh(vrf_id_t, struct prefix *, struct route_node *); +extern void zebra_register_rnh_pseudowire (vrf_id_t, struct zebra_pw *); +extern void zebra_deregister_rnh_pseudowire (vrf_id_t, struct zebra_pw *); extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, rnh_type_t type); extern void zebra_evaluate_rnh(vrf_id_t vrfid, int family, int force, rnh_type_t type, -- 2.39.5