-From f9ff7bf497894b74fd02d54dc0f0a39981f7cc06 Mon Sep 17 00:00:00 2001
+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 1/6] nhrpd: Add support for forwarding multicast packets
+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
---
nhrpd/linux.c | 11 +-
nhrpd/nhrp_interface.c | 2 +
- nhrpd/nhrp_multicast.c | 312 +++++++++++++++++++++++++++++++++++++++++
+ 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, 403 insertions(+), 7 deletions(-)
- create mode 100644 nhrpd/nhrp_multicast.c
+ 8 files changed, 398 insertions(+), 7 deletions(-)
+ create mode 100755 nhrpd/nhrp_multicast.c
--- a/nhrpd/linux.c
+++ b/nhrpd/linux.c
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
-@@ -42,7 +43,7 @@ int os_socket(void)
+@@ -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,
{
struct sockaddr_ll lladdr;
struct iovec iov = {
-@@ -61,16 +62,16 @@ int os_sendmsg(const uint8_t *buf, size_
+@@ -61,16 +67,16 @@ int os_sendmsg(const uint8_t *buf, size_
memset(&lladdr, 0, sizeof(lladdr));
lladdr.sll_family = AF_PACKET;
}
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
if (nifp->ipsec_profile)
--- /dev/null
+++ b/nhrpd/nhrp_multicast.c
-@@ -0,0 +1,312 @@
+@@ -0,0 +1,309 @@
+/* NHRP Multicast Support
+ * Copyright (c) 2020-2021 4RF Limited
+ *
+
+DEFINE_MTYPE_STATIC(NHRPD, NHRP_MULTICAST, "NHRP Multicast")
+
-+static int netlink_mcast_nflog_group;
++int netlink_mcast_nflog_group;
+static int netlink_mcast_log_fd = -1;
+static struct thread *netlink_mcast_log_thread;
-+static int nhrp_multicast_ip_count;
+
+struct mcast_ctx {
+ struct interface *ifp;
+
+ 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 ? 0x0800 : 0x86DD);
-+
-+ 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);
++ 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)
++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) {
++
++ if (p && p->online) {
+ /* Send packet */
+ nhrp_multicast_send(p, pkt);
+ }
+ 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);
++ 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)
+
+ /* dynamic */
+ if (sockunion_family(&mcast->nbma_addr) == AF_UNSPEC) {
-+ nhrp_cache_foreach(ctx->ifp, nhrp_multicast_forward_cache, pctx);
++ nhrp_cache_foreach(ctx->ifp, nhrp_multicast_forward_cache,
++ pctx);
+ return;
+ }
+
+{
+ struct nfgenmsg *nf;
+ struct rtattr *rta;
-+ struct zbuf rtapl, pktpl;
-+ struct interface *ifp;
++ struct zbuf rtapl;
+ uint32_t *out_ndx = NULL;
+ afi_t afi;
+ struct mcast_ctx ctx;
+
-+ debugf(NHRP_DEBUG_COMMON,"Inside %s\n", __func__);
-+
+ nf = znl_pull(zb, sizeof(*nf));
+ if (!nf)
+ return;
+
-+ memset(&pktpl, 0, sizeof(pktpl));
++ 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:
-+ pktpl = rtapl;
++ 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. */
++ * route.
++ */
+ }
+ }
+
-+ if (!out_ndx || !zbuf_used(&pktpl))
++ if (!out_ndx || !ctx.pkt)
+ return;
+
-+ ifp = if_lookup_by_index(htonl(*out_ndx), VRF_DEFAULT);
-+ if (!ifp)
++ ctx.ifp = if_lookup_by_index(htonl(*out_ndx), VRF_DEFAULT);
++ if (!ctx.ifp)
+ return;
+
-+ debugf(NHRP_DEBUG_COMMON,"Outgoing interface = %s\n", ifp->name);
-+
-+ ctx = (struct mcast_ctx) {
-+ .ifp = ifp,
-+ .pkt = &pktpl,
-+ };
++ 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(ifp, afi, nhrp_multicast_forward, (void *)&ctx);
++ nhrp_multicast_foreach(ctx.ifp, afi, nhrp_multicast_forward,
++ (void *)&ctx);
+ }
+}
+
+ zbuf_free(zb);
+}
+
-+static void netlink_mcast_set_nflog_group(struct interface *ifp, int nlgroup)
++void netlink_mcast_set_nflog_group(int nlgroup)
+{
+ if (netlink_mcast_log_fd >= 0) {
+ THREAD_OFF(netlink_mcast_log_thread);
+ return;
+
+ netlink_mcast_log_register(netlink_mcast_log_fd, nlgroup);
-+ thread_add_read(master, netlink_mcast_log_recv, 0, netlink_mcast_log_fd,
++ 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);
++ debugf(NHRP_DEBUG_COMMON, "Register nflog group: %d",
++ netlink_mcast_nflog_group);
+ }
+}
+
-+static int nhrp_multicast_free(struct interface *ifp, struct nhrp_multicast *mcast)
++static int nhrp_multicast_free(struct interface *ifp,
++ struct nhrp_multicast *mcast)
+{
+ list_del(&mcast->list_entry);
+ XFREE(MTYPE_NHRP_MULTICAST, mcast);
-+ if (--nhrp_multicast_ip_count == 0)
-+ netlink_mcast_set_nflog_group(ifp, 0);
+ return 0;
+}
+
-+int nhrp_multicast_add(struct interface *ifp, afi_t afi, union sockunion *nbma_addr)
++int nhrp_multicast_add(struct interface *ifp, afi_t afi,
++ union sockunion *nbma_addr)
+{
+ struct nhrp_interface *nifp = ifp->info;
+ struct nhrp_multicast *mcast;
+ mcast = XMALLOC(MTYPE_NHRP_MULTICAST, sizeof(struct nhrp_multicast));
+
+ *mcast = (struct nhrp_multicast){
-+ .afi = afi,
-+ .ifp = ifp,
-+ .nbma_addr = *nbma_addr,
++ .afi = afi, .ifp = ifp, .nbma_addr = *nbma_addr,
+ };
+ list_add_tail(&mcast->list_entry, &nifp->afi[afi].mcastlist_head);
+
-+ if (netlink_mcast_log_fd == -1)
-+ netlink_mcast_set_nflog_group(ifp, MCAST_NFLOG_GROUP);
-+
-+ nhrp_multicast_ip_count++;
-+
+ sockunion2str(nbma_addr, buf, sizeof(buf));
-+ debugf(NHRP_DEBUG_COMMON, "Adding multicast entry (%s) [%d]", buf, nhrp_multicast_ip_count);
++ 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)
++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;
+ continue;
+
+ sockunion2str(nbma_addr, buf, sizeof(buf));
-+ debugf(NHRP_DEBUG_COMMON, "Deleting multicast entry (%s) [%d]", buf, nhrp_multicast_ip_count);
++ debugf(NHRP_DEBUG_COMMON, "Deleting multicast entry (%s)", buf);
+
+ nhrp_multicast_free(ifp, mcast);
+
+ afi_t afi;
+
+ for (afi = 0; afi < AFI_MAX; afi++) {
-+ debugf(NHRP_DEBUG_COMMON, "Cleaning up multicast entries (%d, %d)", !list_empty(&nifp->afi[afi].mcastlist_head), nhrp_multicast_ip_count);
++ 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) {
++ 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)
++ 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);
++ cb(mcast, ctx);
+ }
+}
--- a/nhrpd/nhrp_peer.c
+++ b/nhrpd/nhrp_peer.c
-@@ -337,7 +337,8 @@ void nhrp_peer_send(struct nhrp_peer *p,
+@@ -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);
++ sockunion_get_addrlen(&p->vc->remote.nbma), ETH_P_NHRP);
zbuf_reset(zb);
}
--- a/nhrpd/nhrp_vty.c
+++ b/nhrpd/nhrp_vty.c
-@@ -569,6 +569,53 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd
+@@ -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_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
-@@ -1040,6 +1087,7 @@ static int interface_config_write(struct
+@@ -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;
const char *aficmd;
afi_t afi;
char buf[SU_ADDRSTRLEN];
-@@ -1109,6 +1157,19 @@ static int interface_config_write(struct
+@@ -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);
}
+ == AF_UNSPEC
+ ? "dynamic"
+ : sockunion2str(
-+ &mcast->nbma_addr, buf,
-+ sizeof(buf)));
++ &mcast->nbma_addr,
++ buf, sizeof(buf)));
+ }
}
vty_endframe(vty, "!\n");
-@@ -1163,6 +1224,8 @@ void nhrp_config_init(void)
+@@ -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);
}
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
-@@ -24,6 +24,7 @@ DECLARE_MGROUP(NHRPD)
-
- #define NHRP_VTY_PORT 2610
- #define NHRP_DEFAULT_CONFIG "nhrpd.conf"
-+#define MCAST_NFLOG_GROUP 224
-
- extern struct thread_master *master;
-
-@@ -259,6 +260,13 @@ struct nhrp_nhs {
+@@ -259,6 +259,13 @@ struct nhrp_nhs {
struct list_head reglist_head;
};
struct nhrp_registration {
struct list_head reglist_entry;
struct thread *t_register;
-@@ -304,6 +312,7 @@ struct nhrp_interface {
+@@ -304,6 +311,7 @@ struct nhrp_interface {
unsigned short mtu;
unsigned int holdtime;
struct list_head nhslist_head;
} afi[AFI_MAX];
};
-@@ -345,6 +354,13 @@ void nhrp_nhs_foreach(struct interface *
+@@ -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);
++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 (*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,
ospf_nbr_self_reset(oi, oi->ospf->router_id);
--- a/doc/user/nhrpd.rst
+++ b/doc/user/nhrpd.rst
-@@ -189,6 +189,34 @@ and
+@@ -189,6 +189,37 @@ and
https://git.alpinelinux.org/user/tteras/strongswan/log/?h=tteras
git repositories for the patches.
+protocols that use multicast (such as OSPF) to be supported in the DMVPN
+network.
+
-+This support requires an NFLOG redirection rule to work:
++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 -I 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 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)
.. _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;