You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

793 lines
24 KiB

  1. From f9ff7bf497894b74fd02d54dc0f0a39981f7cc06 Mon Sep 17 00:00:00 2001
  2. From: Amol Lad <amol.lad@4rf.com>
  3. Date: Wed, 17 Feb 2021 13:47:32 +1300
  4. Subject: [PATCH 1/6] nhrpd: Add support for forwarding multicast packets
  5. Forwarding multicast is a pre-requisite for allowing multicast based routing
  6. protocols such as OSPF to work with DMVPN
  7. This code relies on externally adding iptables rule. For example:
  8. iptables -A OUTPUT -d 224.0.0.0/24 -o gre1 -j NFLOG --nflog-group 224
  9. Signed-off-by: Reuben Dowle <reuben.dowle@4rf.com>
  10. ---
  11. nhrpd/linux.c | 11 +-
  12. nhrpd/nhrp_interface.c | 2 +
  13. nhrpd/nhrp_multicast.c | 312 +++++++++++++++++++++++++++++++++++++++++
  14. nhrpd/nhrp_peer.c | 3 +-
  15. nhrpd/nhrp_vty.c | 63 +++++++++
  16. nhrpd/nhrpd.h | 16 +++
  17. nhrpd/os.h | 2 +-
  18. nhrpd/subdir.am | 1 +
  19. 8 files changed, 403 insertions(+), 7 deletions(-)
  20. create mode 100644 nhrpd/nhrp_multicast.c
  21. --- a/nhrpd/linux.c
  22. +++ b/nhrpd/linux.c
  23. @@ -15,6 +15,7 @@
  24. #include <stdio.h>
  25. #include <unistd.h>
  26. #include <string.h>
  27. +#include <errno.h>
  28. #include <sys/ioctl.h>
  29. #include <sys/socket.h>
  30. #include <sys/types.h>
  31. @@ -42,7 +43,7 @@ int os_socket(void)
  32. }
  33. int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr,
  34. - size_t addrlen)
  35. + size_t addrlen, uint16_t protocol)
  36. {
  37. struct sockaddr_ll lladdr;
  38. struct iovec iov = {
  39. @@ -61,16 +62,16 @@ int os_sendmsg(const uint8_t *buf, size_
  40. memset(&lladdr, 0, sizeof(lladdr));
  41. lladdr.sll_family = AF_PACKET;
  42. - lladdr.sll_protocol = htons(ETH_P_NHRP);
  43. + lladdr.sll_protocol = htons(protocol);
  44. lladdr.sll_ifindex = ifindex;
  45. lladdr.sll_halen = addrlen;
  46. memcpy(lladdr.sll_addr, addr, addrlen);
  47. - status = sendmsg(nhrp_socket_fd, &msg, 0);
  48. + status = sendmsg(os_socket(), &msg, 0);
  49. if (status < 0)
  50. - return -1;
  51. + return -errno;
  52. - return 0;
  53. + return status;
  54. }
  55. int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr,
  56. --- a/nhrpd/nhrp_interface.c
  57. +++ b/nhrpd/nhrp_interface.c
  58. @@ -42,6 +42,7 @@ static int nhrp_if_new_hook(struct inter
  59. struct nhrp_afi_data *ad = &nifp->afi[afi];
  60. ad->holdtime = NHRPD_DEFAULT_HOLDTIME;
  61. list_init(&ad->nhslist_head);
  62. + list_init(&ad->mcastlist_head);
  63. }
  64. return 0;
  65. @@ -55,6 +56,7 @@ static int nhrp_if_delete_hook(struct in
  66. nhrp_cache_interface_del(ifp);
  67. nhrp_nhs_interface_del(ifp);
  68. + nhrp_multicast_interface_del(ifp);
  69. nhrp_peer_interface_del(ifp);
  70. if (nifp->ipsec_profile)
  71. --- /dev/null
  72. +++ b/nhrpd/nhrp_multicast.c
  73. @@ -0,0 +1,312 @@
  74. +/* NHRP Multicast Support
  75. + * Copyright (c) 2020-2021 4RF Limited
  76. + *
  77. + * This file is free software: you may copy, redistribute and/or modify
  78. + * it under the terms of the GNU General Public License as published by
  79. + * the Free Software Foundation, either version 2 of the License, or
  80. + * (at your option) any later version.
  81. + */
  82. +
  83. +#ifdef HAVE_CONFIG_H
  84. +#include "config.h"
  85. +#endif
  86. +
  87. +#include <fcntl.h>
  88. +#include <net/if.h>
  89. +#include <net/ethernet.h>
  90. +#include <netinet/if_ether.h>
  91. +#include <linux/netlink.h>
  92. +#include <linux/neighbour.h>
  93. +#include <linux/netfilter/nfnetlink_log.h>
  94. +#include <linux/if_packet.h>
  95. +#include <sys/types.h>
  96. +#include <sys/socket.h>
  97. +
  98. +#include "thread.h"
  99. +#include "nhrpd.h"
  100. +#include "netlink.h"
  101. +#include "znl.h"
  102. +#include "os.h"
  103. +
  104. +DEFINE_MTYPE_STATIC(NHRPD, NHRP_MULTICAST, "NHRP Multicast")
  105. +
  106. +static int netlink_mcast_nflog_group;
  107. +static int netlink_mcast_log_fd = -1;
  108. +static struct thread *netlink_mcast_log_thread;
  109. +static int nhrp_multicast_ip_count;
  110. +
  111. +struct mcast_ctx {
  112. + struct interface *ifp;
  113. + struct zbuf *pkt;
  114. +};
  115. +
  116. +static void nhrp_multicast_send(struct nhrp_peer *p, struct zbuf *zb)
  117. +{
  118. + char buf[2][256];
  119. + size_t addrlen;
  120. + int ret;
  121. +
  122. + addrlen = sockunion_get_addrlen(&p->vc->remote.nbma);
  123. + ret = os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex,
  124. + sockunion_get_addr(&p->vc->remote.nbma),
  125. + addrlen, addrlen == 4 ? 0x0800 : 0x86DD);
  126. +
  127. + debugf(NHRP_DEBUG_COMMON, "Multicast Packet: %s -> %s, ret = %d, size = %zu, addrlen = %zu",
  128. + sockunion2str(&p->vc->local.nbma, buf[0], sizeof(buf[0])),
  129. + sockunion2str(&p->vc->remote.nbma, buf[1], sizeof(buf[1])),
  130. + ret, zbuf_used(zb), addrlen);
  131. +}
  132. +
  133. +static void nhrp_multicast_forward_nbma(union sockunion *nbma_addr, struct interface *ifp, struct zbuf *pkt)
  134. +{
  135. + struct nhrp_peer *p = nhrp_peer_get(ifp, nbma_addr);
  136. + if(p && p->online) {
  137. + /* Send packet */
  138. + nhrp_multicast_send(p, pkt);
  139. + }
  140. + nhrp_peer_unref(p);
  141. +}
  142. +
  143. +static void nhrp_multicast_forward_cache(struct nhrp_cache *c, void *pctx)
  144. +{
  145. + struct mcast_ctx *ctx = (struct mcast_ctx *)pctx;
  146. +
  147. + if (c->cur.type == NHRP_CACHE_DYNAMIC && c->cur.peer)
  148. + nhrp_multicast_forward_nbma(&c->cur.peer->vc->remote.nbma, ctx->ifp, ctx->pkt);
  149. +}
  150. +
  151. +static void nhrp_multicast_forward(struct nhrp_multicast *mcast, void *pctx)
  152. +{
  153. + struct mcast_ctx *ctx = (struct mcast_ctx *)pctx;
  154. + struct nhrp_interface *nifp = ctx->ifp->info;
  155. +
  156. + if (!nifp->enabled)
  157. + return;
  158. +
  159. + /* dynamic */
  160. + if (sockunion_family(&mcast->nbma_addr) == AF_UNSPEC) {
  161. + nhrp_cache_foreach(ctx->ifp, nhrp_multicast_forward_cache, pctx);
  162. + return;
  163. + }
  164. +
  165. + /* Fixed IP Address */
  166. + nhrp_multicast_forward_nbma(&mcast->nbma_addr, ctx->ifp, ctx->pkt);
  167. +}
  168. +
  169. +static void netlink_mcast_log_handler(struct nlmsghdr *msg, struct zbuf *zb)
  170. +{
  171. + struct nfgenmsg *nf;
  172. + struct rtattr *rta;
  173. + struct zbuf rtapl, pktpl;
  174. + struct interface *ifp;
  175. + uint32_t *out_ndx = NULL;
  176. + afi_t afi;
  177. + struct mcast_ctx ctx;
  178. +
  179. + debugf(NHRP_DEBUG_COMMON,"Inside %s\n", __func__);
  180. +
  181. + nf = znl_pull(zb, sizeof(*nf));
  182. + if (!nf)
  183. + return;
  184. +
  185. + memset(&pktpl, 0, sizeof(pktpl));
  186. + while ((rta = znl_rta_pull(zb, &rtapl)) != NULL) {
  187. + switch (rta->rta_type) {
  188. + case NFULA_IFINDEX_OUTDEV:
  189. + out_ndx = znl_pull(&rtapl, sizeof(*out_ndx));
  190. + break;
  191. + case NFULA_PAYLOAD:
  192. + pktpl = rtapl;
  193. + break;
  194. + /* NFULA_HWHDR exists and is supposed to contain source
  195. + * hardware address. However, for ip_gre it seems to be
  196. + * the nexthop destination address if the packet matches
  197. + * route. */
  198. + }
  199. + }
  200. +
  201. + if (!out_ndx || !zbuf_used(&pktpl))
  202. + return;
  203. +
  204. + ifp = if_lookup_by_index(htonl(*out_ndx), VRF_DEFAULT);
  205. + if (!ifp)
  206. + return;
  207. +
  208. + debugf(NHRP_DEBUG_COMMON,"Outgoing interface = %s\n", ifp->name);
  209. +
  210. + ctx = (struct mcast_ctx) {
  211. + .ifp = ifp,
  212. + .pkt = &pktpl,
  213. + };
  214. +
  215. + for (afi = 0; afi < AFI_MAX; afi++) {
  216. + nhrp_multicast_foreach(ifp, afi, nhrp_multicast_forward, (void *)&ctx);
  217. + }
  218. +}
  219. +
  220. +static int netlink_mcast_log_recv(struct thread *t)
  221. +{
  222. + uint8_t buf[65535]; /* Max OSPF Packet size */
  223. + int fd = THREAD_FD(t);
  224. + struct zbuf payload, zb;
  225. + struct nlmsghdr *n;
  226. +
  227. + netlink_mcast_log_thread = NULL;
  228. +
  229. + zbuf_init(&zb, buf, sizeof(buf), 0);
  230. + while (zbuf_recv(&zb, fd) > 0) {
  231. + while ((n = znl_nlmsg_pull(&zb, &payload)) != NULL) {
  232. + debugf(NHRP_DEBUG_COMMON,
  233. + "Netlink-mcast-log: Received msg_type %u, msg_flags %u",
  234. + n->nlmsg_type, n->nlmsg_flags);
  235. + switch (n->nlmsg_type) {
  236. + case (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_PACKET:
  237. + netlink_mcast_log_handler(n, &payload);
  238. + break;
  239. + }
  240. + }
  241. + }
  242. +
  243. + thread_add_read(master, netlink_mcast_log_recv, 0, netlink_mcast_log_fd,
  244. + &netlink_mcast_log_thread);
  245. +
  246. + return 0;
  247. +}
  248. +
  249. +static void netlink_mcast_log_register(int fd, int group)
  250. +{
  251. + struct nlmsghdr *n;
  252. + struct nfgenmsg *nf;
  253. + struct nfulnl_msg_config_cmd cmd;
  254. + struct zbuf *zb = zbuf_alloc(512);
  255. +
  256. + n = znl_nlmsg_push(zb, (NFNL_SUBSYS_ULOG << 8) | NFULNL_MSG_CONFIG,
  257. + NLM_F_REQUEST | NLM_F_ACK);
  258. + nf = znl_push(zb, sizeof(*nf));
  259. + *nf = (struct nfgenmsg){
  260. + .nfgen_family = AF_UNSPEC,
  261. + .version = NFNETLINK_V0,
  262. + .res_id = htons(group),
  263. + };
  264. + cmd.command = NFULNL_CFG_CMD_BIND;
  265. + znl_rta_push(zb, NFULA_CFG_CMD, &cmd, sizeof(cmd));
  266. + znl_nlmsg_complete(zb, n);
  267. +
  268. + zbuf_send(zb, fd);
  269. + zbuf_free(zb);
  270. +}
  271. +
  272. +static void netlink_mcast_set_nflog_group(struct interface *ifp, int nlgroup)
  273. +{
  274. + if (netlink_mcast_log_fd >= 0) {
  275. + THREAD_OFF(netlink_mcast_log_thread);
  276. + close(netlink_mcast_log_fd);
  277. + netlink_mcast_log_fd = -1;
  278. + debugf(NHRP_DEBUG_COMMON, "De-register nflog group");
  279. + }
  280. + netlink_mcast_nflog_group = nlgroup;
  281. + if (nlgroup) {
  282. + netlink_mcast_log_fd = znl_open(NETLINK_NETFILTER, 0);
  283. + if (netlink_mcast_log_fd < 0)
  284. + return;
  285. +
  286. + netlink_mcast_log_register(netlink_mcast_log_fd, nlgroup);
  287. + thread_add_read(master, netlink_mcast_log_recv, 0, netlink_mcast_log_fd,
  288. + &netlink_mcast_log_thread);
  289. + debugf(NHRP_DEBUG_COMMON, "Register nflog group: %d", netlink_mcast_nflog_group);
  290. + }
  291. +}
  292. +
  293. +static int nhrp_multicast_free(struct interface *ifp, struct nhrp_multicast *mcast)
  294. +{
  295. + list_del(&mcast->list_entry);
  296. + XFREE(MTYPE_NHRP_MULTICAST, mcast);
  297. + if (--nhrp_multicast_ip_count == 0)
  298. + netlink_mcast_set_nflog_group(ifp, 0);
  299. + return 0;
  300. +}
  301. +
  302. +int nhrp_multicast_add(struct interface *ifp, afi_t afi, union sockunion *nbma_addr)
  303. +{
  304. + struct nhrp_interface *nifp = ifp->info;
  305. + struct nhrp_multicast *mcast;
  306. + char buf[SU_ADDRSTRLEN];
  307. +
  308. + list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry)
  309. + {
  310. + if (sockunion_same(&mcast->nbma_addr, nbma_addr))
  311. + return NHRP_ERR_ENTRY_EXISTS;
  312. + }
  313. +
  314. + mcast = XMALLOC(MTYPE_NHRP_MULTICAST, sizeof(struct nhrp_multicast));
  315. +
  316. + *mcast = (struct nhrp_multicast){
  317. + .afi = afi,
  318. + .ifp = ifp,
  319. + .nbma_addr = *nbma_addr,
  320. + };
  321. + list_add_tail(&mcast->list_entry, &nifp->afi[afi].mcastlist_head);
  322. +
  323. + if (netlink_mcast_log_fd == -1)
  324. + netlink_mcast_set_nflog_group(ifp, MCAST_NFLOG_GROUP);
  325. +
  326. + nhrp_multicast_ip_count++;
  327. +
  328. + sockunion2str(nbma_addr, buf, sizeof(buf));
  329. + debugf(NHRP_DEBUG_COMMON, "Adding multicast entry (%s) [%d]", buf, nhrp_multicast_ip_count);
  330. +
  331. + return NHRP_OK;
  332. +}
  333. +
  334. +int nhrp_multicast_del(struct interface *ifp, afi_t afi, union sockunion *nbma_addr)
  335. +{
  336. + struct nhrp_interface *nifp = ifp->info;
  337. + struct nhrp_multicast *mcast, *tmp;
  338. + char buf[SU_ADDRSTRLEN];
  339. +
  340. + list_for_each_entry_safe(mcast, tmp, &nifp->afi[afi].mcastlist_head,
  341. + list_entry)
  342. + {
  343. + if (!sockunion_same(&mcast->nbma_addr, nbma_addr))
  344. + continue;
  345. +
  346. + sockunion2str(nbma_addr, buf, sizeof(buf));
  347. + debugf(NHRP_DEBUG_COMMON, "Deleting multicast entry (%s) [%d]", buf, nhrp_multicast_ip_count);
  348. +
  349. + nhrp_multicast_free(ifp, mcast);
  350. +
  351. + return NHRP_OK;
  352. + }
  353. +
  354. + return NHRP_ERR_ENTRY_NOT_FOUND;
  355. +}
  356. +
  357. +void nhrp_multicast_interface_del(struct interface *ifp)
  358. +{
  359. + struct nhrp_interface *nifp = ifp->info;
  360. + struct nhrp_multicast *mcast, *tmp;
  361. + afi_t afi;
  362. +
  363. + for (afi = 0; afi < AFI_MAX; afi++) {
  364. + debugf(NHRP_DEBUG_COMMON, "Cleaning up multicast entries (%d, %d)", !list_empty(&nifp->afi[afi].mcastlist_head), nhrp_multicast_ip_count);
  365. +
  366. + list_for_each_entry_safe(
  367. + mcast, tmp, &nifp->afi[afi].mcastlist_head,
  368. + list_entry) {
  369. + nhrp_multicast_free(ifp, mcast);
  370. + }
  371. + }
  372. +}
  373. +
  374. +void nhrp_multicast_foreach(struct interface *ifp, afi_t afi,
  375. + void (*cb)(struct nhrp_multicast *, void *),
  376. + void *ctx)
  377. +{
  378. + struct nhrp_interface *nifp = ifp->info;
  379. + struct nhrp_multicast *mcast;
  380. +
  381. + list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry)
  382. + {
  383. + cb (mcast, ctx);
  384. + }
  385. +}
  386. --- a/nhrpd/nhrp_peer.c
  387. +++ b/nhrpd/nhrp_peer.c
  388. @@ -337,7 +337,8 @@ void nhrp_peer_send(struct nhrp_peer *p,
  389. os_sendmsg(zb->head, zbuf_used(zb), p->ifp->ifindex,
  390. sockunion_get_addr(&p->vc->remote.nbma),
  391. - sockunion_get_addrlen(&p->vc->remote.nbma));
  392. + sockunion_get_addrlen(&p->vc->remote.nbma),
  393. + ETH_P_NHRP);
  394. zbuf_reset(zb);
  395. }
  396. --- a/nhrpd/nhrp_vty.c
  397. +++ b/nhrpd/nhrp_vty.c
  398. @@ -569,6 +569,53 @@ DEFUN(if_no_nhrp_map, if_no_nhrp_map_cmd
  399. return CMD_SUCCESS;
  400. }
  401. +DEFUN(if_nhrp_map_multicast, if_nhrp_map_multicast_cmd,
  402. + AFI_CMD " nhrp map multicast <A.B.C.D|X:X::X:X|dynamic>",
  403. + AFI_STR
  404. + NHRP_STR
  405. + "Multicast NBMA Configuration\n"
  406. + "Use this NBMA mapping for multicasts\n"
  407. + "IPv4 NBMA address\n"
  408. + "IPv6 NBMA address\n"
  409. + "Dynamically learn destinations from client registrations on hub\n")
  410. +{
  411. + VTY_DECLVAR_CONTEXT(interface, ifp);
  412. + afi_t afi = cmd_to_afi(argv[0]);
  413. + union sockunion nbma_addr;
  414. + int ret;
  415. +
  416. + if (str2sockunion(argv[4]->arg, &nbma_addr) < 0)
  417. + sockunion_family(&nbma_addr) = AF_UNSPEC;
  418. +
  419. + ret = nhrp_multicast_add(ifp, afi, &nbma_addr);
  420. +
  421. + return nhrp_vty_return(vty, ret);
  422. +}
  423. +
  424. +DEFUN(if_no_nhrp_map_multicast, if_no_nhrp_map_multicast_cmd,
  425. + "no " AFI_CMD " nhrp map multicast <A.B.C.D|X:X::X:X|dynamic>",
  426. + NO_STR
  427. + AFI_STR
  428. + NHRP_STR
  429. + "Multicast NBMA Configuration\n"
  430. + "Use this NBMA mapping for multicasts\n"
  431. + "IPv4 NBMA address\n"
  432. + "IPv6 NBMA address\n"
  433. + "Dynamically learn destinations from client registrations on hub\n")
  434. +{
  435. + VTY_DECLVAR_CONTEXT(interface, ifp);
  436. + afi_t afi = cmd_to_afi(argv[1]);
  437. + union sockunion nbma_addr;
  438. + int ret;
  439. +
  440. + if (str2sockunion(argv[5]->arg, &nbma_addr) < 0)
  441. + sockunion_family(&nbma_addr) = AF_UNSPEC;
  442. +
  443. + ret = nhrp_multicast_del(ifp, afi, &nbma_addr);
  444. +
  445. + return nhrp_vty_return(vty, ret);
  446. +}
  447. +
  448. DEFUN(if_nhrp_nhs, if_nhrp_nhs_cmd,
  449. AFI_CMD " nhrp nhs <A.B.C.D|X:X::X:X|dynamic> nbma <A.B.C.D|FQDN>",
  450. AFI_STR
  451. @@ -1040,6 +1087,7 @@ static int interface_config_write(struct
  452. struct interface *ifp;
  453. struct nhrp_interface *nifp;
  454. struct nhrp_nhs *nhs;
  455. + struct nhrp_multicast *mcast;
  456. const char *aficmd;
  457. afi_t afi;
  458. char buf[SU_ADDRSTRLEN];
  459. @@ -1109,6 +1157,19 @@ static int interface_config_write(struct
  460. sizeof(buf)),
  461. nhs->nbma_fqdn);
  462. }
  463. +
  464. + list_for_each_entry(mcast, &ad->mcastlist_head,
  465. + list_entry)
  466. + {
  467. + vty_out(vty, " %s nhrp map multicast %s\n",
  468. + aficmd,
  469. + sockunion_family(&mcast->nbma_addr)
  470. + == AF_UNSPEC
  471. + ? "dynamic"
  472. + : sockunion2str(
  473. + &mcast->nbma_addr, buf,
  474. + sizeof(buf)));
  475. + }
  476. }
  477. vty_endframe(vty, "!\n");
  478. @@ -1163,6 +1224,8 @@ void nhrp_config_init(void)
  479. install_element(INTERFACE_NODE, &if_no_nhrp_reg_flags_cmd);
  480. install_element(INTERFACE_NODE, &if_nhrp_map_cmd);
  481. install_element(INTERFACE_NODE, &if_no_nhrp_map_cmd);
  482. + install_element(INTERFACE_NODE, &if_nhrp_map_multicast_cmd);
  483. + install_element(INTERFACE_NODE, &if_no_nhrp_map_multicast_cmd);
  484. install_element(INTERFACE_NODE, &if_nhrp_nhs_cmd);
  485. install_element(INTERFACE_NODE, &if_no_nhrp_nhs_cmd);
  486. }
  487. --- a/nhrpd/nhrpd.h
  488. +++ b/nhrpd/nhrpd.h
  489. @@ -24,6 +24,7 @@ DECLARE_MGROUP(NHRPD)
  490. #define NHRP_VTY_PORT 2610
  491. #define NHRP_DEFAULT_CONFIG "nhrpd.conf"
  492. +#define MCAST_NFLOG_GROUP 224
  493. extern struct thread_master *master;
  494. @@ -259,6 +260,13 @@ struct nhrp_nhs {
  495. struct list_head reglist_head;
  496. };
  497. +struct nhrp_multicast {
  498. + struct interface *ifp;
  499. + struct list_head list_entry;
  500. + afi_t afi;
  501. + union sockunion nbma_addr; /* IP-address */
  502. +};
  503. +
  504. struct nhrp_registration {
  505. struct list_head reglist_entry;
  506. struct thread *t_register;
  507. @@ -304,6 +312,7 @@ struct nhrp_interface {
  508. unsigned short mtu;
  509. unsigned int holdtime;
  510. struct list_head nhslist_head;
  511. + struct list_head mcastlist_head;
  512. } afi[AFI_MAX];
  513. };
  514. @@ -345,6 +354,13 @@ void nhrp_nhs_foreach(struct interface *
  515. void *ctx);
  516. void nhrp_nhs_interface_del(struct interface *ifp);
  517. +int nhrp_multicast_add(struct interface *ifp, afi_t afi, union sockunion *nbma_addr);
  518. +int nhrp_multicast_del(struct interface *ifp, afi_t afi, union sockunion *nbma_addr);
  519. +void nhrp_multicast_interface_del(struct interface *ifp);
  520. +void nhrp_multicast_foreach(struct interface *ifp, afi_t afi,
  521. + void (*cb)(struct nhrp_multicast *, void *),
  522. + void *ctx);
  523. +
  524. void nhrp_route_update_nhrp(const struct prefix *p, struct interface *ifp);
  525. void nhrp_route_announce(int add, enum nhrp_cache_type type,
  526. const struct prefix *p, struct interface *ifp,
  527. --- a/nhrpd/os.h
  528. +++ b/nhrpd/os.h
  529. @@ -1,7 +1,7 @@
  530. int os_socket(void);
  531. int os_sendmsg(const uint8_t *buf, size_t len, int ifindex, const uint8_t *addr,
  532. - size_t addrlen);
  533. + size_t addrlen, uint16_t protocol);
  534. int os_recvmsg(uint8_t *buf, size_t *len, int *ifindex, uint8_t *addr,
  535. size_t *addrlen);
  536. int os_configure_dmvpn(unsigned int ifindex, const char *ifname, int af);
  537. --- a/nhrpd/subdir.am
  538. +++ b/nhrpd/subdir.am
  539. @@ -21,6 +21,7 @@ nhrpd_nhrpd_SOURCES = \
  540. nhrpd/nhrp_nhs.c \
  541. nhrpd/nhrp_packet.c \
  542. nhrpd/nhrp_peer.c \
  543. + nhrpd/nhrp_multicast.c \
  544. nhrpd/nhrp_route.c \
  545. nhrpd/nhrp_shortcut.c \
  546. nhrpd/nhrp_vc.c \
  547. --- a/ospfd/ospf_interface.c
  548. +++ b/ospfd/ospf_interface.c
  549. @@ -534,6 +534,8 @@ static struct ospf_if_params *ospf_new_i
  550. oip->network_lsa_seqnum = htonl(OSPF_INITIAL_SEQUENCE_NUMBER);
  551. oip->is_v_wait_set = false;
  552. + oip->ptp_dmvpn = 0;
  553. +
  554. return oip;
  555. }
  556. --- a/ospfd/ospf_interface.h
  557. +++ b/ospfd/ospf_interface.h
  558. @@ -105,6 +105,9 @@ struct ospf_if_params {
  559. /* BFD configuration */
  560. struct bfd_info *bfd_info;
  561. +
  562. + /* point-to-point DMVPN configuration */
  563. + uint8_t ptp_dmvpn;
  564. };
  565. enum { MEMBER_ALLROUTERS = 0,
  566. @@ -167,6 +170,9 @@ struct ospf_interface {
  567. /* OSPF Network Type. */
  568. uint8_t type;
  569. + /* point-to-point DMVPN configuration */
  570. + uint8_t ptp_dmvpn;
  571. +
  572. /* State of Interface State Machine. */
  573. uint8_t state;
  574. --- a/ospfd/ospf_lsa.c
  575. +++ b/ospfd/ospf_lsa.c
  576. @@ -469,6 +469,12 @@ static char link_info_set(struct stream
  577. }
  578. /* Describe Point-to-Point link (Section 12.4.1.1). */
  579. +
  580. +/* Note: If the interface is configured as point-to-point dmvpn then the other
  581. + * end of link is dmvpn hub with point-to-multipoint ospf network type. The
  582. + * hub then expects this router to populate the stub network and also Link Data
  583. + * Field set to IP Address and not MIB-II ifIndex
  584. + */
  585. static int lsa_link_ptop_set(struct stream **s, struct ospf_interface *oi)
  586. {
  587. int links = 0;
  588. @@ -482,7 +488,8 @@ static int lsa_link_ptop_set(struct stre
  589. if ((nbr = ospf_nbr_lookup_ptop(oi)))
  590. if (nbr->state == NSM_Full) {
  591. if (CHECK_FLAG(oi->connected->flags,
  592. - ZEBRA_IFA_UNNUMBERED)) {
  593. + ZEBRA_IFA_UNNUMBERED)
  594. + && !oi->ptp_dmvpn) {
  595. /* For unnumbered point-to-point networks, the
  596. Link Data field
  597. should specify the interface's MIB-II ifIndex
  598. @@ -500,7 +507,8 @@ static int lsa_link_ptop_set(struct stre
  599. }
  600. /* no need for a stub link for unnumbered interfaces */
  601. - if (!CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) {
  602. + if (oi->ptp_dmvpn
  603. + || !CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) {
  604. /* Regardless of the state of the neighboring router, we must
  605. add a Type 3 link (stub network).
  606. N.B. Options 1 & 2 share basically the same logic. */
  607. --- a/ospfd/ospf_vty.c
  608. +++ b/ospfd/ospf_vty.c
  609. @@ -7560,20 +7560,21 @@ DEFUN_HIDDEN (no_ospf_hello_interval,
  610. return no_ip_ospf_hello_interval(self, vty, argc, argv);
  611. }
  612. -DEFUN (ip_ospf_network,
  613. - ip_ospf_network_cmd,
  614. - "ip ospf network <broadcast|non-broadcast|point-to-multipoint|point-to-point>",
  615. - "IP Information\n"
  616. - "OSPF interface commands\n"
  617. - "Network type\n"
  618. - "Specify OSPF broadcast multi-access network\n"
  619. - "Specify OSPF NBMA network\n"
  620. - "Specify OSPF point-to-multipoint network\n"
  621. - "Specify OSPF point-to-point network\n")
  622. +DEFUN(ip_ospf_network, ip_ospf_network_cmd,
  623. + "ip ospf network <broadcast|non-broadcast|point-to-multipoint|point-to-point [dmvpn]>",
  624. + "IP Information\n"
  625. + "OSPF interface commands\n"
  626. + "Network type\n"
  627. + "Specify OSPF broadcast multi-access network\n"
  628. + "Specify OSPF NBMA network\n"
  629. + "Specify OSPF point-to-multipoint network\n"
  630. + "Specify OSPF point-to-point network\n"
  631. + "Specify OSPF point-to-point DMVPN network\n")
  632. {
  633. VTY_DECLVAR_CONTEXT(interface, ifp);
  634. int idx = 0;
  635. int old_type = IF_DEF_PARAMS(ifp)->type;
  636. + uint8_t old_ptp_dmvpn = IF_DEF_PARAMS(ifp)->ptp_dmvpn;
  637. struct route_node *rn;
  638. if (old_type == OSPF_IFTYPE_LOOPBACK) {
  639. @@ -7582,16 +7583,22 @@ DEFUN (ip_ospf_network,
  640. return CMD_WARNING_CONFIG_FAILED;
  641. }
  642. + IF_DEF_PARAMS(ifp)->ptp_dmvpn = 0;
  643. +
  644. if (argv_find(argv, argc, "broadcast", &idx))
  645. IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_BROADCAST;
  646. else if (argv_find(argv, argc, "non-broadcast", &idx))
  647. IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_NBMA;
  648. else if (argv_find(argv, argc, "point-to-multipoint", &idx))
  649. IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_POINTOMULTIPOINT;
  650. - else if (argv_find(argv, argc, "point-to-point", &idx))
  651. + else if (argv_find(argv, argc, "point-to-point", &idx)) {
  652. IF_DEF_PARAMS(ifp)->type = OSPF_IFTYPE_POINTOPOINT;
  653. + if (argv_find(argv, argc, "dmvpn", &idx))
  654. + IF_DEF_PARAMS(ifp)->ptp_dmvpn = 1;
  655. + }
  656. - if (IF_DEF_PARAMS(ifp)->type == old_type)
  657. + if (IF_DEF_PARAMS(ifp)->type == old_type
  658. + && IF_DEF_PARAMS(ifp)->ptp_dmvpn == old_ptp_dmvpn)
  659. return CMD_SUCCESS;
  660. SET_IF_PARAM(IF_DEF_PARAMS(ifp), type);
  661. @@ -7603,6 +7610,7 @@ DEFUN (ip_ospf_network,
  662. continue;
  663. oi->type = IF_DEF_PARAMS(ifp)->type;
  664. + oi->ptp_dmvpn = IF_DEF_PARAMS(ifp)->ptp_dmvpn;
  665. if (oi->state > ISM_Down) {
  666. OSPF_ISM_EVENT_EXECUTE(oi, ISM_InterfaceDown);
  667. @@ -7643,6 +7651,7 @@ DEFUN (no_ip_ospf_network,
  668. struct route_node *rn;
  669. IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp);
  670. + IF_DEF_PARAMS(ifp)->ptp_dmvpn = 0;
  671. if (IF_DEF_PARAMS(ifp)->type == old_type)
  672. return CMD_SUCCESS;
  673. @@ -9888,6 +9897,10 @@ static int config_write_interface_one(st
  674. vty_out(vty, " ip ospf network %s",
  675. ospf_int_type_str
  676. [params->type]);
  677. + if (params->type
  678. + == OSPF_IFTYPE_POINTOPOINT
  679. + && params->ptp_dmvpn)
  680. + vty_out(vty, " dmvpn");
  681. if (params != IF_DEF_PARAMS(ifp) && rn)
  682. vty_out(vty, " %s",
  683. inet_ntoa(
  684. --- a/ospfd/ospfd.c
  685. +++ b/ospfd/ospfd.c
  686. @@ -1017,6 +1017,7 @@ static void add_ospf_interface(struct co
  687. /* If network type is specified previously,
  688. skip network type setting. */
  689. oi->type = IF_DEF_PARAMS(co->ifp)->type;
  690. + oi->ptp_dmvpn = IF_DEF_PARAMS(co->ifp)->ptp_dmvpn;
  691. /* Add pseudo neighbor. */
  692. ospf_nbr_self_reset(oi, oi->ospf->router_id);
  693. --- a/doc/user/nhrpd.rst
  694. +++ b/doc/user/nhrpd.rst
  695. @@ -189,6 +189,34 @@ and
  696. https://git.alpinelinux.org/user/tteras/strongswan/log/?h=tteras
  697. git repositories for the patches.
  698. +.. _multicast-functionality:
  699. +
  700. +Multicast Functionality
  701. +=======================
  702. +
  703. +nhrpd can be configured to forward multicast packets, allowing routing
  704. +protocols that use multicast (such as OSPF) to be supported in the DMVPN
  705. +network.
  706. +
  707. +This support requires an NFLOG redirection rule to work:
  708. +
  709. + .. code-block:: shell
  710. +
  711. + iptables -I OUTPUT -d 224.0.0.0/24 -o gre1 -j NFLOG --nflog-group 2
  712. +
  713. +.. index:: nhrp multicast-nflog-group (1-65535)
  714. +.. clicmd:: nhrp multicast-nflog-group (1-65535)
  715. +
  716. + Sets the nflog group that nhrpd will listen on for multicast packets. This
  717. + value must match the nflog-group value set in the iptables rule.
  718. +
  719. +.. index:: ip nhrp map multicast A.B.C.D|X:X::X:X A.B.C.D|dynamic
  720. +.. clicmd:: ip nhrp map multicast A.B.C.D|X:X::X:X A.B.C.D|dynamic
  721. +
  722. + Sends multicast packets to the specified NBMA address. If dynamic is
  723. + specified then destination NBMA address (or addresses) are learnt
  724. + dynamically.
  725. +
  726. .. _nhrp-events:
  727. NHRP Events
  728. --- a/doc/user/ospfd.rst
  729. +++ b/doc/user/ospfd.rst
  730. @@ -687,8 +687,8 @@ Interfaces
  731. :clicmd:`ip ospf dead-interval minimal hello-multiplier (2-20)` is also
  732. specified for the interface.
  733. -.. index:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)
  734. -.. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point)
  735. +.. index:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point [dmvpn])
  736. +.. clicmd:: ip ospf network (broadcast|non-broadcast|point-to-multipoint|point-to-point [dmvpn])
  737. When configuring a point-to-point network on an interface and the interface
  738. has a /32 address associated with then OSPF will treat the interface
  739. @@ -870,6 +870,9 @@ Redistribution
  740. .. index:: no router zebra
  741. .. clicmd:: no router zebra
  742. + When used in a DMVPN network at a spoke, this OSPF will be configured in
  743. + point-to-point, but the HUB will be a point-to-multipoint. To make this
  744. + topology work, specify the optional 'dmvpn' parameter at the spoke.
  745. .. _showing-ospf-information: