mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 00:56:19 +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"
|
#include "netlink.h"
|
||||||
|
|
||||||
DEFINE_MTYPE_STATIC(NHRPD, NHRP_CACHE, "NHRP cache entry")
|
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];
|
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);
|
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,
|
struct nhrp_cache *nhrp_cache_get(struct interface *ifp,
|
||||||
union sockunion *remote_addr, int create)
|
union sockunion *remote_addr, int create)
|
||||||
{
|
{
|
||||||
@ -424,12 +487,23 @@ struct nhrp_cache_iterator_ctx {
|
|||||||
void *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)
|
static void nhrp_cache_iterator(struct hash_bucket *b, void *ctx)
|
||||||
{
|
{
|
||||||
struct nhrp_cache_iterator_ctx *ic = ctx;
|
struct nhrp_cache_iterator_ctx *ic = ctx;
|
||||||
ic->cb(b->data, 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 nhrp_cache_foreach(struct interface *ifp,
|
||||||
void (*cb)(struct nhrp_cache *, void *), void *ctx)
|
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);
|
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,
|
void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *n,
|
||||||
notifier_fn_t fn)
|
notifier_fn_t fn)
|
||||||
{
|
{
|
||||||
|
@ -23,6 +23,10 @@
|
|||||||
|
|
||||||
DEFINE_MTYPE_STATIC(NHRPD, NHRP_IF, "NHRP interface")
|
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)
|
static int nhrp_if_new_hook(struct interface *ifp)
|
||||||
{
|
{
|
||||||
struct nhrp_interface *nifp;
|
struct nhrp_interface *nifp;
|
||||||
@ -311,11 +315,68 @@ int nhrp_ifp_destroy(struct interface *ifp)
|
|||||||
{
|
{
|
||||||
debugf(NHRP_DEBUG_IF, "if-delete: %s", ifp->name);
|
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);
|
nhrp_interface_update(ifp);
|
||||||
|
|
||||||
return 0;
|
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)
|
int nhrp_ifp_up(struct interface *ifp)
|
||||||
{
|
{
|
||||||
debugf(NHRP_DEBUG_IF, "if-up: %s", ifp->name);
|
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(
|
nhrp_interface_update_address(
|
||||||
ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
|
ifc->ifp, family2afi(PREFIX_FAMILY(ifc->address)), 0);
|
||||||
|
nhrp_interface_update_cache_config(ifc->ifp, true, PREFIX_FAMILY(ifc->address));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,28 +494,42 @@ DEFUN(if_nhrp_map, if_nhrp_map_cmd,
|
|||||||
VTY_DECLVAR_CONTEXT(interface, ifp);
|
VTY_DECLVAR_CONTEXT(interface, ifp);
|
||||||
afi_t afi = cmd_to_afi(argv[0]);
|
afi_t afi = cmd_to_afi(argv[0]);
|
||||||
union sockunion proto_addr, nbma_addr;
|
union sockunion proto_addr, nbma_addr;
|
||||||
|
struct nhrp_cache_config *cc;
|
||||||
struct nhrp_cache *c;
|
struct nhrp_cache *c;
|
||||||
|
enum nhrp_cache_type type;
|
||||||
|
|
||||||
if (str2sockunion(argv[3]->arg, &proto_addr) < 0
|
if (str2sockunion(argv[3]->arg, &proto_addr) < 0
|
||||||
|| afi2family(afi) != sockunion_family(&proto_addr))
|
|| afi2family(afi) != sockunion_family(&proto_addr))
|
||||||
return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
|
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);
|
c = nhrp_cache_get(ifp, &proto_addr, 1);
|
||||||
if (!c)
|
if (!c)
|
||||||
return nhrp_vty_return(vty, NHRP_ERR_FAIL);
|
return nhrp_vty_return(vty, NHRP_ERR_FAIL);
|
||||||
|
|
||||||
c->map = 1;
|
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,
|
nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0,
|
||||||
NULL);
|
NULL);
|
||||||
} else {
|
else
|
||||||
if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
|
|
||||||
return nhrp_vty_return(vty, NHRP_ERR_FAIL);
|
|
||||||
nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0,
|
nhrp_cache_update_binding(c, NHRP_CACHE_STATIC, 0,
|
||||||
nhrp_peer_get(ifp, &nbma_addr), 0,
|
nhrp_peer_get(ifp, &nbma_addr), 0,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,15 +547,22 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd,
|
|||||||
VTY_DECLVAR_CONTEXT(interface, ifp);
|
VTY_DECLVAR_CONTEXT(interface, ifp);
|
||||||
afi_t afi = cmd_to_afi(argv[1]);
|
afi_t afi = cmd_to_afi(argv[1]);
|
||||||
union sockunion proto_addr, nbma_addr;
|
union sockunion proto_addr, nbma_addr;
|
||||||
|
struct nhrp_cache_config *cc;
|
||||||
struct nhrp_cache *c;
|
struct nhrp_cache *c;
|
||||||
|
|
||||||
if (str2sockunion(argv[4]->arg, &proto_addr) < 0
|
if (str2sockunion(argv[4]->arg, &proto_addr) < 0
|
||||||
|| afi2family(afi) != sockunion_family(&proto_addr))
|
|| afi2family(afi) != sockunion_family(&proto_addr))
|
||||||
return nhrp_vty_return(vty, NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH);
|
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);
|
c = nhrp_cache_get(ifp, &proto_addr, 0);
|
||||||
|
/* silently return */
|
||||||
if (!c || !c->map)
|
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_cache_update_binding(c, c->cur.type, -1,
|
||||||
nhrp_peer_get(ifp, &nbma_addr), 0, NULL);
|
nhrp_peer_get(ifp, &nbma_addr), 0, NULL);
|
||||||
@ -997,23 +1018,19 @@ struct write_map_ctx {
|
|||||||
const char *aficmd;
|
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 write_map_ctx *ctx = data;
|
||||||
struct vty *vty = ctx->vty;
|
struct vty *vty = ctx->vty;
|
||||||
char buf[2][SU_ADDRSTRLEN];
|
char buf[2][SU_ADDRSTRLEN];
|
||||||
|
|
||||||
if (!c->map)
|
|
||||||
return;
|
|
||||||
if (sockunion_family(&c->remote_addr) != ctx->family)
|
if (sockunion_family(&c->remote_addr) != ctx->family)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vty_out(vty, " %s nhrp map %s %s\n", ctx->aficmd,
|
vty_out(vty, " %s nhrp map %s %s\n", ctx->aficmd,
|
||||||
sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])),
|
sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])),
|
||||||
c->cur.type == NHRP_CACHE_LOCAL
|
c->type == NHRP_CACHE_LOCAL
|
||||||
? "local"
|
? "local" : sockunion2str(&c->nbma, buf[1], sizeof(buf[1])));
|
||||||
: sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1],
|
|
||||||
sizeof(buf[1])));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int interface_config_write(struct vty *vty)
|
static int interface_config_write(struct vty *vty)
|
||||||
@ -1076,8 +1093,8 @@ static int interface_config_write(struct vty *vty)
|
|||||||
.family = afi2family(afi),
|
.family = afi2family(afi),
|
||||||
.aficmd = aficmd,
|
.aficmd = aficmd,
|
||||||
};
|
};
|
||||||
nhrp_cache_foreach(ifp, interface_config_write_nhrp_map,
|
nhrp_cache_config_foreach(ifp, interface_config_write_nhrp_map,
|
||||||
&mapctx);
|
&mapctx);
|
||||||
|
|
||||||
list_for_each_entry(nhs, &ad->nhslist_head,
|
list_for_each_entry(nhs, &ad->nhslist_head,
|
||||||
nhslist_entry)
|
nhslist_entry)
|
||||||
|
@ -197,6 +197,13 @@ enum nhrp_cache_type {
|
|||||||
extern const char *const nhrp_cache_type_str[];
|
extern const char *const nhrp_cache_type_str[];
|
||||||
extern unsigned long nhrp_cache_counts[NHRP_CACHE_NUM_TYPES];
|
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 nhrp_cache {
|
||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
union sockunion remote_addr;
|
union sockunion remote_addr;
|
||||||
@ -280,6 +287,7 @@ struct nhrp_interface {
|
|||||||
uint32_t grekey;
|
uint32_t grekey;
|
||||||
|
|
||||||
struct hash *peer_hash;
|
struct hash *peer_hash;
|
||||||
|
struct hash *cache_config_hash;
|
||||||
struct hash *cache_hash;
|
struct hash *cache_hash;
|
||||||
|
|
||||||
struct notifier_list notifier_list;
|
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_purge(struct nhrp_shortcut *s, int force);
|
||||||
void nhrp_shortcut_prefix_change(const struct prefix *p, int deleted);
|
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,
|
struct nhrp_cache *nhrp_cache_get(struct interface *ifp,
|
||||||
union sockunion *remote_addr, int create);
|
union sockunion *remote_addr, int create);
|
||||||
void nhrp_cache_foreach(struct interface *ifp,
|
void nhrp_cache_foreach(struct interface *ifp,
|
||||||
void (*cb)(struct nhrp_cache *, void *), void *ctx);
|
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);
|
void nhrp_cache_set_used(struct nhrp_cache *, int);
|
||||||
int nhrp_cache_update_binding(struct nhrp_cache *, enum nhrp_cache_type type,
|
int nhrp_cache_update_binding(struct nhrp_cache *, enum nhrp_cache_type type,
|
||||||
int holding_time, struct nhrp_peer *p,
|
int holding_time, struct nhrp_peer *p,
|
||||||
|
Loading…
Reference in New Issue
Block a user