diff options
-rw-r--r-- | nhrpd/nhrp_cache.c | 86 | ||||
-rw-r--r-- | nhrpd/nhrp_interface.c | 63 | ||||
-rw-r--r-- | nhrpd/nhrp_vty.c | 49 | ||||
-rw-r--r-- | nhrpd/nhrpd.h | 14 |
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, |