|
From fef2ed139d140f551cdfcbb21c5a023dea2e02cb Mon Sep 17 00:00:00 2001
|
|
From: Philippe Guibert <philippe.guibert@6wind.com>
|
|
Date: Thu, 26 Mar 2020 17:33:53 +0100
|
|
Subject: [PATCH] nhrpd: cache config may disappear if iface not present at
|
|
startup
|
|
|
|
When interface not present at config time, store separately the list of
|
|
config parameters. Then, when interface is ready and an address has been configured, the nbma setting is done. Reversely, when interface disappears,
|
|
there is no need to keep the maps present, then keep only the configuration.
|
|
|
|
Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
|
|
---
|
|
nhrpd/nhrp_cache.c | 86 ++++++++++++++++++++++++++++++++++++++++++
|
|
nhrpd/nhrp_interface.c | 63 ++++++++++++++++++++++++++++++-
|
|
nhrpd/nhrp_vty.c | 49 ++++++++++++++++--------
|
|
nhrpd/nhrpd.h | 14 +++++++
|
|
4 files changed, 195 insertions(+), 17 deletions(-)
|
|
|
|
--- a/nhrpd/nhrp_cache.c
|
|
+++ b/nhrpd/nhrp_cache.c
|
|
@@ -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_
|
|
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)
|
|
{
|
|
@@ -423,12 +486,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)
|
|
{
|
|
@@ -441,6 +515,18 @@ void nhrp_cache_foreach(struct interface
|
|
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)
|
|
{
|
|
--- a/nhrpd/nhrp_interface.c
|
|
+++ b/nhrpd/nhrp_interface.c
|
|
@@ -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 *i
|
|
{
|
|
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);
|
|
@@ -346,7 +407,7 @@ int nhrp_interface_address_add(ZAPI_CALL
|
|
|
|
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;
|
|
}
|
|
|
|
--- a/nhrpd/nhrp_vty.c
|
|
+++ b/nhrpd/nhrp_vty.c
|
|
@@ -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
|
|
.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)
|
|
--- a/nhrpd/nhrpd.h
|
|
+++ b/nhrpd/nhrpd.h
|
|
@@ -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,
|