Merge pull request #7501 from pguibert6WIND/nhrp_map_fix

nhrpd: cache config may disappear if iface not present at startup
This commit is contained in:
Russ White 2020-12-07 16:17:39 -05:00 committed by GitHub
commit c0f5b038b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 195 additions and 17 deletions

View File

@ -16,6 +16,7 @@
#include "netlink.h"
DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry")
DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE_CONFIG, "NHRP cache config entry")
unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES];
@ -77,6 +78,68 @@ static void nhrp_cache_free(struct nhrp_cache *c)
XFREE(MTYPE_NHRP_CACHE, c);
}
static unsigned int nhrp_cache_config_protocol_key(const void *peer_data)
{
const struct nhrp_cache_config *p = peer_data;
return sockunion_hash(&p->remote_addr);
}
static bool nhrp_cache_config_protocol_cmp(const void *cache_data,
const void *key_data)
{
const struct nhrp_cache_config *a = cache_data;
const struct nhrp_cache_config *b = key_data;
if (!sockunion_same(&a->remote_addr, &b->remote_addr))
return false;
if (a->ifp != b->ifp)
return false;
return true;
}
static void *nhrp_cache_config_alloc(void *data)
{
struct nhrp_cache_config *p, *key = data;
p = XCALLOC(MTYPE_NHRP_CACHE_CONFIG, sizeof(struct nhrp_cache_config));
*p = (struct nhrp_cache_config){
.remote_addr = key->remote_addr,
.ifp = key->ifp,
};
return p;
}
void nhrp_cache_config_free(struct nhrp_cache_config *c)
{
struct nhrp_interface *nifp = c->ifp->info;
hash_release(nifp->cache_config_hash, c);
XFREE(MTYPE_NHRP_CACHE_CONFIG, c);
}
struct nhrp_cache_config *nhrp_cache_config_get(struct interface *ifp,
union sockunion *remote_addr,
int create)
{
struct nhrp_interface *nifp = ifp->info;
struct nhrp_cache_config key;
if (!nifp->cache_config_hash) {
nifp->cache_config_hash =
hash_create(nhrp_cache_config_protocol_key,
nhrp_cache_config_protocol_cmp,
"NHRP Config Cache");
if (!nifp->cache_config_hash)
return NULL;
}
key.remote_addr = *remote_addr;
key.ifp = ifp;
return hash_get(nifp->cache_config_hash, &key,
create ? nhrp_cache_config_alloc : NULL);
}
struct nhrp_cache *nhrp_cache_get(struct interface *ifp,
union sockunion *remote_addr, int create)
{
@ -424,12 +487,23 @@ struct nhrp_cache_iterator_ctx {
void *ctx;
};
struct nhrp_cache_config_iterator_ctx {
void (*cb)(struct nhrp_cache_config *, void *);
void *ctx;
};
static void nhrp_cache_iterator(struct hash_bucket *b, void *ctx)
{
struct nhrp_cache_iterator_ctx *ic = ctx;
ic->cb(b->data, ic->ctx);
}
static void nhrp_cache_config_iterator(struct hash_bucket *b, void *ctx)
{
struct nhrp_cache_config_iterator_ctx *ic = ctx;
ic->cb(b->data, ic->ctx);
}
void nhrp_cache_foreach(struct interface *ifp,
void (*cb)(struct nhrp_cache *, void *), void *ctx)
{
@ -442,6 +516,18 @@ void nhrp_cache_foreach(struct interface *ifp,
hash_iterate(nifp->cache_hash, nhrp_cache_iterator, &ic);
}
void nhrp_cache_config_foreach(struct interface *ifp,
void (*cb)(struct nhrp_cache_config *, void *), void *ctx)
{
struct nhrp_interface *nifp = ifp->info;
struct nhrp_cache_config_iterator_ctx ic = {
.cb = cb, .ctx = ctx,
};
if (nifp->cache_config_hash)
hash_iterate(nifp->cache_config_hash, nhrp_cache_config_iterator, &ic);
}
void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *n,
notifier_fn_t fn)
{

View File

@ -23,6 +23,10 @@
DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface")
static void nhrp_interface_update_cache_config(struct interface *ifp,
bool available,
uint8_t family);
static int nhrp_if_new_hook(struct interface *ifp)
{
struct nhrp_interface *nifp;
@ -311,11 +315,68 @@ int nhrp_ifp_destroy(struct interface *ifp)
{
debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name);
nhrp_interface_update_cache_config(ifp, false, AF_INET);
nhrp_interface_update_cache_config(ifp, false, AF_INET6);
nhrp_interface_update(ifp);
return 0;
}
struct map_ctx {
int family;
bool enabled;
};
static void interface_config_update_nhrp_map(struct nhrp_cache_config *cc, void *data)
{
struct map_ctx *ctx = data;
struct interface *ifp = cc->ifp;
struct nhrp_cache *c;
union sockunion nbma_addr;
if (sockunion_family(&cc->remote_addr) != ctx->family)
return;
/* gre layer not ready */
if (ifp->vrf_id == VRF_UNKNOWN)
return;
c = nhrp_cache_get(ifp, &cc->remote_addr, ctx->enabled ? 1 : 0);
if (!c && !ctx->enabled)
return;
/* suppress */
if (!ctx->enabled) {
if (c && c->map) {
nhrp_cache_update_binding(c, c->cur.type, -1,
nhrp_peer_get(ifp, &nbma_addr), 0, NULL);
}
return;
}
/* create */
c->map = 1;
if (cc->type == NHRP_CACHE_LOCAL)
nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0,
NULL);
else {
nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0,
nhrp_peer_get(ifp, &cc->nbma), 0,
NULL);
}
}
static void nhrp_interface_update_cache_config(struct interface *ifp, bool available, uint8_t family)
{
struct map_ctx mapctx;
mapctx = (struct map_ctx){
.family = family,
.enabled = available
};
nhrp_cache_config_foreach(ifp, interface_config_update_nhrp_map,
&mapctx);
}
int nhrp_ifp_up(struct interface *ifp)
{
debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
@ -345,7 +406,7 @@ int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS)
nhrp_interface_update_address(
ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
nhrp_interface_update_cache_config(ifc->ifp, true, PREFIX_FAMILY(ifc->address));
return 0;
}

View File

@ -494,28 +494,42 @@ DEFUN(if_nhrp_map, if_nhrp_map_cmd,
VTY_DECLVAR_CONTEXT(interface, ifp);
afi_t afi = cmd_to_afi(argv[0]);
union sockunion proto_addr, nbma_addr;
struct nhrp_cache_config *cc;
struct nhrp_cache *c;
enum nhrp_cache_type type;
if (str2sockunion(argv[3]->arg, &proto_addr) < 0
|| afi2family(afi) != sockunion_family(&proto_addr))
return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
if (strmatch(argv[4]->text, "local"))
type = NHRP_CACHE_LOCAL;
else {
if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
return nhrp_vty_return(vty, NHRP_ERR_FAIL);
type = NHRP_CACHE_STATIC;
}
cc = nhrp_cache_config_get(ifp, &proto_addr, 1);
if (!cc)
return nhrp_vty_return(vty, NHRP_ERR_FAIL);
cc->nbma = nbma_addr;
cc->type = type;
/* gre layer not ready */
if (ifp->ifindex == IFINDEX_INTERNAL)
return CMD_SUCCESS;
c = nhrp_cache_get(ifp, &proto_addr, 1);
if (!c)
return nhrp_vty_return(vty, NHRP_ERR_FAIL);
c->map = 1;
if (strmatch(argv[4]->text, "local")) {
if (type == NHRP_CACHE_LOCAL)
nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0,
NULL);
} else {
if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
return nhrp_vty_return(vty, NHRP_ERR_FAIL);
else
nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0,
nhrp_peer_get(ifp, &nbma_addr), 0,
NULL);
}
return CMD_SUCCESS;
}
@ -533,15 +547,22 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd,
VTY_DECLVAR_CONTEXT(interface, ifp);
afi_t afi = cmd_to_afi(argv[1]);
union sockunion proto_addr, nbma_addr;
struct nhrp_cache_config *cc;
struct nhrp_cache *c;
if (str2sockunion(argv[4]->arg, &proto_addr) < 0
|| afi2family(afi) != sockunion_family(&proto_addr))
return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
cc = nhrp_cache_config_get(ifp, &proto_addr, 0);
if (!cc)
return nhrp_vty_return(vty, NHRP_ERR_FAIL);
nhrp_cache_config_free(cc);
c = nhrp_cache_get(ifp, &proto_addr, 0);
/* silently return */
if (!c || !c->map)
return nhrp_vty_return(vty, NHRP_ERR_ENTRY_NOT_FOUND);
return CMD_SUCCESS;
nhrp_cache_update_binding(c, c->cur.type, -1,
nhrp_peer_get(ifp, &nbma_addr), 0, NULL);
@ -997,23 +1018,19 @@ struct write_map_ctx {
const char *aficmd;
};
static void interface_config_write_nhrp_map(struct nhrp_cache *c, void *data)
static void interface_config_write_nhrp_map(struct nhrp_cache_config *c, void *data)
{
struct write_map_ctx *ctx = data;
struct vty *vty = ctx->vty;
char buf[2][SU_ADDRSTRLEN];
if (!c->map)
return;
if (sockunion_family(&c->remote_addr) != ctx->family)
return;
vty_out(vty, " %s nhrp map %s %s\n", ctx->aficmd,
sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])),
c->cur.type == NHRP_CACHE_LOCAL
? "local"
: sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1],
sizeof(buf[1])));
c->type == NHRP_CACHE_LOCAL
? "local" : sockunion2str(&c->nbma, buf[1], sizeof(buf[1])));
}
static int interface_config_write(struct vty *vty)
@ -1076,8 +1093,8 @@ static int interface_config_write(struct vty *vty)
.family = afi2family(afi),
.aficmd = aficmd,
};
nhrp_cache_foreach(ifp, interface_config_write_nhrp_map,
&mapctx);
nhrp_cache_config_foreach(ifp, interface_config_write_nhrp_map,
&mapctx);
list_for_each_entry(nhs, &ad->nhslist_head,
nhslist_entry)

View File

@ -197,6 +197,13 @@ enum nhrp_cache_type {
extern const char *const nhrp_cache_type_str[];
extern unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES];
struct nhrp_cache_config {
struct interface *ifp;
union sockunion remote_addr;
enum nhrp_cache_type type;
union sockunion nbma;
};
struct nhrp_cache {
struct interface *ifp;
union sockunion remote_addr;
@ -280,6 +287,7 @@ struct nhrp_interface {
uint32_t grekey;
struct hash *peer_hash;
struct hash *cache_config_hash;
struct hash *cache_hash;
struct notifier_list notifier_list;
@ -358,10 +366,16 @@ void nhrp_shortcut_foreach(afi_t afi,
void nhrp_shortcut_purge(struct nhrp_shortcut *s, int force);
void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted);
void nhrp_cache_config_free(struct nhrp_cache_config *c);
struct nhrp_cache_config *nhrp_cache_config_get(struct interface *ifp,
union sockunion *remote_addr,
int create);
struct nhrp_cache *nhrp_cache_get(struct interface *ifp,
union sockunion *remote_addr, int create);
void nhrp_cache_foreach(struct interface *ifp,
void (*cb)(struct nhrp_cache *, void *), void *ctx);
void nhrp_cache_config_foreach(struct interface *ifp,
void (*cb)(struct nhrp_cache_config *, void *), void *ctx);
void nhrp_cache_set_used(struct nhrp_cache *, int);
int nhrp_cache_update_binding(struct nhrp_cache *, enum nhrp_cache_type type,
int holding_time, struct nhrp_peer *p,