Signed-off-by: Lucian Cristian <lucian.cristian@gmail.com>lilik-openwrt-22.03
@ -1,385 +0,0 @@ | |||
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, |
@ -1,48 +0,0 @@ | |||
From e5773617afba7408c76ec2683814ce076c72c79d Mon Sep 17 00:00:00 2001 | |||
From: Mark Stapp <mjs@voltanet.io> | |||
Date: Tue, 8 Dec 2020 09:10:10 -0500 | |||
Subject: [PATCH] nhrpd: fix SA warning in nhrp_interface | |||
Clear SA warning from recent nhrp cache code changes. | |||
Signed-off-by: Mark Stapp <mjs@voltanet.io> | |||
--- | |||
nhrpd/nhrp_interface.c | 14 ++++++++++---- | |||
1 file changed, 10 insertions(+), 4 deletions(-) | |||
--- a/nhrpd/nhrp_interface.c | |||
+++ b/nhrpd/nhrp_interface.c | |||
@@ -327,7 +327,8 @@ struct map_ctx { | |||
bool enabled; | |||
}; | |||
-static void interface_config_update_nhrp_map(struct nhrp_cache_config *cc, void *data) | |||
+static void interface_config_update_nhrp_map(struct nhrp_cache_config *cc, | |||
+ void *data) | |||
{ | |||
struct map_ctx *ctx = data; | |||
struct interface *ifp = cc->ifp; | |||
@@ -344,15 +345,20 @@ static void interface_config_update_nhrp | |||
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); | |||
+ nhrp_cache_update_binding( | |||
+ c, c->cur.type, -1, | |||
+ nhrp_peer_get(ifp, &nbma_addr), 0, NULL); | |||
} | |||
return; | |||
} | |||
- /* create */ | |||
+ | |||
+ /* Newly created */ | |||
+ assert(c != NULL); | |||
+ | |||
c->map = 1; | |||
if (cc->type == NHRP_CACHE_LOCAL) | |||
nhrp_cache_update_binding(c, NHRP_CACHE_LOCAL, 0, NULL, 0, |
@ -1,226 +0,0 @@ | |||
From ee72f0a0eb93038ef6dfd01fed9f32e24c5de2a1 Mon Sep 17 00:00:00 2001 | |||
From: Reuben Dowle <reuben.dowle@4rf.com> | |||
Date: Mon, 7 Dec 2020 16:35:13 +1300 | |||
Subject: [PATCH] nhrpd: Cleanup resources when interface is deleted | |||
Currently when an interface is deleted from configuration, associated | |||
resources are not freed. This causes memory leaks and crashes. | |||
To reproduce this issue: | |||
* Connect to a DMVPN hub | |||
* Outside of frr, delete the underlying GRE interface | |||
* Use 'no interface xxx' to delete the interface containing nhrp configurations | |||
Signed-off-by: Reuben Dowle <reuben.dowle@4rf.com> | |||
--- | |||
nhrpd/nhrp_cache.c | 42 ++++++++++++++++++++++++++++++++++++++++-- | |||
nhrpd/nhrp_interface.c | 15 +++++++++++++++ | |||
nhrpd/nhrp_nhs.c | 18 ++++++++++++++++++ | |||
nhrpd/nhrp_peer.c | 27 +++++++++++++++++++++++++++ | |||
nhrpd/nhrpd.h | 3 +++ | |||
5 files changed, 103 insertions(+), 2 deletions(-) | |||
mode change 100644 => 100755 nhrpd/nhrp_cache.c | |||
mode change 100644 => 100755 nhrpd/nhrp_interface.c | |||
mode change 100644 => 100755 nhrpd/nhrpd.h | |||
--- a/nhrpd/nhrp_cache.c | |||
+++ b/nhrpd/nhrp_cache.c | |||
@@ -69,12 +69,13 @@ static void nhrp_cache_free(struct nhrp_ | |||
{ | |||
struct nhrp_interface *nifp = c->ifp->info; | |||
- zassert(c->cur.type == NHRP_CACHE_INVALID && c->cur.peer == NULL); | |||
- zassert(c->new.type == NHRP_CACHE_INVALID && c->new.peer == NULL); | |||
+ debugf(NHRP_DEBUG_COMMON, "Deleting cache entry"); | |||
nhrp_cache_counts[c->cur.type]--; | |||
notifier_call(&c->notifier_list, NOTIFY_CACHE_DELETE); | |||
zassert(!notifier_active(&c->notifier_list)); | |||
hash_release(nifp->cache_hash, c); | |||
+ THREAD_OFF(c->t_timeout); | |||
+ THREAD_OFF(c->t_auth); | |||
XFREE(MTYPE_NHRP_CACHE, c); | |||
} | |||
@@ -140,6 +141,41 @@ struct nhrp_cache_config *nhrp_cache_con | |||
create ? nhrp_cache_config_alloc : NULL); | |||
} | |||
+static void do_nhrp_cache_free(struct hash_bucket *hb, | |||
+ void *arg __attribute__((__unused__))) | |||
+{ | |||
+ struct nhrp_cache *c = hb->data; | |||
+ | |||
+ nhrp_cache_free(c); | |||
+} | |||
+ | |||
+static void do_nhrp_cache_config_free(struct hash_bucket *hb, | |||
+ void *arg __attribute__((__unused__))) | |||
+{ | |||
+ struct nhrp_cache_config *cc = hb->data; | |||
+ | |||
+ nhrp_cache_config_free(cc); | |||
+} | |||
+ | |||
+void nhrp_cache_interface_del(struct interface *ifp) | |||
+{ | |||
+ struct nhrp_interface *nifp = ifp->info; | |||
+ | |||
+ debugf(NHRP_DEBUG_COMMON, "Cleaning up undeleted cache entries (%lu)", | |||
+ nifp->cache_hash ? nifp->cache_hash->count : 0); | |||
+ | |||
+ if (nifp->cache_hash) { | |||
+ hash_iterate(nifp->cache_hash, do_nhrp_cache_free, NULL); | |||
+ hash_free(nifp->cache_hash); | |||
+ } | |||
+ | |||
+ if (nifp->cache_config_hash) { | |||
+ hash_iterate(nifp->cache_config_hash, do_nhrp_cache_config_free, | |||
+ NULL); | |||
+ hash_free(nifp->cache_config_hash); | |||
+ } | |||
+} | |||
+ | |||
struct nhrp_cache *nhrp_cache_get(struct interface *ifp, | |||
union sockunion *remote_addr, int create) | |||
{ | |||
@@ -164,6 +200,7 @@ struct nhrp_cache *nhrp_cache_get(struct | |||
static int nhrp_cache_do_free(struct thread *t) | |||
{ | |||
struct nhrp_cache *c = THREAD_ARG(t); | |||
+ | |||
c->t_timeout = NULL; | |||
nhrp_cache_free(c); | |||
return 0; | |||
@@ -172,6 +209,7 @@ static int nhrp_cache_do_free(struct thr | |||
static int nhrp_cache_do_timeout(struct thread *t) | |||
{ | |||
struct nhrp_cache *c = THREAD_ARG(t); | |||
+ | |||
c->t_timeout = NULL; | |||
if (c->cur.type != NHRP_CACHE_INVALID) | |||
nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL); | |||
--- a/nhrpd/nhrp_interface.c | |||
+++ b/nhrpd/nhrp_interface.c | |||
@@ -49,6 +49,21 @@ static int nhrp_if_new_hook(struct inter | |||
static int nhrp_if_delete_hook(struct interface *ifp) | |||
{ | |||
+ struct nhrp_interface *nifp = ifp->info; | |||
+ | |||
+ debugf(NHRP_DEBUG_IF, "Deleted interface (%s)", ifp->name); | |||
+ | |||
+ nhrp_cache_interface_del(ifp); | |||
+ nhrp_nhs_interface_del(ifp); | |||
+ nhrp_peer_interface_del(ifp); | |||
+ | |||
+ if (nifp->ipsec_profile) | |||
+ free(nifp->ipsec_profile); | |||
+ if (nifp->ipsec_fallback_profile) | |||
+ free(nifp->ipsec_fallback_profile); | |||
+ if (nifp->source) | |||
+ free(nifp->source); | |||
+ | |||
XFREE(MTYPE_NHRP_IF, ifp->info); | |||
return 0; | |||
} | |||
--- a/nhrpd/nhrp_nhs.c | |||
+++ b/nhrpd/nhrp_nhs.c | |||
@@ -378,6 +378,24 @@ int nhrp_nhs_free(struct nhrp_nhs *nhs) | |||
return 0; | |||
} | |||
+void nhrp_nhs_interface_del(struct interface *ifp) | |||
+{ | |||
+ struct nhrp_interface *nifp = ifp->info; | |||
+ struct nhrp_nhs *nhs, *tmp; | |||
+ afi_t afi; | |||
+ | |||
+ for (afi = 0; afi < AFI_MAX; afi++) { | |||
+ debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%d)", | |||
+ !list_empty(&nifp->afi[afi].nhslist_head)); | |||
+ | |||
+ list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head, | |||
+ nhslist_entry) | |||
+ { | |||
+ nhrp_nhs_free(nhs); | |||
+ } | |||
+ } | |||
+} | |||
+ | |||
void nhrp_nhs_terminate(void) | |||
{ | |||
struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); | |||
--- a/nhrpd/nhrp_peer.c | |||
+++ b/nhrpd/nhrp_peer.c | |||
@@ -38,11 +38,17 @@ static void nhrp_packet_debug(struct zbu | |||
static void nhrp_peer_check_delete(struct nhrp_peer *p) | |||
{ | |||
+ char buf[2][256]; | |||
struct nhrp_interface *nifp = p->ifp->info; | |||
if (p->ref || notifier_active(&p->notifier_list)) | |||
return; | |||
+ debugf(NHRP_DEBUG_COMMON, "Deleting peer ref:%d remote:%s local:%s", | |||
+ p->ref, | |||
+ sockunion2str(&p->vc->remote.nbma, buf[0], sizeof(buf[0])), | |||
+ sockunion2str(&p->vc->local.nbma, buf[1], sizeof(buf[1]))); | |||
+ | |||
THREAD_OFF(p->t_fallback); | |||
hash_release(nifp->peer_hash, p); | |||
nhrp_interface_notify_del(p->ifp, &p->ifp_notifier); | |||
@@ -185,6 +191,27 @@ static void *nhrp_peer_create(void *data | |||
return p; | |||
} | |||
+static void do_peer_hash_free(struct hash_bucket *hb, | |||
+ void *arg __attribute__((__unused__))) | |||
+{ | |||
+ struct nhrp_peer *p = hb->data; | |||
+ nhrp_peer_check_delete(p); | |||
+} | |||
+ | |||
+void nhrp_peer_interface_del(struct interface *ifp) | |||
+{ | |||
+ struct nhrp_interface *nifp = ifp->info; | |||
+ | |||
+ debugf(NHRP_DEBUG_COMMON, "Cleaning up undeleted peer entries (%lu)", | |||
+ nifp->peer_hash ? nifp->peer_hash->count : 0); | |||
+ | |||
+ if (nifp->peer_hash) { | |||
+ hash_iterate(nifp->peer_hash, do_peer_hash_free, NULL); | |||
+ assert(nifp->peer_hash->count == 0); | |||
+ hash_free(nifp->peer_hash); | |||
+ } | |||
+} | |||
+ | |||
struct nhrp_peer *nhrp_peer_get(struct interface *ifp, | |||
const union sockunion *remote_nbma) | |||
{ | |||
--- a/nhrpd/nhrpd.h | |||
+++ b/nhrpd/nhrpd.h | |||
@@ -343,6 +343,7 @@ void nhrp_nhs_foreach(struct interface * | |||
void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, | |||
void *), | |||
void *ctx); | |||
+void nhrp_nhs_interface_del(struct interface *ifp); | |||
void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp); | |||
void nhrp_route_announce(int add, enum nhrp_cache_type type, | |||
@@ -366,6 +367,7 @@ 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_interface_del(struct interface *ifp); | |||
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, | |||
@@ -446,6 +448,7 @@ struct nhrp_reqid *nhrp_reqid_lookup(str | |||
int nhrp_packet_init(void); | |||
+void nhrp_peer_interface_del(struct interface *ifp); | |||
struct nhrp_peer *nhrp_peer_get(struct interface *ifp, | |||
const union sockunion *remote_nbma); | |||
struct nhrp_peer *nhrp_peer_ref(struct nhrp_peer *p); |
@ -1,383 +0,0 @@ | |||
From f91ce319d3cdb465df54ff4e091dbd4aed85b24c Mon Sep 17 00:00:00 2001 | |||
From: Mobashshera Rasool <mrasool@vmware.com> | |||
Date: Wed, 23 Dec 2020 13:20:22 +0000 | |||
Subject: [PATCH] ospfd: Clear ip ospf process and clear ip ospf neighbor | |||
Implement the below 2 CLIs to clear the current data in the process | |||
and neighbor data structure. | |||
1. clear ip ospf process | |||
2. clear ip ospf neighbor | |||
Signed-off-by: Mobashshera Rasool <mrasool@vmware.com> | |||
--- | |||
doc/user/ospfd.rst | 17 ++++++++ | |||
ospfd/ospf_ase.c | 1 + | |||
ospfd/ospf_lsa.c | 13 +++++- | |||
ospfd/ospf_vty.c | 72 +++++++++++++++++++++++++++++++-- | |||
ospfd/ospfd.c | 99 ++++++++++++++++++++++++++++++++++++---------- | |||
ospfd/ospfd.h | 5 +++ | |||
6 files changed, 182 insertions(+), 25 deletions(-) | |||
--- a/doc/user/ospfd.rst | |||
+++ b/doc/user/ospfd.rst | |||
@@ -322,6 +322,23 @@ To start OSPF process you have to specif | |||
This feature is enabled by default. | |||
+.. index:: clear ip ospf [(1-65535)] process | |||
+.. clicmd:: clear ip ospf [(1-65535)] process | |||
+ | |||
+ This command can be used to clear the ospf process data structures. This | |||
+ will clear the ospf neighborship as well and it will get re-established. | |||
+ This will clear the LSDB too. This will be helpful when there is a change | |||
+ in router-id and if user wants the router-id change to take effect, user can | |||
+ use this cli instead of restarting the ospfd daemon. | |||
+ | |||
+.. index:: clear ip ospf [(1-65535)] neighbor | |||
+.. clicmd:: clear ip ospf [(1-65535)] neighbor | |||
+ | |||
+ This command can be used to clear the ospf neighbor data structures. This | |||
+ will clear the ospf neighborship and it will get re-established. This | |||
+ command can be used when the neighbor state get stuck at some state and | |||
+ this can be used to recover it from that state. | |||
+ | |||
.. _ospf-area: | |||
Areas | |||
--- a/ospfd/ospf_ase.c | |||
+++ b/ospfd/ospf_ase.c | |||
@@ -753,6 +753,7 @@ void ospf_ase_unregister_external_lsa(st | |||
lst = rn->info; | |||
listnode_delete(lst, lsa); | |||
ospf_lsa_unlock(&lsa); /* external_lsas list */ | |||
+ | |||
route_unlock_node(rn); | |||
} | |||
} | |||
--- a/ospfd/ospf_lsa.c | |||
+++ b/ospfd/ospf_lsa.c | |||
@@ -2735,7 +2735,7 @@ int ospf_check_nbr_status(struct ospf *o | |||
static int ospf_maxage_lsa_remover(struct thread *thread) | |||
{ | |||
struct ospf *ospf = THREAD_ARG(thread); | |||
- struct ospf_lsa *lsa; | |||
+ struct ospf_lsa *lsa, *old; | |||
struct route_node *rn; | |||
int reschedule = 0; | |||
@@ -2797,6 +2797,17 @@ static int ospf_maxage_lsa_remover(struc | |||
/* Remove from lsdb. */ | |||
if (lsa->lsdb) { | |||
+ old = ospf_lsdb_lookup(lsa->lsdb, lsa); | |||
+ /* The max age LSA here must be the same | |||
+ * as the LSA in LSDB | |||
+ */ | |||
+ if (old != lsa) { | |||
+ flog_err(EC_OSPF_LSA_MISSING, | |||
+ "%s: LSA[Type%d:%s]: LSA not in LSDB", | |||
+ __func__, lsa->data->type, | |||
+ inet_ntoa(lsa->data->id)); | |||
+ continue; | |||
+ } | |||
ospf_discard_from_db(ospf, lsa->lsdb, lsa); | |||
ospf_lsdb_delete(lsa->lsdb, lsa); | |||
} else { | |||
--- a/ospfd/ospf_vty.c | |||
+++ b/ospfd/ospf_vty.c | |||
@@ -276,7 +276,7 @@ DEFPY (ospf_router_id, | |||
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) | |||
if (area->full_nbrs) { | |||
vty_out(vty, | |||
- "For this router-id change to take effect, save config and restart ospfd\n"); | |||
+ "For this router-id change to take effect, use “clear ip ospf process” command\n"); | |||
return CMD_SUCCESS; | |||
} | |||
@@ -309,7 +309,7 @@ DEFUN_HIDDEN (ospf_router_id_old, | |||
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) | |||
if (area->full_nbrs) { | |||
vty_out(vty, | |||
- "For this router-id change to take effect, save config and restart ospfd\n"); | |||
+ "For this router-id change to take effect, use “clear ip ospf process” command\n"); | |||
return CMD_SUCCESS; | |||
} | |||
@@ -342,7 +342,7 @@ DEFPY (no_ospf_router_id, | |||
for (ALL_LIST_ELEMENTS_RO(ospf->areas, node, area)) | |||
if (area->full_nbrs) { | |||
vty_out(vty, | |||
- "For this router-id change to take effect, save config and restart ospfd\n"); | |||
+ "For this router-id change to take effect, use “clear ip ospf process” command\n"); | |||
return CMD_SUCCESS; | |||
} | |||
@@ -9769,6 +9769,70 @@ DEFUN (show_ip_ospf_vrfs, | |||
return CMD_SUCCESS; | |||
} | |||
+DEFPY (clear_ip_ospf_neighbor, | |||
+ clear_ip_ospf_neighbor_cmd, | |||
+ "clear ip ospf [(1-65535)]$instance neighbor [A.B.C.D$nbr_id]", | |||
+ CLEAR_STR | |||
+ IP_STR | |||
+ "OSPF information\n" | |||
+ "Instance ID\n" | |||
+ "Reset OSPF Neighbor\n" | |||
+ "Neighbor ID\n") | |||
+{ | |||
+ struct listnode *node; | |||
+ struct ospf *ospf = NULL; | |||
+ | |||
+ /* If user does not specify the arguments, | |||
+ * instance = 0 and nbr_id = 0.0.0.0 | |||
+ */ | |||
+ if (instance != 0) { | |||
+ /* This means clear only the particular ospf process */ | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (ospf == NULL) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
+ } | |||
+ | |||
+ /* Clear all the ospf processes */ | |||
+ for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { | |||
+ if (!ospf->oi_running) | |||
+ continue; | |||
+ | |||
+ ospf_neighbor_reset(ospf, nbr_id, nbr_id_str); | |||
+ } | |||
+ | |||
+ return CMD_SUCCESS; | |||
+} | |||
+ | |||
+DEFPY (clear_ip_ospf_process, | |||
+ clear_ip_ospf_process_cmd, | |||
+ "clear ip ospf [(1-65535)]$instance process", | |||
+ CLEAR_STR | |||
+ IP_STR | |||
+ "OSPF information\n" | |||
+ "Instance ID\n" | |||
+ "Reset OSPF Process\n") | |||
+{ | |||
+ struct listnode *node; | |||
+ struct ospf *ospf = NULL; | |||
+ | |||
+ /* Check if instance is not passed as an argument */ | |||
+ if (instance != 0) { | |||
+ /* This means clear only the particular ospf process */ | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (ospf == NULL) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
+ } | |||
+ | |||
+ /* Clear all the ospf processes */ | |||
+ for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { | |||
+ if (!ospf->oi_running) | |||
+ continue; | |||
+ | |||
+ ospf_process_reset(ospf); | |||
+ } | |||
+ | |||
+ return CMD_SUCCESS; | |||
+} | |||
static const char *const ospf_abr_type_str[] = { | |||
"unknown", "standard", "ibm", "cisco", "shortcut" | |||
@@ -10806,6 +10870,8 @@ DEFUN (clear_ip_ospf_interface, | |||
void ospf_vty_clear_init(void) | |||
{ | |||
install_element(ENABLE_NODE, &clear_ip_ospf_interface_cmd); | |||
+ install_element(ENABLE_NODE, &clear_ip_ospf_process_cmd); | |||
+ install_element(ENABLE_NODE, &clear_ip_ospf_neighbor_cmd); | |||
} | |||
--- a/ospfd/ospfd.c | |||
+++ b/ospfd/ospfd.c | |||
@@ -84,13 +84,15 @@ static void ospf_finish_final(struct osp | |||
#define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1 | |||
-void ospf_router_id_update(struct ospf *ospf) | |||
+void ospf_process_refresh_data(struct ospf *ospf, bool reset) | |||
{ | |||
struct vrf *vrf = vrf_lookup_by_id(ospf->vrf_id); | |||
struct in_addr router_id, router_id_old; | |||
struct ospf_interface *oi; | |||
struct interface *ifp; | |||
- struct listnode *node; | |||
+ struct listnode *node, *nnode; | |||
+ struct ospf_area *area; | |||
+ bool rid_change = false; | |||
if (!ospf->oi_running) { | |||
if (IS_DEBUG_OSPF_EVENT) | |||
@@ -123,8 +125,8 @@ void ospf_router_id_update(struct ospf * | |||
zlog_debug("Router-ID[OLD:%s]: Update to %s", | |||
inet_ntoa(ospf->router_id), inet_ntoa(router_id)); | |||
- if (!IPV4_ADDR_SAME(&router_id_old, &router_id)) { | |||
- | |||
+ rid_change = !(IPV4_ADDR_SAME(&router_id_old, &router_id)); | |||
+ if (rid_change || (reset)) { | |||
for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { | |||
/* Some nbrs are identified by router_id, these needs | |||
* to be rebuilt. Possible optimization would be to do | |||
@@ -146,16 +148,8 @@ void ospf_router_id_update(struct ospf * | |||
ospf_if_up(oi); | |||
} | |||
- /* Flush (inline) all external LSAs based on the OSPF_LSA_SELF | |||
- * flag */ | |||
- if (ospf->lsdb) { | |||
- struct route_node *rn; | |||
- struct ospf_lsa *lsa; | |||
- | |||
- LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) | |||
- if (IS_LSA_SELF(lsa)) | |||
- ospf_lsa_flush_schedule(ospf, lsa); | |||
- } | |||
+ /* Flush (inline) all the self originated LSAs */ | |||
+ ospf_flush_self_originated_lsas_now(ospf); | |||
ospf->router_id = router_id; | |||
if (IS_DEBUG_OSPF_EVENT) | |||
@@ -180,24 +174,81 @@ void ospf_router_id_update(struct ospf * | |||
LSDB_LOOP (EXTERNAL_LSDB(ospf), rn, lsa) { | |||
/* AdvRouter and Router ID is the same. */ | |||
if (IPV4_ADDR_SAME(&lsa->data->adv_router, | |||
- &ospf->router_id)) { | |||
+ &ospf->router_id) && rid_change) { | |||
SET_FLAG(lsa->flags, | |||
OSPF_LSA_SELF_CHECKED); | |||
SET_FLAG(lsa->flags, OSPF_LSA_SELF); | |||
ospf_lsa_flush_schedule(ospf, lsa); | |||
} | |||
+ /* The above flush will send immediately | |||
+ * So discard the LSA to originate new | |||
+ */ | |||
+ ospf_discard_from_db(ospf, ospf->lsdb, lsa); | |||
} | |||
+ | |||
+ LSDB_LOOP (OPAQUE_AS_LSDB(ospf), rn, lsa) | |||
+ ospf_discard_from_db(ospf, ospf->lsdb, lsa); | |||
+ | |||
+ ospf_lsdb_delete_all(ospf->lsdb); | |||
} | |||
+ /* Delete the LSDB */ | |||
+ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) | |||
+ ospf_area_lsdb_discard_delete(area); | |||
+ | |||
/* update router-lsa's for each area */ | |||
ospf_router_lsa_update(ospf); | |||
/* update ospf_interface's */ | |||
- FOR_ALL_INTERFACES (vrf, ifp) | |||
- ospf_if_update(ospf, ifp); | |||
+ FOR_ALL_INTERFACES (vrf, ifp) { | |||
+ if (reset) | |||
+ ospf_if_reset(ifp); | |||
+ else | |||
+ ospf_if_update(ospf, ifp); | |||
+ } | |||
ospf_external_lsa_rid_change(ospf); | |||
} | |||
+ | |||
+ ospf->inst_shutdown = 0; | |||
+} | |||
+ | |||
+void ospf_router_id_update(struct ospf *ospf) | |||
+{ | |||
+ ospf_process_refresh_data(ospf, false); | |||
+} | |||
+ | |||
+void ospf_process_reset(struct ospf *ospf) | |||
+{ | |||
+ ospf_process_refresh_data(ospf, true); | |||
+} | |||
+ | |||
+void ospf_neighbor_reset(struct ospf *ospf, struct in_addr nbr_id, | |||
+ const char *nbr_str) | |||
+{ | |||
+ struct route_node *rn; | |||
+ struct ospf_neighbor *nbr; | |||
+ struct ospf_interface *oi; | |||
+ struct listnode *node; | |||
+ | |||
+ /* Clear only a particular nbr with nbr router id as nbr_id */ | |||
+ if (nbr_str != NULL) { | |||
+ for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { | |||
+ nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, &nbr_id); | |||
+ if (nbr) | |||
+ OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); | |||
+ } | |||
+ return; | |||
+ } | |||
+ | |||
+ /* send Neighbor event KillNbr to all associated neighbors. */ | |||
+ for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { | |||
+ for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { | |||
+ nbr = rn->info; | |||
+ if (nbr && (nbr != oi->nbr_self)) | |||
+ OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); | |||
+ } | |||
+ } | |||
} | |||
/* For OSPF area sort by area id. */ | |||
@@ -826,14 +877,11 @@ static struct ospf_area *ospf_area_new(s | |||
return new; | |||
} | |||
-static void ospf_area_free(struct ospf_area *area) | |||
+void ospf_area_lsdb_discard_delete(struct ospf_area *area) | |||
{ | |||
struct route_node *rn; | |||
struct ospf_lsa *lsa; | |||
- ospf_opaque_type10_lsa_term(area); | |||
- | |||
- /* Free LSDBs. */ | |||
LSDB_LOOP (ROUTER_LSDB(area), rn, lsa) | |||
ospf_discard_from_db(area->ospf, area->lsdb, lsa); | |||
LSDB_LOOP (NETWORK_LSDB(area), rn, lsa) | |||
@@ -851,6 +899,15 @@ static void ospf_area_free(struct ospf_a | |||
ospf_discard_from_db(area->ospf, area->lsdb, lsa); | |||
ospf_lsdb_delete_all(area->lsdb); | |||
+} | |||
+ | |||
+static void ospf_area_free(struct ospf_area *area) | |||
+{ | |||
+ ospf_opaque_type10_lsa_term(area); | |||
+ | |||
+ /* Free LSDBs. */ | |||
+ ospf_area_lsdb_discard_delete(area); | |||
+ | |||
ospf_lsdb_free(area->lsdb); | |||
ospf_lsa_unlock(&area->router_lsa_self); | |||
--- a/ospfd/ospfd.h | |||
+++ b/ospfd/ospfd.h | |||
@@ -519,7 +519,11 @@ extern struct ospf *ospf_lookup_by_inst_ | |||
extern struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id); | |||
extern uint32_t ospf_count_area_params(struct ospf *ospf); | |||
extern void ospf_finish(struct ospf *); | |||
+extern void ospf_process_refresh_data(struct ospf *ospf, bool reset); | |||
extern void ospf_router_id_update(struct ospf *ospf); | |||
+extern void ospf_process_reset(struct ospf *ospf); | |||
+extern void ospf_neighbor_reset(struct ospf *ospf, struct in_addr nbr_id, | |||
+ const char *nbr_str); | |||
extern int ospf_network_set(struct ospf *, struct prefix_ipv4 *, struct in_addr, | |||
int); | |||
extern int ospf_network_unset(struct ospf *, struct prefix_ipv4 *, | |||
@@ -544,6 +548,7 @@ extern int ospf_area_shortcut_set(struct | |||
extern int ospf_area_shortcut_unset(struct ospf *, struct ospf_area *); | |||
extern int ospf_timers_refresh_set(struct ospf *, int); | |||
extern int ospf_timers_refresh_unset(struct ospf *); | |||
+void ospf_area_lsdb_discard_delete(struct ospf_area *area); | |||
extern int ospf_nbr_nbma_set(struct ospf *, struct in_addr); | |||
extern int ospf_nbr_nbma_unset(struct ospf *, struct in_addr); | |||
extern int ospf_nbr_nbma_priority_set(struct ospf *, struct in_addr, uint8_t); |
@ -1,105 +0,0 @@ | |||
From 153bdb3d03542530ed1deccbefc716cb4b699a67 Mon Sep 17 00:00:00 2001 | |||
From: Donald Sharp <sharpd@nvidia.com> | |||
Date: Thu, 28 Jan 2021 14:56:11 -0500 | |||
Subject: [PATCH] ospfd: ospf_nbr_nbma_lookup_next always returns NULL | |||
The calling function of ospf_nbr_nbma_lookup_next calls | |||
this function and then immediately returns when it | |||
gets the NULL. Just cleanup a bit more code. | |||
Signed-off-by: Donald Sharp <sharpd@nvidia.com> | |||
--- | |||
ospfd/ospf_snmp.c | 23 +---------------------- | |||
ospfd/ospfd.c | 9 --------- | |||
ospfd/ospfd.h | 2 -- | |||
3 files changed, 1 insertion(+), 33 deletions(-) | |||
--- a/ospfd/ospf_snmp.c | |||
+++ b/ospfd/ospf_snmp.c | |||
@@ -1236,7 +1236,6 @@ static struct ospf_nbr_nbma *ospfHostLoo | |||
size_t *length, | |||
struct in_addr *addr, int exact) | |||
{ | |||
- int len; | |||
struct ospf_nbr_nbma *nbr_nbma; | |||
struct ospf *ospf; | |||
@@ -1258,28 +1257,8 @@ static struct ospf_nbr_nbma *ospfHostLoo | |||
nbr_nbma = ospf_nbr_nbma_lookup(ospf, *addr); | |||
return nbr_nbma; | |||
- } else { | |||
- len = *length - v->namelen; | |||
- if (len > 4) | |||
- len = 4; | |||
- | |||
- oid2in_addr(name + v->namelen, len, addr); | |||
- | |||
- nbr_nbma = | |||
- ospf_nbr_nbma_lookup_next(ospf, addr, len == 0 ? 1 : 0); | |||
- | |||
- if (nbr_nbma == NULL) | |||
- return NULL; | |||
- | |||
- oid_copy_addr(name + v->namelen, addr, IN_ADDR_SIZE); | |||
- | |||
- /* Set TOS 0. */ | |||
- name[v->namelen + IN_ADDR_SIZE] = 0; | |||
- | |||
- *length = v->namelen + IN_ADDR_SIZE + 1; | |||
- | |||
- return nbr_nbma; | |||
} | |||
+ | |||
return NULL; | |||
} | |||
--- a/ospfd/ospfd.c | |||
+++ b/ospfd/ospfd.c | |||
@@ -1919,35 +1919,6 @@ struct ospf_nbr_nbma *ospf_nbr_nbma_look | |||
return NULL; | |||
} | |||
-struct ospf_nbr_nbma *ospf_nbr_nbma_lookup_next(struct ospf *ospf, | |||
- struct in_addr *addr, int first) | |||
-{ | |||
-#if 0 | |||
- struct ospf_nbr_nbma *nbr_nbma; | |||
- struct listnode *node; | |||
-#endif | |||
- | |||
- if (ospf == NULL) | |||
- return NULL; | |||
- | |||
-#if 0 | |||
- for (ALL_LIST_ELEMENTS_RO (ospf->nbr_nbma, node, nbr_nbma)) | |||
- { | |||
- if (first) | |||
- { | |||
- *addr = nbr_nbma->addr; | |||
- return nbr_nbma; | |||
- } | |||
- else if (ntohl (nbr_nbma->addr.s_addr) > ntohl (addr->s_addr)) | |||
- { | |||
- *addr = nbr_nbma->addr; | |||
- return nbr_nbma; | |||
- } | |||
- } | |||
-#endif | |||
- return NULL; | |||
-} | |||
- | |||
int ospf_nbr_nbma_set(struct ospf *ospf, struct in_addr nbr_addr) | |||
{ | |||
struct ospf_nbr_nbma *nbr_nbma; | |||
--- a/ospfd/ospfd.h | |||
+++ b/ospfd/ospfd.h | |||
@@ -563,8 +563,6 @@ extern void ospf_terminate(void); | |||
extern void ospf_nbr_nbma_if_update(struct ospf *, struct ospf_interface *); | |||
extern struct ospf_nbr_nbma *ospf_nbr_nbma_lookup(struct ospf *, | |||
struct in_addr); | |||
-extern struct ospf_nbr_nbma *ospf_nbr_nbma_lookup_next(struct ospf *, | |||
- struct in_addr *, int); | |||
extern int ospf_oi_count(struct interface *); | |||
extern struct ospf_area *ospf_area_get(struct ospf *, struct in_addr); |
@ -1,797 +0,0 @@ | |||
From 409f98ab443682ec360e3e76954f1c8985b3371d Mon Sep 17 00:00:00 2001 | |||
From: Igor Ryzhov <iryzhov@nfware.com> | |||
Date: Thu, 28 Jan 2021 02:41:07 +0300 | |||
Subject: [PATCH 1/2] ospfd: don't rely on instance existence in vty | |||
Store instance index at startup and use it when processing vty commands. | |||
The instance itself may be created and deleted by the user in runtime | |||
using `[no] router ospf X` command. | |||
Fixes #7908 | |||
Signed-off-by: Igor Ryzhov <iryzhov@nfware.com> | |||
--- | |||
ospfd/ospf_dump.c | 70 ++++++--------- | |||
ospfd/ospf_main.c | 20 +---- | |||
ospfd/ospf_vty.c | 220 +++++++++++++++++++++++----------------------- | |||
ospfd/ospfd.c | 26 +++--- | |||
ospfd/ospfd.h | 3 +- | |||
5 files changed, 154 insertions(+), 185 deletions(-) | |||
--- a/ospfd/ospf_dump.c | |||
+++ b/ospfd/ospf_dump.c | |||
@@ -607,7 +607,7 @@ DEFUN (debug_ospf_packet, | |||
if (inst) // user passed instance ID | |||
{ | |||
- if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10))) | |||
+ if (inst != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
} | |||
@@ -683,7 +683,7 @@ DEFUN (no_debug_ospf_packet, | |||
if (inst) // user passed instance ID | |||
{ | |||
- if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10))) | |||
+ if (inst != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
} | |||
@@ -754,7 +754,7 @@ DEFUN (debug_ospf_ism, | |||
if (inst) // user passed instance ID | |||
{ | |||
- if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10))) | |||
+ if (inst != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
} | |||
@@ -805,7 +805,7 @@ DEFUN (no_debug_ospf_ism, | |||
if (inst) // user passed instance ID | |||
{ | |||
- if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10))) | |||
+ if (inst != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
} | |||
@@ -900,8 +900,8 @@ DEFUN (debug_ospf_instance_nsm, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
- return CMD_SUCCESS; | |||
+ if (instance != ospf_instance) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
return debug_ospf_nsm_common(vty, 4, argc, argv); | |||
} | |||
@@ -972,7 +972,7 @@ DEFUN (no_debug_ospf_instance_nsm, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
return no_debug_ospf_nsm_common(vty, 5, argc, argv); | |||
@@ -1046,7 +1046,7 @@ DEFUN (debug_ospf_instance_lsa, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
return debug_ospf_lsa_common(vty, 4, argc, argv); | |||
@@ -1122,7 +1122,7 @@ DEFUN (no_debug_ospf_instance_lsa, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
return no_debug_ospf_lsa_common(vty, 5, argc, argv); | |||
@@ -1184,7 +1184,7 @@ DEFUN (debug_ospf_instance_zebra, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
return debug_ospf_zebra_common(vty, 4, argc, argv); | |||
@@ -1248,8 +1248,8 @@ DEFUN (no_debug_ospf_instance_zebra, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
- return CMD_SUCCESS; | |||
+ if (instance != ospf_instance) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
return no_debug_ospf_zebra_common(vty, 5, argc, argv); | |||
} | |||
@@ -1294,8 +1294,8 @@ DEFUN (debug_ospf_instance_event, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
- return CMD_SUCCESS; | |||
+ if (instance != ospf_instance) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
if (vty->node == CONFIG_NODE) | |||
CONF_DEBUG_ON(event, EVENT); | |||
@@ -1316,8 +1316,8 @@ DEFUN (no_debug_ospf_instance_event, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
- return CMD_SUCCESS; | |||
+ if (instance != ospf_instance) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
if (vty->node == CONFIG_NODE) | |||
CONF_DEBUG_OFF(event, EVENT); | |||
@@ -1364,8 +1364,8 @@ DEFUN (debug_ospf_instance_nssa, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
- return CMD_SUCCESS; | |||
+ if (instance != ospf_instance) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
if (vty->node == CONFIG_NODE) | |||
CONF_DEBUG_ON(nssa, NSSA); | |||
@@ -1386,8 +1386,8 @@ DEFUN (no_debug_ospf_instance_nssa, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if (!ospf_lookup_instance(instance)) | |||
- return CMD_SUCCESS; | |||
+ if (instance != ospf_instance) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
if (vty->node == CONFIG_NODE) | |||
CONF_DEBUG_OFF(nssa, NSSA); | |||
@@ -1536,12 +1536,12 @@ DEFUN (no_debug_ospf, | |||
return CMD_SUCCESS; | |||
} | |||
-static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf) | |||
+static int show_debugging_ospf_common(struct vty *vty) | |||
{ | |||
int i; | |||
- if (ospf->instance) | |||
- vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); | |||
+ if (ospf_instance) | |||
+ vty_out(vty, "\nOSPF Instance: %d\n\n", ospf_instance); | |||
vty_out(vty, "OSPF debugging status:\n"); | |||
@@ -1645,13 +1645,7 @@ DEFUN_NOSH (show_debugging_ospf, | |||
DEBUG_STR | |||
OSPF_STR) | |||
{ | |||
- struct ospf *ospf = NULL; | |||
- | |||
- ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); | |||
- if (ospf == NULL) | |||
- return CMD_SUCCESS; | |||
- | |||
- return show_debugging_ospf_common(vty, ospf); | |||
+ return show_debugging_ospf_common(vty); | |||
} | |||
DEFUN_NOSH (show_debugging_ospf_instance, | |||
@@ -1663,14 +1657,13 @@ DEFUN_NOSH (show_debugging_ospf_instance | |||
"Instance ID\n") | |||
{ | |||
int idx_number = 3; | |||
- struct ospf *ospf; | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- if ((ospf = ospf_lookup_instance(instance)) == NULL) | |||
- return CMD_SUCCESS; | |||
+ if (instance != ospf_instance) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
- return show_debugging_ospf_common(vty, ospf); | |||
+ return show_debugging_ospf_common(vty); | |||
} | |||
static int config_write_debug(struct vty *vty); | |||
@@ -1693,16 +1686,11 @@ static int config_write_debug(struct vty | |||
"", " send", " recv", "", | |||
" detail", " send detail", " recv detail", " detail"}; | |||
- struct ospf *ospf; | |||
char str[16]; | |||
memset(str, 0, 16); | |||
- ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); | |||
- if (ospf == NULL) | |||
- return CMD_SUCCESS; | |||
- | |||
- if (ospf->instance) | |||
- snprintf(str, sizeof(str), " %u", ospf->instance); | |||
+ if (ospf_instance) | |||
+ snprintf(str, sizeof(str), " %u", ospf_instance); | |||
/* debug ospf ism (status|events|timers). */ | |||
if (IS_CONF_DEBUG_OSPF(ism, ISM) == OSPF_DEBUG_ISM) | |||
--- a/ospfd/ospf_main.c | |||
+++ b/ospfd/ospf_main.c | |||
@@ -145,9 +145,6 @@ FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = | |||
/* OSPFd main routine. */ | |||
int main(int argc, char **argv) | |||
{ | |||
- unsigned short instance = 0; | |||
- bool created = false; | |||
- | |||
#ifdef SUPPORT_OSPF_API | |||
/* OSPF apiserver is disabled by default. */ | |||
ospf_apiserver_enable = 0; | |||
@@ -168,8 +165,8 @@ int main(int argc, char **argv) | |||
switch (opt) { | |||
case 'n': | |||
- ospfd_di.instance = instance = atoi(optarg); | |||
- if (instance < 1) | |||
+ ospfd_di.instance = ospf_instance = atoi(optarg); | |||
+ if (ospf_instance < 1) | |||
exit(0); | |||
break; | |||
case 0: | |||
@@ -207,7 +204,7 @@ int main(int argc, char **argv) | |||
/* OSPFd inits. */ | |||
ospf_if_init(); | |||
- ospf_zebra_init(master, instance); | |||
+ ospf_zebra_init(master, ospf_instance); | |||
/* OSPF vty inits. */ | |||
ospf_vty_init(); | |||
@@ -223,17 +220,6 @@ int main(int argc, char **argv) | |||
/* OSPF errors init */ | |||
ospf_error_init(); | |||
- /* | |||
- * Need to initialize the default ospf structure, so the interface mode | |||
- * commands can be duly processed if they are received before 'router | |||
- * ospf', when ospfd is restarted | |||
- */ | |||
- if (instance && !ospf_get_instance(instance, &created)) { | |||
- flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s", | |||
- strerror(errno)); | |||
- exit(1); | |||
- } | |||
- | |||
frr_config_fork(); | |||
frr_run(master); | |||
--- a/ospfd/ospf_vty.c | |||
+++ b/ospfd/ospf_vty.c | |||
@@ -136,44 +136,37 @@ int ospf_oi_count(struct interface *ifp) | |||
all_vrf = strmatch(vrf_name, "all"); \ | |||
} | |||
-static struct ospf *ospf_cmd_lookup_ospf(struct vty *vty, | |||
- struct cmd_token *argv[], | |||
- const int argc, uint32_t enable, | |||
- unsigned short *instance) | |||
+static int ospf_router_cmd_parse(struct vty *vty, struct cmd_token *argv[], | |||
+ const int argc, unsigned short *instance, | |||
+ const char **vrf_name) | |||
{ | |||
- struct ospf *ospf = NULL; | |||
int idx_vrf = 0, idx_inst = 0; | |||
- const char *vrf_name = NULL; | |||
- bool created = false; | |||
*instance = 0; | |||
- if (argv_find(argv, argc, "(1-65535)", &idx_inst)) | |||
+ if (argv_find(argv, argc, "(1-65535)", &idx_inst)) { | |||
+ if (ospf_instance == 0) { | |||
+ vty_out(vty, | |||
+ "%% OSPF is not running in instance mode\n"); | |||
+ return CMD_WARNING_CONFIG_FAILED; | |||
+ } | |||
+ | |||
*instance = strtoul(argv[idx_inst]->arg, NULL, 10); | |||
+ } | |||
+ *vrf_name = NULL; | |||
if (argv_find(argv, argc, "vrf", &idx_vrf)) { | |||
- vrf_name = argv[idx_vrf + 1]->arg; | |||
- if (vrf_name == NULL || strmatch(vrf_name, VRF_DEFAULT_NAME)) | |||
- vrf_name = NULL; | |||
- if (enable) { | |||
- /* Allocate VRF aware instance */ | |||
- ospf = ospf_get(*instance, vrf_name, &created); | |||
- } else { | |||
- ospf = ospf_lookup_by_inst_name(*instance, vrf_name); | |||
- } | |||
- } else { | |||
- if (enable) { | |||
- ospf = ospf_get(*instance, NULL, &created); | |||
- } else { | |||
- ospf = ospf_lookup_instance(*instance); | |||
+ if (ospf_instance != 0) { | |||
+ vty_out(vty, | |||
+ "%% VRF is not supported in instance mode\n"); | |||
+ return CMD_WARNING_CONFIG_FAILED; | |||
} | |||
- } | |||
- if (created) { | |||
- if (DFLT_OSPF_LOG_ADJACENCY_CHANGES) | |||
- SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); | |||
+ *vrf_name = argv[idx_vrf + 1]->arg; | |||
+ if (*vrf_name && strmatch(*vrf_name, VRF_DEFAULT_NAME)) | |||
+ *vrf_name = NULL; | |||
} | |||
- return ospf; | |||
+ return CMD_SUCCESS; | |||
} | |||
static void ospf_show_vrf_name(struct ospf *ospf, struct vty *vty, | |||
@@ -209,28 +202,35 @@ DEFUN_NOSH (router_ospf, | |||
"Instance ID\n" | |||
VRF_CMD_HELP_STR) | |||
{ | |||
- struct ospf *ospf = NULL; | |||
- int ret = CMD_SUCCESS; | |||
- unsigned short instance = 0; | |||
+ unsigned short instance; | |||
+ const char *vrf_name; | |||
+ bool created = false; | |||
+ struct ospf *ospf; | |||
+ int ret; | |||
- ospf = ospf_cmd_lookup_ospf(vty, argv, argc, 1, &instance); | |||
- if (!ospf) | |||
- return CMD_WARNING_CONFIG_FAILED; | |||
+ ret = ospf_router_cmd_parse(vty, argv, argc, &instance, &vrf_name); | |||
+ if (ret != CMD_SUCCESS) | |||
+ return ret; | |||
- /* The following logic to set the vty qobj index is in place to be able | |||
- to ignore the commands which dont belong to this instance. */ | |||
- if (ospf->instance != instance) { | |||
+ if (instance != ospf_instance) { | |||
VTY_PUSH_CONTEXT_NULL(OSPF_NODE); | |||
- ret = CMD_NOT_MY_INSTANCE; | |||
- } else { | |||
- if (IS_DEBUG_OSPF_EVENT) | |||
- zlog_debug( | |||
- "Config command 'router ospf %d' received, vrf %s id %u oi_running %u", | |||
- instance, ospf->name ? ospf->name : "NIL", | |||
- ospf->vrf_id, ospf->oi_running); | |||
- VTY_PUSH_CONTEXT(OSPF_NODE, ospf); | |||
+ return CMD_NOT_MY_INSTANCE; | |||
} | |||
+ ospf = ospf_get(instance, vrf_name, &created); | |||
+ | |||
+ if (created) | |||
+ if (DFLT_OSPF_LOG_ADJACENCY_CHANGES) | |||
+ SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); | |||
+ | |||
+ if (IS_DEBUG_OSPF_EVENT) | |||
+ zlog_debug( | |||
+ "Config command 'router ospf %d' received, vrf %s id %u oi_running %u", | |||
+ ospf->instance, ospf->name ? ospf->name : "NIL", | |||
+ ospf->vrf_id, ospf->oi_running); | |||
+ | |||
+ VTY_PUSH_CONTEXT(OSPF_NODE, ospf); | |||
+ | |||
return ret; | |||
} | |||
@@ -243,19 +243,25 @@ DEFUN (no_router_ospf, | |||
"Instance ID\n" | |||
VRF_CMD_HELP_STR) | |||
{ | |||
+ unsigned short instance; | |||
+ const char *vrf_name; | |||
struct ospf *ospf; | |||
- unsigned short instance = 0; | |||
+ int ret; | |||
- ospf = ospf_cmd_lookup_ospf(vty, argv, argc, 0, &instance); | |||
- if (ospf == NULL) { | |||
- if (instance) | |||
- return CMD_NOT_MY_INSTANCE; | |||
- else | |||
- return CMD_WARNING; | |||
- } | |||
- ospf_finish(ospf); | |||
+ ret = ospf_router_cmd_parse(vty, argv, argc, &instance, &vrf_name); | |||
+ if (ret != CMD_SUCCESS) | |||
+ return ret; | |||
- return CMD_SUCCESS; | |||
+ if (instance != ospf_instance) | |||
+ return CMD_NOT_MY_INSTANCE; | |||
+ | |||
+ ospf = ospf_lookup(instance, vrf_name); | |||
+ if (ospf) | |||
+ ospf_finish(ospf); | |||
+ else | |||
+ ret = CMD_WARNING_CONFIG_FAILED; | |||
+ | |||
+ return ret; | |||
} | |||
@@ -3326,11 +3332,11 @@ DEFUN (show_ip_ospf_instance, | |||
json_object *json = NULL; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
if (uj) | |||
@@ -4016,11 +4022,11 @@ DEFUN (show_ip_ospf_instance_interface, | |||
json_object *json = NULL; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
if (uj) | |||
@@ -4409,11 +4415,11 @@ DEFUN (show_ip_ospf_instance_neighbor, | |||
int ret = CMD_SUCCESS; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
if (uj) | |||
@@ -4621,11 +4627,11 @@ DEFUN (show_ip_ospf_instance_neighbor_al | |||
int ret = CMD_SUCCESS; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
if (uj) | |||
json = json_object_new_object(); | |||
@@ -4761,11 +4767,11 @@ DEFUN (show_ip_ospf_instance_neighbor_in | |||
show_ip_ospf_neighbour_header(vty); | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
if (!uj) | |||
@@ -5170,11 +5176,11 @@ DEFPY (show_ip_ospf_instance_neighbor_id | |||
{ | |||
struct ospf *ospf; | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
return show_ip_ospf_neighbor_id_common(vty, ospf, &router_id, !!json, | |||
@@ -5343,11 +5349,11 @@ DEFUN (show_ip_ospf_instance_neighbor_de | |||
int ret = CMD_SUCCESS; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
if (uj) | |||
@@ -5538,11 +5544,11 @@ DEFUN (show_ip_ospf_instance_neighbor_de | |||
int ret = CMD_SUCCESS; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
if (uj) | |||
@@ -5670,11 +5676,11 @@ DEFUN (show_ip_ospf_instance_neighbor_in | |||
bool uj = use_json(argc, argv); | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
return show_ip_ospf_neighbor_int_detail_common(vty, ospf, idx_ifname, | |||
@@ -6420,10 +6426,11 @@ DEFUN (show_ip_ospf_instance_database, | |||
if (argv_find(argv, argc, "(1-65535)", &idx)) { | |||
instance = strtoul(argv[idx]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
return (show_ip_ospf_database_common(vty, ospf, idx ? 1 : 0, | |||
@@ -6484,15 +6491,12 @@ DEFUN (show_ip_ospf_instance_database_ma | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) { | |||
- vty_out(vty, "%% OSPF instance not found\n"); | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
- } | |||
return show_ip_ospf_database_common(vty, ospf, 1, argc, argv, 0); | |||
} | |||
@@ -6578,13 +6582,12 @@ DEFUN (show_ip_ospf_instance_database_ty | |||
if (argv_find(argv, argc, "(1-65535)", &idx)) { | |||
instance = strtoul(argv[idx]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) { | |||
- vty_out(vty, "%% OSPF instance not found\n"); | |||
+ | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
- } | |||
return (show_ip_ospf_database_type_adv_router_common( | |||
vty, ospf, idx ? 1 : 0, argc, argv, use_vrf)); | |||
@@ -8035,7 +8038,7 @@ DEFUN (ip_ospf_area, | |||
else | |||
ospf = ospf_lookup_instance(instance); | |||
- if (instance && ospf == NULL) { | |||
+ if (instance && instance != ospf_instance) { | |||
/* | |||
* At this point we know we have received | |||
* an instance and there is no ospf instance | |||
@@ -8159,7 +8162,7 @@ DEFUN (no_ip_ospf_area, | |||
else | |||
ospf = ospf_lookup_instance(instance); | |||
- if (instance && ospf == NULL) | |||
+ if (instance && instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
argv_find(argv, argc, "area", &idx); | |||
@@ -9519,11 +9522,11 @@ DEFUN (show_ip_ospf_instance_border_rout | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
return show_ip_ospf_border_routers_common(vty, ospf, 0); | |||
@@ -9687,11 +9690,11 @@ DEFUN (show_ip_ospf_instance_route, | |||
unsigned short instance = 0; | |||
instance = strtoul(argv[idx_number]->arg, NULL, 10); | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
- if (!ospf->oi_running) | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ if (!ospf || !ospf->oi_running) | |||
return CMD_SUCCESS; | |||
return show_ip_ospf_route_common(vty, ospf, NULL, 0); | |||
@@ -9787,8 +9790,7 @@ DEFPY (clear_ip_ospf_neighbor, | |||
*/ | |||
if (instance != 0) { | |||
/* This means clear only the particular ospf process */ | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
} | |||
@@ -9818,8 +9820,7 @@ DEFPY (clear_ip_ospf_process, | |||
/* Check if instance is not passed as an argument */ | |||
if (instance != 0) { | |||
/* This means clear only the particular ospf process */ | |||
- ospf = ospf_lookup_instance(instance); | |||
- if (ospf == NULL) | |||
+ if (instance != ospf_instance) | |||
return CMD_NOT_MY_INSTANCE; | |||
} | |||
@@ -9860,7 +9861,6 @@ static int config_write_interface_one(st | |||
struct route_node *rn = NULL; | |||
struct ospf_if_params *params; | |||
int write = 0; | |||
- struct ospf *ospf = vrf->info; | |||
FOR_ALL_INTERFACES (vrf, ifp) { | |||
@@ -10039,9 +10039,9 @@ static int config_write_interface_one(st | |||
/* Area print. */ | |||
if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { | |||
- if (ospf && ospf->instance) | |||
+ if (ospf_instance) | |||
vty_out(vty, " ip ospf %d", | |||
- ospf->instance); | |||
+ ospf_instance); | |||
else | |||
vty_out(vty, " ip ospf"); | |||
--- a/ospfd/ospfd.c | |||
+++ b/ospfd/ospfd.c | |||
@@ -67,6 +67,8 @@ static struct ospf_master ospf_master; | |||
/* OSPF process wide configuration pointer to export. */ | |||
struct ospf_master *om; | |||
+unsigned short ospf_instance; | |||
+ | |||
extern struct zclient *zclient; | |||
@@ -438,36 +440,28 @@ static void ospf_init(struct ospf *ospf) | |||
ospf_router_id_update(ospf); | |||
} | |||
-struct ospf *ospf_get(unsigned short instance, const char *name, bool *created) | |||
+struct ospf *ospf_lookup(unsigned short instance, const char *name) | |||
{ | |||
struct ospf *ospf; | |||
- /* vrf name provided call inst and name based api | |||
- * in case of no name pass default ospf instance */ | |||
- if (name) | |||
+ if (ospf_instance) { | |||
+ ospf = ospf_lookup_instance(instance); | |||
+ } else { | |||
ospf = ospf_lookup_by_inst_name(instance, name); | |||
- else | |||
- ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); | |||
- | |||
- *created = (ospf == NULL); | |||
- if (ospf == NULL) { | |||
- ospf = ospf_new(instance, name); | |||
- ospf_add(ospf); | |||
- | |||
- ospf_init(ospf); | |||
} | |||
return ospf; | |||
} | |||
-struct ospf *ospf_get_instance(unsigned short instance, bool *created) | |||
+struct ospf *ospf_get(unsigned short instance, const char *name, bool *created) | |||
{ | |||
struct ospf *ospf; | |||
- ospf = ospf_lookup_instance(instance); | |||
+ ospf = ospf_lookup(instance, name); | |||
+ | |||
*created = (ospf == NULL); | |||
if (ospf == NULL) { | |||
- ospf = ospf_new(instance, NULL /* VRF_DEFAULT*/); | |||
+ ospf = ospf_new(instance, name); | |||
ospf_add(ospf); | |||
ospf_init(ospf); | |||
--- a/ospfd/ospfd.h | |||
+++ b/ospfd/ospfd.h | |||
@@ -502,6 +502,7 @@ struct ospf_nbr_nbma { | |||
/* Extern variables. */ | |||
extern struct ospf_master *om; | |||
+extern unsigned short ospf_instance; | |||
extern const int ospf_redistributed_proto_max; | |||
extern struct zclient *zclient; | |||
extern struct thread_master *master; | |||
@@ -511,9 +512,9 @@ extern struct zebra_privs_t ospfd_privs; | |||
/* Prototypes. */ | |||
extern const char *ospf_redist_string(unsigned int route_type); | |||
extern struct ospf *ospf_lookup_instance(unsigned short); | |||
+extern struct ospf *ospf_lookup(unsigned short instance, const char *name); | |||
extern struct ospf *ospf_get(unsigned short instance, const char *name, | |||
bool *created); | |||
-extern struct ospf *ospf_get_instance(unsigned short, bool *created); | |||
extern struct ospf *ospf_lookup_by_inst_name(unsigned short instance, | |||
const char *name); | |||
extern struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id); | |||
--- a/vtysh/vtysh.c | |||
+++ b/vtysh/vtysh.c | |||
@@ -2487,7 +2487,7 @@ static int show_per_daemon(const char *l | |||
int ret = CMD_SUCCESS; | |||
for (i = 0; i < array_size(vtysh_client); i++) | |||
- if (vtysh_client[i].fd >= 0) { | |||
+ if (vtysh_client[i].fd >= 0 || vtysh_client[i].next) { | |||
vty_out(vty, headline, vtysh_client[i].name); | |||
ret = vtysh_client_execute(&vtysh_client[i], line); | |||
vty_out(vty, "\n"); |
@ -1,964 +0,0 @@ | |||
From 6ea5d99456b14db5e82abc2461228bb37aa7556d Mon Sep 17 00:00:00 2001 | |||
From: Amol Lad <amol.lad@4rf.com> | |||
Date: Wed, 17 Feb 2021 13:47:32 +1300 | |||
Subject: [PATCH 01/14] nhrpd: Add support for forwarding multicast packets | |||
Forwarding multicast is a pre-requisite for allowing multicast based routing | |||
protocols such as OSPF to work with DMVPN | |||
This code relies on externally adding iptables rule. For example: | |||
iptables -A OUTPUT -d 224.0.0.0/24 -o gre1 -j NFLOG --nflog-group 224 | |||
Signed-off-by: Reuben Dowle <reuben.dowle@4rf.com> | |||
--- | |||
nhrpd/linux.c | 11 +- | |||
nhrpd/nhrp_interface.c | 2 + | |||
nhrpd/nhrp_multicast.c | 307 +++++++++++++++++++++++++++++++++++++++++ | |||
nhrpd/nhrp_peer.c | 3 +- | |||
nhrpd/nhrp_vty.c | 63 +++++++++ | |||
nhrpd/nhrpd.h | 16 +++ | |||
nhrpd/os.h | 2 +- | |||
nhrpd/subdir.am | 1 + | |||
8 files changed, 398 insertions(+), 7 deletions(-) | |||
create mode 100755 nhrpd/nhrp_multicast.c | |||
--- a/nhrpd/linux.c | |||
+++ b/nhrpd/linux.c | |||
@@ -15,6 +15,7 @@ | |||
#include <stdio.h> | |||
#include <unistd.h> | |||
#include <string.h> | |||
+#include <errno.h> | |||
#include <sys/ioctl.h> | |||
#include <sys/socket.h> | |||
#include <sys/types.h> | |||
@@ -31,6 +32,11 @@ | |||
#include "os.h" | |||
#include "netlink.h" | |||
+#ifndef HAVE_STRLCPY | |||
+size_t strlcpy(char *__restrict dest, | |||
+ const char *__restrict src, size_t destsize); | |||
+#endif | |||
+ | |||
static int nhrp_socket_fd = -1; | |||
int os_socket(void) | |||
@@ -42,7 +48,7 @@ int os_socket(void) | |||
} | |||
int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, | |||
- size_t addrlen) | |||
+ size_t addrlen, uint16_t protocol) | |||
{ | |||
struct sockaddr_ll lladdr; | |||
struct iovec iov = { | |||
@@ -61,16 +67,16 @@ int os_sendmsg(const uint8_t *buf, size_ | |||
memset(&lladdr, 0, sizeof(lladdr)); | |||
lladdr.sll_family = AF_PACKET; | |||
- lladdr.sll_protocol = htons(ETH_P_NHRP); | |||
+ lladdr.sll_protocol = htons(protocol); | |||
lladdr.sll_ifindex = ifindex; | |||
lladdr.sll_halen = addrlen; | |||
memcpy(lladdr.sll_addr, addr, addrlen); | |||
- status = sendmsg(nhrp_socket_fd, &msg, 0); | |||
+ status = sendmsg(os_socket(), &msg, 0); | |||
if (status < 0) | |||
- return -1; | |||
+ return -errno; | |||
- return 0; | |||
+ return status; | |||
} | |||
int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr, | |||
@@ -111,7 +117,7 @@ static int linux_configure_arp(const cha | |||
{ | |||
struct ifreq ifr; | |||
- strncpy(ifr.ifr_name, iface, IFNAMSIZ - 1); | |||
+ strlcpy(ifr.ifr_name, iface, IFNAMSIZ); | |||
if (ioctl(nhrp_socket_fd, SIOCGIFFLAGS, &ifr)) | |||
return -1; | |||
--- a/nhrpd/nhrp_interface.c | |||
+++ b/nhrpd/nhrp_interface.c | |||
@@ -42,6 +42,7 @@ static int nhrp_if_new_hook(struct inter | |||
struct nhrp_afi_data *ad = &nifp->afi[afi]; | |||
ad->holdtime = NHRPD_DEFAULT_HOLDTIME; | |||
list_init(&ad->nhslist_head); | |||
+ list_init(&ad->mcastlist_head); | |||
} | |||
return 0; | |||
@@ -55,6 +56,7 @@ static int nhrp_if_delete_hook(struct in | |||
nhrp_cache_interface_del(ifp); | |||
nhrp_nhs_interface_del(ifp); | |||
+ nhrp_multicast_interface_del(ifp); | |||
nhrp_peer_interface_del(ifp); | |||
if (nifp->ipsec_profile) | |||
--- /dev/null | |||
+++ b/nhrpd/nhrp_multicast.c | |||
@@ -0,0 +1,309 @@ | |||
+/* NHRP Multicast Support | |||
+ * Copyright (c) 2020-2021 4RF Limited | |||
+ * | |||
+ * This file is free software: you may copy, redistribute and/or modify | |||
+ * it under the terms of the GNU General Public License as published by | |||
+ * the Free Software Foundation, either version 2 of the License, or | |||
+ * (at your option) any later version. | |||
+ */ | |||
+ | |||
+#ifdef HAVE_CONFIG_H | |||
+#include "config.h" | |||
+#endif | |||
+ | |||
+#include <fcntl.h> | |||
+#include <net/if.h> | |||
+#include <net/ethernet.h> | |||
+#include <netinet/if_ether.h> | |||
+#include <linux/netlink.h> | |||
+#include <linux/neighbour.h> | |||
+#include <linux/netfilter/nfnetlink_log.h> | |||
+#include <linux/if_packet.h> | |||
+#include <sys/types.h> | |||
+#include <sys/socket.h> | |||
+ | |||
+#include "thread.h" | |||
+#include "nhrpd.h" | |||
+#include "netlink.h" | |||
+#include "znl.h" | |||
+#include "os.h" | |||
+ | |||
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_MULTICAST, "NHRP Multicast") | |||
+ | |||
+int netlink_mcast_nflog_group; | |||
+static int netlink_mcast_log_fd = -1; | |||
+static struct thread *netlink_mcast_log_thread; | |||
+ | |||
+struct mcast_ctx { | |||
+ struct interface *ifp; | |||
+ struct zbuf *pkt; | |||
+}; | |||
+ | |||
+static void nhrp_multicast_send(struct nhrp_peer *p, struct zbuf *zb) | |||
+{ | |||
+ char buf[2][256]; | |||
+ size_t addrlen; | |||
+ int ret; | |||
+ | |||
+ addrlen = sockunion_get_addrlen(&p->vc->remote.nbma); | |||
+ ret = os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex, | |||
+ sockunion_get_addr(&p->vc->remote.nbma), addrlen, | |||
+ addrlen == 4 ? ETH_P_IP : ETH_P_IPV6); | |||
+ | |||
+ debugf(NHRP_DEBUG_COMMON, | |||
+ "Multicast Packet: %s -> %s, ret = %d, size = %zu, addrlen = %zu", | |||
+ sockunion2str(&p->vc->local.nbma, buf[0], sizeof(buf[0])), | |||
+ sockunion2str(&p->vc->remote.nbma, buf[1], sizeof(buf[1])), ret, | |||
+ zbuf_used(zb), addrlen); | |||
+} | |||
+ | |||
+static void nhrp_multicast_forward_nbma(union sockunion *nbma_addr, | |||
+ struct interface *ifp, struct zbuf *pkt) | |||
+{ | |||
+ struct nhrp_peer *p = nhrp_peer_get(ifp, nbma_addr); | |||
+ | |||
+ if (p && p->online) { | |||
+ /* Send packet */ | |||
+ nhrp_multicast_send(p, pkt); | |||
+ } | |||
+ nhrp_peer_unref(p); | |||
+} | |||
+ | |||
+static void nhrp_multicast_forward_cache(struct nhrp_cache *c, void *pctx) | |||
+{ | |||
+ struct mcast_ctx *ctx = (struct mcast_ctx *)pctx; | |||
+ | |||
+ if (c->cur.type == NHRP_CACHE_DYNAMIC && c->cur.peer) | |||
+ nhrp_multicast_forward_nbma(&c->cur.peer->vc->remote.nbma, | |||
+ ctx->ifp, ctx->pkt); | |||
+} | |||
+ | |||
+static void nhrp_multicast_forward(struct nhrp_multicast *mcast, void *pctx) | |||
+{ | |||
+ struct mcast_ctx *ctx = (struct mcast_ctx *)pctx; | |||
+ struct nhrp_interface *nifp = ctx->ifp->info; | |||
+ | |||
+ if (!nifp->enabled) | |||
+ return; | |||
+ | |||
+ /* dynamic */ | |||
+ if (sockunion_family(&mcast->nbma_addr) == AF_UNSPEC) { | |||
+ nhrp_cache_foreach(ctx->ifp, nhrp_multicast_forward_cache, | |||
+ pctx); | |||
+ return; | |||
+ } | |||
+ | |||
+ /* Fixed IP Address */ | |||
+ nhrp_multicast_forward_nbma(&mcast->nbma_addr, ctx->ifp, ctx->pkt); | |||
+} | |||
+ | |||
+static void netlink_mcast_log_handler(struct nlmsghdr *msg, struct zbuf *zb) | |||
+{ | |||
+ struct nfgenmsg *nf; | |||
+ struct rtattr *rta; | |||
+ struct zbuf rtapl; | |||
+ uint32_t *out_ndx = NULL; | |||
+ afi_t afi; | |||
+ struct mcast_ctx ctx; | |||
+ | |||
+ nf = znl_pull(zb, sizeof(*nf)); | |||
+ if (!nf) | |||
+ return; | |||
+ | |||
+ ctx.pkt = NULL; | |||
+ while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) { | |||
+ switch (rta->rta_type) { | |||
+ case NFULA_IFINDEX_OUTDEV: | |||
+ out_ndx = znl_pull(&rtapl, sizeof(*out_ndx)); | |||
+ break; | |||
+ case NFULA_PAYLOAD: | |||
+ ctx.pkt = &rtapl; | |||
+ break; | |||
+ /* NFULA_HWHDR exists and is supposed to contain source | |||
+ * hardware address. However, for ip_gre it seems to be | |||
+ * the nexthop destination address if the packet matches | |||
+ * route. | |||
+ */ | |||
+ } | |||
+ } | |||
+ | |||
+ if (!out_ndx || !ctx.pkt) | |||
+ return; | |||
+ | |||
+ ctx.ifp = if_lookup_by_index(htonl(*out_ndx), VRF_DEFAULT); | |||
+ if (!ctx.ifp) | |||
+ return; | |||
+ | |||
+ debugf(NHRP_DEBUG_COMMON, "Received multicast packet on %s len %zu\n", | |||
+ ctx.ifp->name, zbuf_used(ctx.pkt)); | |||
+ | |||
+ for (afi = 0; afi < AFI_MAX; afi++) { | |||
+ nhrp_multicast_foreach(ctx.ifp, afi, nhrp_multicast_forward, | |||
+ (void *)&ctx); | |||
+ } | |||
+} | |||
+ | |||
+static int netlink_mcast_log_recv(struct thread *t) | |||
+{ | |||
+ uint8_t buf[65535]; /* Max OSPF Packet size */ | |||
+ int fd = THREAD_FD(t); | |||
+ struct zbuf payload, zb; | |||
+ struct nlmsghdr *n; | |||
+ | |||
+ netlink_mcast_log_thread = NULL; | |||
+ | |||
+ zbuf_init(&zb, buf, sizeof(buf), 0); | |||
+ while (zbuf_recv(&zb, fd) > 0) { | |||
+ while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) { | |||
+ debugf(NHRP_DEBUG_COMMON, | |||
+ "Netlink-mcast-log: Received msg_type %u, msg_flags %u", | |||
+ n->nlmsg_type, n->nlmsg_flags); | |||
+ switch (n->nlmsg_type) { | |||
+ case (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET: | |||
+ netlink_mcast_log_handler(n, &payload); | |||
+ break; | |||
+ } | |||
+ } | |||
+ } | |||
+ | |||
+ thread_add_read(master, netlink_mcast_log_recv, 0, netlink_mcast_log_fd, | |||
+ &netlink_mcast_log_thread); | |||
+ | |||
+ return 0; | |||
+} | |||
+ | |||
+static void netlink_mcast_log_register(int fd, int group) | |||
+{ | |||
+ struct nlmsghdr *n; | |||
+ struct nfgenmsg *nf; | |||
+ struct nfulnl_msg_config_cmd cmd; | |||
+ struct zbuf *zb = zbuf_alloc(512); | |||
+ | |||
+ n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG, | |||
+ NLM_F_REQUEST | NLM_F_ACK); | |||
+ nf = znl_push(zb, sizeof(*nf)); | |||
+ *nf = (struct nfgenmsg){ | |||
+ .nfgen_family = AF_UNSPEC, | |||
+ .version = NFNETLINK_V0, | |||
+ .res_id = htons(group), | |||
+ }; | |||
+ cmd.command = NFULNL_CFG_CMD_BIND; | |||
+ znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd)); | |||
+ znl_nlmsg_complete(zb, n); | |||
+ | |||
+ zbuf_send(zb, fd); | |||
+ zbuf_free(zb); | |||
+} | |||
+ | |||
+void netlink_mcast_set_nflog_group(int nlgroup) | |||
+{ | |||
+ if (netlink_mcast_log_fd >= 0) { | |||
+ THREAD_OFF(netlink_mcast_log_thread); | |||
+ close(netlink_mcast_log_fd); | |||
+ netlink_mcast_log_fd = -1; | |||
+ debugf(NHRP_DEBUG_COMMON, "De-register nflog group"); | |||
+ } | |||
+ netlink_mcast_nflog_group = nlgroup; | |||
+ if (nlgroup) { | |||
+ netlink_mcast_log_fd = znl_open(NETLINK_NETFILTER, 0); | |||
+ if (netlink_mcast_log_fd < 0) | |||
+ return; | |||
+ | |||
+ netlink_mcast_log_register(netlink_mcast_log_fd, nlgroup); | |||
+ thread_add_read(master, netlink_mcast_log_recv, 0, | |||
+ netlink_mcast_log_fd, | |||
+ &netlink_mcast_log_thread); | |||
+ debugf(NHRP_DEBUG_COMMON, "Register nflog group: %d", | |||
+ netlink_mcast_nflog_group); | |||
+ } | |||
+} | |||
+ | |||
+static int nhrp_multicast_free(struct interface *ifp, | |||
+ struct nhrp_multicast *mcast) | |||
+{ | |||
+ list_del(&mcast->list_entry); | |||
+ XFREE(MTYPE_NHRP_MULTICAST, mcast); | |||
+ return 0; | |||
+} | |||
+ | |||
+int nhrp_multicast_add(struct interface *ifp, afi_t afi, | |||
+ union sockunion *nbma_addr) | |||
+{ | |||
+ struct nhrp_interface *nifp = ifp->info; | |||
+ struct nhrp_multicast *mcast; | |||
+ char buf[SU_ADDRSTRLEN]; | |||
+ | |||
+ list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry) | |||
+ { | |||
+ if (sockunion_same(&mcast->nbma_addr, nbma_addr)) | |||
+ return NHRP_ERR_ENTRY_EXISTS; | |||
+ } | |||
+ | |||
+ mcast = XMALLOC(MTYPE_NHRP_MULTICAST, sizeof(struct nhrp_multicast)); | |||
+ | |||
+ *mcast = (struct nhrp_multicast){ | |||
+ .afi = afi, .ifp = ifp, .nbma_addr = *nbma_addr, | |||
+ }; | |||
+ list_add_tail(&mcast->list_entry, &nifp->afi[afi].mcastlist_head); | |||
+ | |||
+ sockunion2str(nbma_addr, buf, sizeof(buf)); | |||
+ debugf(NHRP_DEBUG_COMMON, "Adding multicast entry (%s)", buf); | |||
+ | |||
+ return NHRP_OK; | |||
+} | |||
+ | |||
+int nhrp_multicast_del(struct interface *ifp, afi_t afi, | |||
+ union sockunion *nbma_addr) | |||
+{ | |||
+ struct nhrp_interface *nifp = ifp->info; | |||
+ struct nhrp_multicast *mcast, *tmp; | |||
+ char buf[SU_ADDRSTRLEN]; | |||
+ | |||
+ list_for_each_entry_safe(mcast, tmp, &nifp->afi[afi].mcastlist_head, | |||
+ list_entry) | |||
+ { | |||
+ if (!sockunion_same(&mcast->nbma_addr, nbma_addr)) | |||
+ continue; | |||
+ | |||
+ sockunion2str(nbma_addr, buf, sizeof(buf)); | |||
+ debugf(NHRP_DEBUG_COMMON, "Deleting multicast entry (%s)", buf); | |||
+ | |||
+ nhrp_multicast_free(ifp, mcast); | |||
+ | |||
+ return NHRP_OK; | |||
+ } | |||
+ | |||
+ return NHRP_ERR_ENTRY_NOT_FOUND; | |||
+} | |||
+ | |||
+void nhrp_multicast_interface_del(struct interface *ifp) | |||
+{ | |||
+ struct nhrp_interface *nifp = ifp->info; | |||
+ struct nhrp_multicast *mcast, *tmp; | |||
+ afi_t afi; | |||
+ | |||
+ for (afi = 0; afi < AFI_MAX; afi++) { | |||
+ debugf(NHRP_DEBUG_COMMON, | |||
+ "Cleaning up multicast entries (%d)", | |||
+ !list_empty(&nifp->afi[afi].mcastlist_head)); | |||
+ | |||
+ list_for_each_entry_safe( | |||
+ mcast, tmp, &nifp->afi[afi].mcastlist_head, list_entry) | |||
+ { | |||
+ nhrp_multicast_free(ifp, mcast); | |||
+ } | |||
+ } | |||
+} | |||
+ | |||
+void nhrp_multicast_foreach(struct interface *ifp, afi_t afi, | |||
+ void (*cb)(struct nhrp_multicast *, void *), | |||
+ void *ctx) | |||
+{ | |||
+ struct nhrp_interface *nifp = ifp->info; | |||
+ struct nhrp_multicast *mcast; | |||
+ | |||
+ list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry) | |||
+ { | |||
+ cb(mcast, ctx); | |||
+ } | |||
+} | |||
--- a/nhrpd/nhrp_peer.c | |||
+++ b/nhrpd/nhrp_peer.c | |||
@@ -337,7 +337,7 @@ void nhrp_peer_send(struct nhrp_peer *p, | |||
os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex, | |||
sockunion_get_addr(&p->vc->remote.nbma), | |||
- sockunion_get_addrlen(&p->vc->remote.nbma)); | |||
+ sockunion_get_addrlen(&p->vc->remote.nbma), ETH_P_NHRP); | |||
zbuf_reset(zb); | |||
} | |||
--- a/nhrpd/nhrp_vty.c | |||
+++ b/nhrpd/nhrp_vty.c | |||
@@ -187,6 +187,9 @@ static int nhrp_config_write(struct vty | |||
if (netlink_nflog_group) { | |||
vty_out(vty, "nhrp nflog-group %d\n", netlink_nflog_group); | |||
} | |||
+ if (netlink_mcast_nflog_group) | |||
+ vty_out(vty, "nhrp multicast-nflog-group %d\n", | |||
+ netlink_mcast_nflog_group); | |||
return 0; | |||
} | |||
@@ -257,6 +260,31 @@ DEFUN(no_nhrp_nflog_group, no_nhrp_nflog | |||
return CMD_SUCCESS; | |||
} | |||
+DEFUN(nhrp_multicast_nflog_group, nhrp_multicast_nflog_group_cmd, | |||
+ "nhrp multicast-nflog-group (1-65535)", | |||
+ NHRP_STR | |||
+ "Specify NFLOG group number for Multicast Packets\n" | |||
+ "NFLOG group number\n") | |||
+{ | |||
+ uint32_t nfgroup; | |||
+ | |||
+ nfgroup = strtoul(argv[2]->arg, NULL, 10); | |||
+ netlink_mcast_set_nflog_group(nfgroup); | |||
+ | |||
+ return CMD_SUCCESS; | |||
+} | |||
+ | |||
+DEFUN(no_nhrp_multicast_nflog_group, no_nhrp_multicast_nflog_group_cmd, | |||
+ "no nhrp multicast-nflog-group [(1-65535)]", | |||
+ NO_STR | |||
+ NHRP_STR | |||
+ "Specify NFLOG group number\n" | |||
+ "NFLOG group number\n") | |||
+{ | |||
+ netlink_mcast_set_nflog_group(0); | |||
+ return CMD_SUCCESS; | |||
+} | |||
+ | |||
DEFUN(tunnel_protection, tunnel_protection_cmd, | |||
"tunnel protection vici profile PROFILE [fallback-profile FALLBACK]", | |||
"NHRP/GRE integration\n" | |||
@@ -569,6 +597,53 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd | |||
return CMD_SUCCESS; | |||
} | |||
+DEFUN(if_nhrp_map_multicast, if_nhrp_map_multicast_cmd, | |||
+ AFI_CMD " nhrp map multicast <A.B.C.D|X:X::X:X|dynamic>", | |||
+ AFI_STR | |||
+ NHRP_STR | |||
+ "Multicast NBMA Configuration\n" | |||
+ "Use this NBMA mapping for multicasts\n" | |||
+ "IPv4 NBMA address\n" | |||
+ "IPv6 NBMA address\n" | |||
+ "Dynamically learn destinations from client registrations on hub\n") | |||
+{ | |||
+ VTY_DECLVAR_CONTEXT(interface, ifp); | |||
+ afi_t afi = cmd_to_afi(argv[0]); | |||
+ union sockunion nbma_addr; | |||
+ int ret; | |||
+ | |||
+ if (str2sockunion(argv[4]->arg, &nbma_addr) < 0) | |||
+ sockunion_family(&nbma_addr) = AF_UNSPEC; | |||
+ | |||
+ ret = nhrp_multicast_add(ifp, afi, &nbma_addr); | |||
+ | |||
+ return nhrp_vty_return(vty, ret); | |||
+} | |||
+ | |||
+DEFUN(if_no_nhrp_map_multicast, if_no_nhrp_map_multicast_cmd, | |||
+ "no " AFI_CMD " nhrp map multicast <A.B.C.D|X:X::X:X|dynamic>", | |||
+ NO_STR | |||
+ AFI_STR | |||
+ NHRP_STR | |||
+ "Multicast NBMA Configuration\n" | |||
+ "Use this NBMA mapping for multicasts\n" | |||
+ "IPv4 NBMA address\n" | |||
+ "IPv6 NBMA address\n" | |||
+ "Dynamically learn destinations from client registrations on hub\n") | |||
+{ | |||
+ VTY_DECLVAR_CONTEXT(interface, ifp); | |||
+ afi_t afi = cmd_to_afi(argv[1]); | |||
+ union sockunion nbma_addr; | |||
+ int ret; | |||
+ | |||
+ if (str2sockunion(argv[5]->arg, &nbma_addr) < 0) | |||
+ sockunion_family(&nbma_addr) = AF_UNSPEC; | |||
+ | |||
+ ret = nhrp_multicast_del(ifp, afi, &nbma_addr); | |||
+ | |||
+ return nhrp_vty_return(vty, ret); | |||
+} | |||
+ | |||
DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd, | |||
AFI_CMD " nhrp nhs <A.B.C.D|X:X::X:X|dynamic> nbma <A.B.C.D|FQDN>", | |||
AFI_STR | |||
@@ -644,8 +719,8 @@ static void show_ip_nhrp_cache(struct nh | |||
sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])); | |||
if (c->cur.peer) | |||
- sockunion2str(&c->cur.peer->vc->remote.nbma, | |||
- buf[1], sizeof(buf[1])); | |||
+ sockunion2str(&c->cur.peer->vc->remote.nbma, buf[1], | |||
+ sizeof(buf[1])); | |||
else | |||
snprintf(buf[1], sizeof(buf[1]), "-"); | |||
@@ -704,8 +779,8 @@ static void show_ip_nhrp_nhs(struct nhrp | |||
ctx->count++; | |||
if (reg && reg->peer) | |||
- sockunion2str(®->peer->vc->remote.nbma, | |||
- buf[0], sizeof(buf[0])); | |||
+ sockunion2str(®->peer->vc->remote.nbma, buf[0], | |||
+ sizeof(buf[0])); | |||
else | |||
snprintf(buf[0], sizeof(buf[0]), "-"); | |||
sockunion2str(reg ? ®->proto_addr : &n->proto_addr, buf[1], | |||
@@ -1018,7 +1093,8 @@ struct write_map_ctx { | |||
const char *aficmd; | |||
}; | |||
-static void interface_config_write_nhrp_map(struct nhrp_cache_config *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; | |||
@@ -1030,7 +1106,8 @@ static void interface_config_write_nhrp_ | |||
vty_out(vty, " %s nhrp map %s %s\n", ctx->aficmd, | |||
sockunion2str(&c->remote_addr, buf[0], sizeof(buf[0])), | |||
c->type == NHRP_CACHE_LOCAL | |||
- ? "local" : sockunion2str(&c->nbma, buf[1], sizeof(buf[1]))); | |||
+ ? "local" | |||
+ : sockunion2str(&c->nbma, buf[1], sizeof(buf[1]))); | |||
} | |||
static int interface_config_write(struct vty *vty) | |||
@@ -1040,6 +1117,7 @@ static int interface_config_write(struct | |||
struct interface *ifp; | |||
struct nhrp_interface *nifp; | |||
struct nhrp_nhs *nhs; | |||
+ struct nhrp_multicast *mcast; | |||
const char *aficmd; | |||
afi_t afi; | |||
char buf[SU_ADDRSTRLEN]; | |||
@@ -1093,8 +1171,8 @@ static int interface_config_write(struct | |||
.family = afi2family(afi), | |||
.aficmd = aficmd, | |||
}; | |||
- nhrp_cache_config_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) | |||
@@ -1109,6 +1187,19 @@ static int interface_config_write(struct | |||
sizeof(buf)), | |||
nhs->nbma_fqdn); | |||
} | |||
+ | |||
+ list_for_each_entry(mcast, &ad->mcastlist_head, | |||
+ list_entry) | |||
+ { | |||
+ vty_out(vty, " %s nhrp map multicast %s\n", | |||
+ aficmd, | |||
+ sockunion_family(&mcast->nbma_addr) | |||
+ == AF_UNSPEC | |||
+ ? "dynamic" | |||
+ : sockunion2str( | |||
+ &mcast->nbma_addr, | |||
+ buf, sizeof(buf))); | |||
+ } | |||
} | |||
vty_endframe(vty, "!\n"); | |||
@@ -1142,6 +1233,8 @@ void nhrp_config_init(void) | |||
install_element(CONFIG_NODE, &no_nhrp_event_socket_cmd); | |||
install_element(CONFIG_NODE, &nhrp_nflog_group_cmd); | |||
install_element(CONFIG_NODE, &no_nhrp_nflog_group_cmd); | |||
+ install_element(CONFIG_NODE, &nhrp_multicast_nflog_group_cmd); | |||
+ install_element(CONFIG_NODE, &no_nhrp_multicast_nflog_group_cmd); | |||
/* interface specific commands */ | |||
install_node(&nhrp_interface_node); | |||
@@ -1163,6 +1256,8 @@ void nhrp_config_init(void) | |||
install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd); | |||
install_element(INTERFACE_NODE, &if_nhrp_map_cmd); | |||
install_element(INTERFACE_NODE, &if_no_nhrp_map_cmd); | |||
+ install_element(INTERFACE_NODE, &if_nhrp_map_multicast_cmd); | |||
+ install_element(INTERFACE_NODE, &if_no_nhrp_map_multicast_cmd); | |||
install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd); | |||
install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd); | |||
} | |||
--- a/nhrpd/nhrpd.h | |||
+++ b/nhrpd/nhrpd.h | |||
@@ -259,6 +259,13 @@ struct nhrp_nhs { | |||
struct list_head reglist_head; | |||
}; | |||
+struct nhrp_multicast { | |||
+ struct interface *ifp; | |||
+ struct list_head list_entry; | |||
+ afi_t afi; | |||
+ union sockunion nbma_addr; /* IP-address */ | |||
+}; | |||
+ | |||
struct nhrp_registration { | |||
struct list_head reglist_entry; | |||
struct thread *t_register; | |||
@@ -304,6 +311,7 @@ struct nhrp_interface { | |||
unsigned short mtu; | |||
unsigned int holdtime; | |||
struct list_head nhslist_head; | |||
+ struct list_head mcastlist_head; | |||
} afi[AFI_MAX]; | |||
}; | |||
@@ -345,6 +353,16 @@ void nhrp_nhs_foreach(struct interface * | |||
void *ctx); | |||
void nhrp_nhs_interface_del(struct interface *ifp); | |||
+int nhrp_multicast_add(struct interface *ifp, afi_t afi, | |||
+ union sockunion *nbma_addr); | |||
+int nhrp_multicast_del(struct interface *ifp, afi_t afi, | |||
+ union sockunion *nbma_addr); | |||
+void nhrp_multicast_interface_del(struct interface *ifp); | |||
+void nhrp_multicast_foreach(struct interface *ifp, afi_t afi, | |||
+ void (*cb)(struct nhrp_multicast *, void *), | |||
+ void *ctx); | |||
+void netlink_mcast_set_nflog_group(int nlgroup); | |||
+ | |||
void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp); | |||
void nhrp_route_announce(int add, enum nhrp_cache_type type, | |||
const struct prefix *p, struct interface *ifp, | |||
--- a/nhrpd/os.h | |||
+++ b/nhrpd/os.h | |||
@@ -1,7 +1,7 @@ | |||
int os_socket(void); | |||
int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr, | |||
- size_t addrlen); | |||
+ size_t addrlen, uint16_t protocol); | |||
int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr, | |||
size_t *addrlen); | |||
int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af); | |||
--- a/nhrpd/subdir.am | |||
+++ b/nhrpd/subdir.am | |||
@@ -21,6 +21,7 @@ nhrpd_nhrpd_SOURCES = \ | |||
nhrpd/nhrp_nhs.c \ | |||
nhrpd/nhrp_packet.c \ | |||
nhrpd/nhrp_peer.c \ | |||
+ nhrpd/nhrp_multicast.c \ | |||
nhrpd/nhrp_route.c \ | |||
nhrpd/nhrp_shortcut.c \ | |||
nhrpd/nhrp_vc.c \ | |||
--- a/ospfd/ospf_interface.c | |||
+++ b/ospfd/ospf_interface.c | |||
@@ -534,6 +534,8 @@ static struct ospf_if_params *ospf_new_i | |||
oip->network_lsa_seqnum = htonl(OSPF_INITIAL_SEQUENCE_NUMBER); | |||
oip->is_v_wait_set = false; | |||
+ oip->ptp_dmvpn = 0; | |||
+ | |||
return oip; | |||
} | |||
--- a/ospfd/ospf_interface.h | |||
+++ b/ospfd/ospf_interface.h | |||
@@ -105,6 +105,9 @@ struct ospf_if_params { | |||
/* BFD configuration */ | |||
struct bfd_info *bfd_info; | |||
+ | |||
+ /* point-to-point DMVPN configuration */ | |||
+ uint8_t ptp_dmvpn; | |||
}; | |||
enum { MEMBER_ALLROUTERS = 0, | |||
@@ -167,6 +170,9 @@ struct ospf_interface { | |||
/* OSPF Network Type. */ | |||
uint8_t type; | |||
+ /* point-to-point DMVPN configuration */ | |||
+ uint8_t ptp_dmvpn; | |||
+ | |||
/* State of Interface State Machine. */ | |||
uint8_t state; | |||
--- a/ospfd/ospf_lsa.c | |||
+++ b/ospfd/ospf_lsa.c | |||
@@ -469,6 +469,12 @@ static char link_info_set(struct stream | |||
} | |||
/* Describe Point-to-Point link (Section 12.4.1.1). */ | |||
+ | |||
+/* Note: If the interface is configured as point-to-point dmvpn then the other | |||
+ * end of link is dmvpn hub with point-to-multipoint ospf network type. The | |||
+ * hub then expects this router to populate the stub network and also Link Data | |||
+ * Field set to IP Address and not MIB-II ifIndex | |||
+ */ | |||
static int lsa_link_ptop_set(struct stream **s, struct ospf_interface *oi) | |||
{ | |||
int links = 0; | |||
@@ -482,7 +488,8 @@ static int lsa_link_ptop_set(struct stre | |||
if ((nbr = ospf_nbr_lookup_ptop(oi))) | |||
if (nbr->state == NSM_Full) { | |||
if (CHECK_FLAG(oi->connected->flags, | |||
- ZEBRA_IFA_UNNUMBERED)) { | |||
+ ZEBRA_IFA_UNNUMBERED) | |||
+ && !oi->ptp_dmvpn) { | |||
/* For unnumbered point-to-point networks, the | |||
Link Data field | |||
should specify the interface's MIB-II ifIndex | |||
@@ -500,7 +507,8 @@ static int lsa_link_ptop_set(struct stre | |||
} | |||
/* no need for a stub link for unnumbered interfaces */ | |||
- if (!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { | |||
+ if (oi->ptp_dmvpn | |||
+ || !CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { | |||
/* Regardless of the state of the neighboring router, we must | |||
add a Type 3 link (stub network). | |||
N.B. Options 1 & 2 share basically the same logic. */ | |||
--- a/ospfd/ospf_vty.c | |||
+++ b/ospfd/ospf_vty.c | |||
@@ -7562,20 +7562,21 @@ DEFUN_HIDDEN (no_ospf_hello_interval, | |||
return no_ip_ospf_hello_interval(self, vty, argc, argv); | |||
} | |||
-DEFUN (ip_ospf_network, | |||
- ip_ospf_network_cmd, | |||
- "ip ospf network <broadcast|non-broadcast|point-to-multipoint|point-to-point>", | |||
- "IP Information\n" | |||
- "OSPF interface commands\n" | |||
- "Network type\n" | |||
- "Specify OSPF broadcast multi-access network\n" | |||
- "Specify OSPF NBMA network\n" | |||
- "Specify OSPF point-to-multipoint network\n" | |||
- "Specify OSPF point-to-point network\n") | |||
+DEFUN(ip_ospf_network, ip_ospf_network_cmd, | |||
+ "ip ospf network <broadcast|non-broadcast|point-to-multipoint|point-to-point [dmvpn]>", | |||
+ "IP Information\n" | |||
+ "OSPF interface commands\n" | |||
+ "Network type\n" | |||
+ "Specify OSPF broadcast multi-access network\n" | |||
+ "Specify OSPF NBMA network\n" | |||
+ "Specify OSPF point-to-multipoint network\n" | |||
+ "Specify OSPF point-to-point network\n" | |||
+ "Specify OSPF point-to-point DMVPN network\n") | |||
{ | |||
VTY_DECLVAR_CONTEXT(interface, ifp); | |||
int idx = 0; | |||
int old_type = IF_DEF_PARAMS(ifp)->type; | |||
+ uint8_t old_ptp_dmvpn = IF_DEF_PARAMS(ifp)->ptp_dmvpn; | |||
struct route_node *rn; | |||
if (old_type == OSPF_IFTYPE_LOOPBACK) { | |||
@@ -7584,16 +7585,22 @@ DEFUN (ip_ospf_network, | |||
return CMD_WARNING_CONFIG_FAILED; | |||
} | |||
+ IF_DEF_PARAMS(ifp)->ptp_dmvpn = 0; | |||
+ | |||
if (argv_find(argv, argc, "broadcast", &idx)) | |||
IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_BROADCAST; | |||
else if (argv_find(argv, argc, "non-broadcast", &idx)) | |||
IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_NBMA; | |||
else if (argv_find(argv, argc, "point-to-multipoint", &idx)) | |||
IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT; | |||
- else if (argv_find(argv, argc, "point-to-point", &idx)) | |||
+ else if (argv_find(argv, argc, "point-to-point", &idx)) { | |||
IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_POINTOPOINT; | |||
+ if (argv_find(argv, argc, "dmvpn", &idx)) | |||
+ IF_DEF_PARAMS(ifp)->ptp_dmvpn = 1; | |||
+ } | |||
- if (IF_DEF_PARAMS(ifp)->type == old_type) | |||
+ if (IF_DEF_PARAMS(ifp)->type == old_type | |||
+ && IF_DEF_PARAMS(ifp)->ptp_dmvpn == old_ptp_dmvpn) | |||
return CMD_SUCCESS; | |||
SET_IF_PARAM(IF_DEF_PARAMS(ifp), type); | |||
@@ -7605,6 +7612,7 @@ DEFUN (ip_ospf_network, | |||
continue; | |||
oi->type = IF_DEF_PARAMS(ifp)->type; | |||
+ oi->ptp_dmvpn = IF_DEF_PARAMS(ifp)->ptp_dmvpn; | |||
if (oi->state > ISM_Down) { | |||
OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown); | |||
@@ -7645,6 +7653,7 @@ DEFUN (no_ip_ospf_network, | |||
struct route_node *rn; | |||
IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp); | |||
+ IF_DEF_PARAMS(ifp)->ptp_dmvpn = 0; | |||
if (IF_DEF_PARAMS(ifp)->type == old_type) | |||
return CMD_SUCCESS; | |||
@@ -9888,6 +9897,10 @@ static int config_write_interface_one(st | |||
vty_out(vty, " ip ospf network %s", | |||
ospf_int_type_str | |||
[params->type]); | |||
+ if (params->type | |||
+ == OSPF_IFTYPE_POINTOPOINT | |||
+ && params->ptp_dmvpn) | |||
+ vty_out(vty, " dmvpn"); | |||
if (params != IF_DEF_PARAMS(ifp) && rn) | |||
vty_out(vty, " %s", | |||
inet_ntoa( | |||
--- a/ospfd/ospfd.c | |||
+++ b/ospfd/ospfd.c | |||
@@ -1004,6 +1004,7 @@ static void add_ospf_interface(struct co | |||
/* If network type is specified previously, | |||
skip network type setting. */ | |||
oi->type = IF_DEF_PARAMS(co->ifp)->type; | |||
+ oi->ptp_dmvpn = IF_DEF_PARAMS(co->ifp)->ptp_dmvpn; | |||
/* Add pseudo neighbor. */ | |||
ospf_nbr_self_reset(oi, oi->ospf->router_id); | |||
--- a/doc/user/nhrpd.rst | |||
+++ b/doc/user/nhrpd.rst | |||
@@ -189,6 +189,37 @@ and | |||
https://git.alpinelinux.org/user/tteras/strongswan/log/?h=tteras | |||
git repositories for the patches. | |||
+.. _multicast-functionality: | |||
+ | |||
+Multicast Functionality | |||
+======================= | |||
+ | |||
+nhrpd can be configured to forward multicast packets, allowing routing | |||
+protocols that use multicast (such as OSPF) to be supported in the DMVPN | |||
+network. | |||
+ | |||
+This support requires an iptables NFLOG rule to allow nhrpd to intercept | |||
+multicast packets. A second iptables rule is also usually used to drop the | |||
+original multicast packet. | |||
+ | |||
+ .. code-block:: shell | |||
+ | |||
+ iptables -A OUTPUT -d 224.0.0.0/24 -o gre1 -j NFLOG --nflog-group 2 | |||
+ iptables -A OUTPUT -d 224.0.0.0/24 -o gre1 -j DROP | |||
+ | |||
+.. index:: nhrp multicast-nflog-group (1-65535) | |||
+.. clicmd:: nhrp multicast-nflog-group (1-65535) | |||
+ | |||
+ Sets the nflog group that nhrpd will listen on for multicast packets. This | |||
+ value must match the nflog-group value set in the iptables rule. | |||
+ | |||
+.. index:: ip nhrp map multicast A.B.C.D|X:X::X:X A.B.C.D|dynamic | |||
+.. clicmd:: ip nhrp map multicast A.B.C.D|X:X::X:X A.B.C.D|dynamic | |||
+ | |||
+ Sends multicast packets to the specified NBMA address. If dynamic is | |||
+ specified then destination NBMA address (or addresses) are learnt | |||
+ dynamically. | |||
+ | |||
.. _nhrp-events: | |||
NHRP Events | |||
--- a/doc/user/ospfd.rst | |||
+++ b/doc/user/ospfd.rst | |||
@@ -687,8 +687,8 @@ Interfaces | |||
:clicmd:`ip ospf dead-interval minimal hello-multiplier (2-20)` is also | |||
specified for the interface. | |||
-.. index:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point) | |||
-.. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point) | |||
+.. index:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point [dmvpn]) | |||
+.. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point [dmvpn]) | |||
When configuring a point-to-point network on an interface and the interface | |||
has a /32 address associated with then OSPF will treat the interface | |||
@@ -870,6 +870,9 @@ Redistribution | |||
.. index:: no router zebra | |||
.. clicmd:: no router zebra | |||
+ When used in a DMVPN network at a spoke, this OSPF will be configured in | |||
+ point-to-point, but the HUB will be a point-to-multipoint. To make this | |||
+ topology work, specify the optional 'dmvpn' parameter at the spoke. | |||
.. _showing-ospf-information: | |||
--- a/nhrpd/netlink.h | |||
+++ b/nhrpd/netlink.h | |||
@@ -13,6 +13,7 @@ union sockunion; | |||
struct interface; | |||
extern int netlink_nflog_group; | |||
+extern int netlink_mcast_nflog_group; | |||
extern int netlink_req_fd; | |||
void netlink_init(void); | |||
--- a/ospfd/ospf_packet.c | |||
+++ b/ospfd/ospf_packet.c | |||
@@ -802,7 +802,13 @@ static int ospf_write(struct thread *thr | |||
inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off, | |||
iph.ip_len, oi->ifp->name, oi->ifp->mtu); | |||
- if (ret < 0) | |||
+ /* sendmsg will return EPERM if firewall is blocking sending. | |||
+ * This is a normal situation when 'ip nhrp map multicast xxx' | |||
+ * is being used to send multicast packets to DMVPN peers. In | |||
+ * that case the original message is blocked with iptables rule | |||
+ * causing the EPERM result | |||
+ */ | |||
+ if (ret < 0 && errno != EPERM) | |||
flog_err( | |||
EC_LIB_SOCKET, | |||
"*** sendmsg in ospf_write failed to %s, id %d, off %d, len %d, interface %s, mtu %u: %s", | |||
@@ -910,8 +916,11 @@ static void ospf_hello(struct ip *iph, s | |||
/* Compare network mask. */ | |||
/* Checking is ignored for Point-to-Point and Virtual link. */ | |||
+ /* Checking is also ignored for Point-to-Multipoint with /32 prefix */ | |||
if (oi->type != OSPF_IFTYPE_POINTOPOINT | |||
- && oi->type != OSPF_IFTYPE_VIRTUALLINK) | |||
+ && oi->type != OSPF_IFTYPE_VIRTUALLINK | |||
+ && !(oi->type == OSPF_IFTYPE_POINTOMULTIPOINT | |||
+ && oi->address->prefixlen == IPV4_MAX_BITLEN)) | |||
if (oi->address->prefixlen != p.prefixlen) { | |||
flog_warn( | |||
EC_OSPF_PACKET, | |||
@@ -2439,6 +2448,11 @@ static int ospf_check_network_mask(struc | |||
|| oi->type == OSPF_IFTYPE_VIRTUALLINK) | |||
return 1; | |||
+ /* Ignore mask check for max prefix length (32) */ | |||
+ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT | |||
+ && oi->address->prefixlen == IPV4_MAX_BITLEN) | |||
+ return 1; | |||
+ | |||
masklen2ip(oi->address->prefixlen, &mask); | |||
me.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr; |
@ -1,82 +0,0 @@ | |||
From 354196c027e81affb05163a6c3676eef1ba06dd9 Mon Sep 17 00:00:00 2001 | |||
From: Zoran Pericic <zpericic@netst.org> | |||
Date: Sat, 25 Jan 2020 19:38:39 +0100 | |||
Subject: [PATCH] nhrp: Make vici socket path configurable | |||
MIME-Version: 1.0 | |||
Content-Type: text/plain; charset=UTF-8 | |||
Content-Transfer-Encoding: 8bit | |||
nhrp: Configure vici socket path using | |||
configure --with-vici-socket=/var/run/charon.vici | |||
If not specified default to /var/run/charon.vici | |||
Signed-off-by: Zoran Peričić <zpericic@netst.org> | |||
--- | |||
configure.ac | 8 ++++++++ | |||
doc/user/installation.rst | 4 ++++ | |||
nhrpd/README.nhrpd | 3 ++- | |||
nhrpd/vici.c | 2 +- | |||
4 files changed, 15 insertions(+), 2 deletions(-) | |||
--- a/configure.ac | |||
+++ b/configure.ac | |||
@@ -139,6 +139,13 @@ AC_ARG_WITH([yangmodelsdir], [AS_HELP_ST | |||
]) | |||
AC_SUBST([yangmodelsdir]) | |||
+AC_ARG_WITH([vici-socket], [AS_HELP_STRING([--with-vici-socket=PATH], [vici-socket (/var/run/charon.vici)])], [ | |||
+ vici_socket="$withval" | |||
+], [ | |||
+ vici_socket="/var/run/charon.vici" | |||
+]) | |||
+AC_DEFINE_UNQUOTED([VICI_SOCKET], ["$vici_socket"], [StrongSWAN vici socket path]) | |||
+ | |||
AC_ARG_ENABLE(tcmalloc, | |||
AS_HELP_STRING([--enable-tcmalloc], [Turn on tcmalloc]), | |||
[case "${enableval}" in | |||
@@ -2480,6 +2487,7 @@ group for vty sockets : ${enable_vty_g | |||
config file mask : ${enable_configfile_mask} | |||
log file mask : ${enable_logfile_mask} | |||
zebra protobuf enabled : ${enable_protobuf:-no} | |||
+vici socket path : ${vici_socket} | |||
The above user and group must have read/write access to the state file | |||
directory and to the config files in the config file directory." | |||
--- a/doc/user/installation.rst | |||
+++ b/doc/user/installation.rst | |||
@@ -383,6 +383,10 @@ options to the configuration script. | |||
Look for YANG modules in `dir` [`prefix`/share/yang]. Note that the FRR | |||
YANG modules will be installed here. | |||
+.. option:: --with-vici-socket <path> | |||
+ | |||
+ Set StrongSWAN vici interface socket path [/var/run/charon.vici]. | |||
+ | |||
Python dependency, documentation and tests | |||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |||
--- a/nhrpd/README.nhrpd | |||
+++ b/nhrpd/README.nhrpd | |||
@@ -126,7 +126,8 @@ Integration with strongSwan | |||
Contrary to opennhrp, Quagga/NHRP has tight integration with IKE daemon. | |||
Currently strongSwan is supported using the VICI protocol. strongSwan | |||
-is connected using UNIX socket (hardcoded now as /var/run/charon.vici). | |||
+is connected using UNIX socket (default /var/run/charon.vici use configure | |||
+argument --with-vici-socket= to change). | |||
Thus nhrpd needs to be run as user that can open that file. | |||
Currently, you will need patched strongSwan. The working tree is at: | |||
--- a/nhrpd/vici.c | |||
+++ b/nhrpd/vici.c | |||
@@ -478,7 +478,7 @@ static int vici_reconnect(struct thread | |||
if (vici->fd >= 0) | |||
return 0; | |||
- fd = sock_open_unix("/var/run/charon.vici"); | |||
+ fd = sock_open_unix(VICI_SOCKET); | |||
if (fd < 0) { | |||
debugf(NHRP_DEBUG_VICI, | |||
"%s: failure connecting VICI socket: %s", __func__, |