mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-13 12:15:33 +00:00
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:
commit
c0f5b038b6
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user