summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--nhrpd/nhrp_cache.c86
-rw-r--r--nhrpd/nhrp_interface.c63
-rw-r--r--nhrpd/nhrp_vty.c49
-rw-r--r--nhrpd/nhrpd.h14
4 files changed, 195 insertions, 17 deletions
diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c
index f7c71c221..1c8fee8b0 100644
--- 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_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)
{
diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c
index 0ed2371eb..0e7d4e793 100644
--- 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 *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;
}
diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c
index 27b7bece4..1ea4c5e64 100644
--- 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 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)
diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h
index cbee5951f..80a365a3c 100644
--- 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,