]> git.puffer.fish Git - matthieu/frr.git/commitdiff
zebra: add nexthop tracking for pseudowires
authorRenato Westphal <renato@opensourcerouting.org>
Fri, 30 Jun 2017 15:26:04 +0000 (12:26 -0300)
committerDavid Lamparter <equinox@opensourcerouting.org>
Wed, 9 Aug 2017 10:35:15 +0000 (12:35 +0200)
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 <renato@opensourcerouting.org>
zebra/zebra_pw.c
zebra/zebra_pw.h
zebra/zebra_rnh.c
zebra/zebra_rnh.h

index 143224254b1725984873689b7742d4a4682afee9..35d8c84da14fd9f288695901ab4016f597a7bfe6 100644 (file)
@@ -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
index 62f45db5cd92ed16616a02fd3c6cf3afe739c6d7..382eaeaa4fe8ac810733c5f04e1fc070a2a82b53 100644 (file)
@@ -43,6 +43,7 @@ struct zebra_pw {
        int status;
        uint8_t protocol;
        struct zserv *client;
+       struct rnh *rnh;
        struct thread *install_retry_timer;
 };
 
index 8ab46f683c7ebe75cdcbaa7e2c052c7ec5d40e27..65698f30aedce99a504b371d9ff5afbf0d48de0d 100644 (file)
@@ -126,6 +126,7 @@ struct rnh *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;
@@ -161,6 +162,7 @@ void 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);
 }
@@ -210,7 +212,8 @@ void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
        }
        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);
 }
 
@@ -237,7 +240,8 @@ void 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);
 }
 
@@ -284,6 +288,58 @@ void zebra_deregister_rnh_static_nexthops(vrf_id_t vrf_id,
        }
 }
 
+/* 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.
  */
@@ -595,6 +651,15 @@ static void 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
@@ -636,6 +701,9 @@ static void 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);
        }
 }
 
@@ -1003,5 +1071,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
        if (!list_isempty(rnh->zebra_static_route_list))
                vty_out(vty, " zebra%s",
                        rnh->filtered[ZEBRA_ROUTE_STATIC] ? "(filtered)" : "");
+       if (!list_isempty(rnh->zebra_pseudowire_list))
+               vty_out(vty, " zebra[pseudowires]");
        vty_out(vty, "\n");
 }
index f8d89ec8ca89fe2780e44734033a09264b012dc0..7e183684da40917a8bdbcee660c77c0b94060485 100644 (file)
@@ -42,6 +42,8 @@ struct rnh {
        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 +69,8 @@ extern void zebra_deregister_rnh_static_nexthops(vrf_id_t,
                                                 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,