#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"
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);
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;
pw->data = *data;
if (pw->enabled)
- zebra_pw_update(pw);
+ zebra_register_rnh_pseudowire(pw->vrf_id, pw);
else
zebra_pw_uninstall(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
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;
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);
}
}
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);
}
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);
}
}
}
+/* 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.
*/
}
}
+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
/* 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);
}
}
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");
}