mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-08 09:30:30 +00:00
Merge pull request #2897 from donaldsharp/zebra_rnh_fixup
zebra: When registering a nexthop, we do not always need to re-eval
This commit is contained in:
commit
955cb66380
@ -34,6 +34,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nexthop.h"
|
#include "nexthop.h"
|
||||||
#include "nexthop_group.h"
|
#include "nexthop_group.h"
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
#include "static_vrf.h"
|
#include "static_vrf.h"
|
||||||
#include "static_routes.h"
|
#include "static_routes.h"
|
||||||
@ -43,6 +44,7 @@
|
|||||||
|
|
||||||
/* Zebra structure to hold current status. */
|
/* Zebra structure to hold current status. */
|
||||||
struct zclient *zclient;
|
struct zclient *zclient;
|
||||||
|
static struct hash *static_nht_hash;
|
||||||
|
|
||||||
static struct interface *zebra_interface_if_lookup(struct stream *s)
|
static struct interface *zebra_interface_if_lookup(struct stream *s)
|
||||||
{
|
{
|
||||||
@ -176,10 +178,16 @@ static void zebra_connected(struct zclient *zclient)
|
|||||||
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
zclient_send_reg_requests(zclient, VRF_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct static_nht_data {
|
||||||
|
struct prefix *nh;
|
||||||
|
uint32_t refcount;
|
||||||
|
uint8_t nh_num;
|
||||||
|
};
|
||||||
|
|
||||||
static int static_zebra_nexthop_update(int command, struct zclient *zclient,
|
static int static_zebra_nexthop_update(int command, struct zclient *zclient,
|
||||||
zebra_size_t length, vrf_id_t vrf_id)
|
zebra_size_t length, vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
|
struct static_nht_data *nhtd, lookup;
|
||||||
struct zapi_route nhr;
|
struct zapi_route nhr;
|
||||||
afi_t afi = AFI_IP;
|
afi_t afi = AFI_IP;
|
||||||
|
|
||||||
@ -191,6 +199,14 @@ static int static_zebra_nexthop_update(int command, struct zclient *zclient,
|
|||||||
if (nhr.prefix.family == AF_INET6)
|
if (nhr.prefix.family == AF_INET6)
|
||||||
afi = AFI_IP6;
|
afi = AFI_IP6;
|
||||||
|
|
||||||
|
memset(&lookup, 0, sizeof(lookup));
|
||||||
|
lookup.nh = &nhr.prefix;
|
||||||
|
|
||||||
|
nhtd = hash_lookup(static_nht_hash, &lookup);
|
||||||
|
if (nhtd)
|
||||||
|
nhtd->nh_num = nhr.nexthop_num;
|
||||||
|
|
||||||
|
|
||||||
static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id);
|
static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, vrf_id);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -200,10 +216,50 @@ static void static_zebra_capabilities(struct zclient_capabilities *cap)
|
|||||||
mpls_enabled = cap->mpls_enabled;
|
mpls_enabled = cap->mpls_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int static_nht_hash_key(void *data)
|
||||||
|
{
|
||||||
|
struct static_nht_data *nhtd = data;
|
||||||
|
|
||||||
|
return prefix_hash_key(nhtd->nh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int static_nht_hash_cmp(const void *d1, const void *d2)
|
||||||
|
{
|
||||||
|
const struct static_nht_data *nhtd1 = d1;
|
||||||
|
const struct static_nht_data *nhtd2 = d2;
|
||||||
|
|
||||||
|
return prefix_same(nhtd1->nh, nhtd2->nh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *static_nht_hash_alloc(void *data)
|
||||||
|
{
|
||||||
|
struct static_nht_data *copy = data;
|
||||||
|
struct static_nht_data *new;
|
||||||
|
|
||||||
|
new = XMALLOC(MTYPE_TMP, sizeof(*new));
|
||||||
|
|
||||||
|
new->nh = prefix_new();
|
||||||
|
prefix_copy(new->nh, copy->nh);
|
||||||
|
new->refcount = 0;
|
||||||
|
new->nh_num = 0;
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void static_nht_hash_free(void *data)
|
||||||
|
{
|
||||||
|
struct static_nht_data *nhtd = data;
|
||||||
|
|
||||||
|
prefix_free(nhtd->nh);
|
||||||
|
XFREE(MTYPE_TMP, nhtd);
|
||||||
|
}
|
||||||
|
|
||||||
void static_zebra_nht_register(struct static_route *si, bool reg)
|
void static_zebra_nht_register(struct static_route *si, bool reg)
|
||||||
{
|
{
|
||||||
|
struct static_nht_data *nhtd, lookup;
|
||||||
uint32_t cmd;
|
uint32_t cmd;
|
||||||
struct prefix p;
|
struct prefix p;
|
||||||
|
afi_t afi = AFI_IP;
|
||||||
|
|
||||||
cmd = (reg) ?
|
cmd = (reg) ?
|
||||||
ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
|
ZEBRA_NEXTHOP_REGISTER : ZEBRA_NEXTHOP_UNREGISTER;
|
||||||
@ -224,20 +280,48 @@ void static_zebra_nht_register(struct static_route *si, bool reg)
|
|||||||
p.family = AF_INET;
|
p.family = AF_INET;
|
||||||
p.prefixlen = IPV4_MAX_BITLEN;
|
p.prefixlen = IPV4_MAX_BITLEN;
|
||||||
p.u.prefix4 = si->addr.ipv4;
|
p.u.prefix4 = si->addr.ipv4;
|
||||||
|
afi = AFI_IP;
|
||||||
break;
|
break;
|
||||||
case STATIC_IPV6_GATEWAY:
|
case STATIC_IPV6_GATEWAY:
|
||||||
case STATIC_IPV6_GATEWAY_IFNAME:
|
case STATIC_IPV6_GATEWAY_IFNAME:
|
||||||
p.family = AF_INET6;
|
p.family = AF_INET6;
|
||||||
p.prefixlen = IPV6_MAX_BITLEN;
|
p.prefixlen = IPV6_MAX_BITLEN;
|
||||||
p.u.prefix6 = si->addr.ipv6;
|
p.u.prefix6 = si->addr.ipv6;
|
||||||
|
afi = AFI_IP6;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset(&lookup, 0, sizeof(lookup));
|
||||||
|
lookup.nh = &p;
|
||||||
|
|
||||||
|
si->nh_registered = reg;
|
||||||
|
|
||||||
|
if (reg) {
|
||||||
|
nhtd = hash_get(static_nht_hash, &lookup,
|
||||||
|
static_nht_hash_alloc);
|
||||||
|
nhtd->refcount++;
|
||||||
|
|
||||||
|
if (nhtd->refcount > 1) {
|
||||||
|
static_nht_update(nhtd->nh, nhtd->nh_num,
|
||||||
|
afi, si->nh_vrf_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nhtd = hash_lookup(static_nht_hash, &lookup);
|
||||||
|
if (!nhtd)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nhtd->refcount--;
|
||||||
|
if (nhtd->refcount >= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
hash_release(static_nht_hash, nhtd);
|
||||||
|
static_nht_hash_free(nhtd);
|
||||||
|
}
|
||||||
|
|
||||||
if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
|
if (zclient_send_rnh(zclient, cmd, &p, false, si->nh_vrf_id) < 0)
|
||||||
zlog_warn("%s: Failure to send nexthop to zebra",
|
zlog_warn("%s: Failure to send nexthop to zebra",
|
||||||
__PRETTY_FUNCTION__);
|
__PRETTY_FUNCTION__);
|
||||||
|
|
||||||
si->nh_registered = reg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void static_zebra_route_add(struct route_node *rn,
|
extern void static_zebra_route_add(struct route_node *rn,
|
||||||
@ -373,4 +457,8 @@ void static_zebra_init(void)
|
|||||||
zclient->interface_address_delete = interface_address_delete;
|
zclient->interface_address_delete = interface_address_delete;
|
||||||
zclient->route_notify_owner = route_notify_owner;
|
zclient->route_notify_owner = route_notify_owner;
|
||||||
zclient->nexthop_update = static_zebra_nexthop_update;
|
zclient->nexthop_update = static_zebra_nexthop_update;
|
||||||
|
|
||||||
|
static_nht_hash = hash_create(static_nht_hash_key,
|
||||||
|
static_nht_hash_cmp,
|
||||||
|
"Static Nexthop Tracking hash");
|
||||||
}
|
}
|
||||||
|
@ -1022,6 +1022,7 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
|
|||||||
unsigned short l = 0;
|
unsigned short l = 0;
|
||||||
uint8_t flags = 0;
|
uint8_t flags = 0;
|
||||||
uint16_t type = cmd2type[hdr->command];
|
uint16_t type = cmd2type[hdr->command];
|
||||||
|
bool exist;
|
||||||
|
|
||||||
if (IS_ZEBRA_DEBUG_NHT)
|
if (IS_ZEBRA_DEBUG_NHT)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
@ -1064,7 +1065,10 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
|
|||||||
p.family);
|
p.family);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type);
|
rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type, &exist);
|
||||||
|
if (!rnh)
|
||||||
|
return;
|
||||||
|
|
||||||
if (type == RNH_NEXTHOP_TYPE) {
|
if (type == RNH_NEXTHOP_TYPE) {
|
||||||
if (flags
|
if (flags
|
||||||
&& !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
|
&& !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED))
|
||||||
@ -1084,7 +1088,9 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS)
|
|||||||
|
|
||||||
zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
|
zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf));
|
||||||
/* Anything not AF_INET/INET6 has been filtered out above */
|
/* Anything not AF_INET/INET6 has been filtered out above */
|
||||||
zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type, &p);
|
if (!exist)
|
||||||
|
zebra_evaluate_rnh(zvrf_id(zvrf), p.family, 1, type,
|
||||||
|
&p);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_failure:
|
stream_failure:
|
||||||
|
@ -103,7 +103,8 @@ char *rnh_str(struct rnh *rnh, char *buf, int size)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
|
struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
|
||||||
|
bool *exists)
|
||||||
{
|
{
|
||||||
struct route_table *table;
|
struct route_table *table;
|
||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
@ -119,6 +120,7 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
|
|||||||
prefix2str(p, buf, sizeof(buf));
|
prefix2str(p, buf, sizeof(buf));
|
||||||
zlog_warn("%u: Add RNH %s type %d - table not found", vrfid,
|
zlog_warn("%u: Add RNH %s type %d - table not found", vrfid,
|
||||||
buf, type);
|
buf, type);
|
||||||
|
exists = false;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +138,9 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
|
|||||||
route_lock_node(rn);
|
route_lock_node(rn);
|
||||||
rn->info = rnh;
|
rn->info = rnh;
|
||||||
rnh->node = rn;
|
rnh->node = rn;
|
||||||
}
|
*exists = false;
|
||||||
|
} else
|
||||||
|
*exists = true;
|
||||||
|
|
||||||
route_unlock_node(rn);
|
route_unlock_node(rn);
|
||||||
return (rn->info);
|
return (rn->info);
|
||||||
@ -190,6 +194,14 @@ void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type)
|
|||||||
route_unlock_node(rn);
|
route_unlock_node(rn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code will send to the registering client
|
||||||
|
* the looked up rnh.
|
||||||
|
* For a rnh that was created, there is no data
|
||||||
|
* so it will send an empty nexthop group
|
||||||
|
* If rnh exists then we know it has been evaluated
|
||||||
|
* and as such it will have a resolved rnh.
|
||||||
|
*/
|
||||||
void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
|
void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
|
||||||
rnh_type_t type, vrf_id_t vrf_id)
|
rnh_type_t type, vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
@ -201,8 +213,7 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
|
|||||||
}
|
}
|
||||||
if (!listnode_lookup(rnh->client_list, client)) {
|
if (!listnode_lookup(rnh->client_list, client)) {
|
||||||
listnode_add(rnh->client_list, client);
|
listnode_add(rnh->client_list, client);
|
||||||
send_client(rnh, client, type,
|
send_client(rnh, client, type, vrf_id);
|
||||||
vrf_id); // Pending: check if its needed
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,9 +258,10 @@ void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw)
|
|||||||
{
|
{
|
||||||
struct prefix nh;
|
struct prefix nh;
|
||||||
struct rnh *rnh;
|
struct rnh *rnh;
|
||||||
|
bool exists;
|
||||||
|
|
||||||
addr2hostprefix(pw->af, &pw->nexthop, &nh);
|
addr2hostprefix(pw->af, &pw->nexthop, &nh);
|
||||||
rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE);
|
rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE, &exists);
|
||||||
if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
|
if (rnh && !listnode_lookup(rnh->zebra_pseudowire_list, pw)) {
|
||||||
listnode_add(rnh->zebra_pseudowire_list, pw);
|
listnode_add(rnh->zebra_pseudowire_list, pw);
|
||||||
pw->rnh = rnh;
|
pw->rnh = rnh;
|
||||||
|
@ -68,7 +68,7 @@ static inline int rnh_resolve_via_default(int family)
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid,
|
extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid,
|
||||||
rnh_type_t type);
|
rnh_type_t type, bool *exists);
|
||||||
extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
|
extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
|
||||||
rnh_type_t type);
|
rnh_type_t type);
|
||||||
extern void zebra_free_rnh(struct rnh *rnh);
|
extern void zebra_free_rnh(struct rnh *rnh);
|
||||||
|
Loading…
Reference in New Issue
Block a user