diff options
author | Jafar Al-Gharaibeh <Jafaral@users.noreply.github.com> | 2021-04-13 19:49:28 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-13 19:49:28 +0200 |
commit | d75213d26036a2880f23f5e67cb1c890f20299de (patch) | |
tree | 704214848af1d599fa2b945c0f7e311a9923f6e6 | |
parent | Merge pull request #8414 from idryzhov/fix-filter-cli (diff) | |
parent | nhrpd: Change sockunion2str to %pSU in a few places (diff) | |
download | frr-d75213d26036a2880f23f5e67cb1c890f20299de.tar.xz frr-d75213d26036a2880f23f5e67cb1c890f20299de.zip |
Merge pull request #8153 from reubendowle/nhrp-multicast
nhrp, ospf: add nhrp multicast for OSPF DMVPN
-rw-r--r-- | doc/user/nhrpd.rst | 31 | ||||
-rw-r--r-- | doc/user/ospfd.rst | 5 | ||||
-rw-r--r-- | nhrpd/linux.c | 18 | ||||
-rw-r--r-- | nhrpd/netlink.h | 1 | ||||
-rw-r--r-- | nhrpd/nhrp_interface.c | 2 | ||||
-rw-r--r-- | nhrpd/nhrp_multicast.c | 305 | ||||
-rw-r--r-- | nhrpd/nhrp_peer.c | 2 | ||||
-rw-r--r-- | nhrpd/nhrp_vty.c | 130 | ||||
-rw-r--r-- | nhrpd/nhrpd.h | 18 | ||||
-rw-r--r-- | nhrpd/os.h | 2 | ||||
-rw-r--r-- | nhrpd/subdir.am | 1 | ||||
-rw-r--r-- | ospfd/ospf_interface.c | 2 | ||||
-rw-r--r-- | ospfd/ospf_interface.h | 6 | ||||
-rw-r--r-- | ospfd/ospf_lsa.c | 12 | ||||
-rw-r--r-- | ospfd/ospf_packet.c | 18 | ||||
-rw-r--r-- | ospfd/ospf_spf.c | 4 | ||||
-rw-r--r-- | ospfd/ospf_vty.c | 37 | ||||
-rw-r--r-- | ospfd/ospfd.c | 1 |
18 files changed, 549 insertions, 46 deletions
diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index b02e761ac..cbbc2dc10 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -180,6 +180,37 @@ https://git-old.alpinelinux.org/user/tteras/strongswan/ Actively maintained patches are also available at: https://gitlab.alpinelinux.org/alpine/aports/-/tree/master/main/strongswan +.. _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 diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 800530901..7d1e91dc4 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -587,7 +587,7 @@ Interfaces :clicmd:`ip ospf dead-interval minimal hello-multiplier (2-20)` is also specified for the interface. -.. clicmd:: 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 [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 @@ -595,6 +595,9 @@ Interfaces net.ipv4.conf.<interface name>.rp_filter value to 0. In order for the ospf multicast packets to be delivered by the kernel. + 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. Set explicitly network type for specified interface. diff --git a/nhrpd/linux.c b/nhrpd/linux.c index 9cabdbf06..bcf97f030 100644 --- 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_t len, int ifindex, const uint8_t *addr, 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 char *iface, int on) { 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; diff --git a/nhrpd/netlink.h b/nhrpd/netlink.h index 74cb81daa..5e971cabf 100644 --- 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); diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index f6d89b141..402ffe9a2 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -42,6 +42,7 @@ static int nhrp_if_new_hook(struct interface *ifp) 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 interface *ifp) nhrp_cache_interface_del(ifp); nhrp_nhs_interface_del(ifp); + nhrp_multicast_interface_del(ifp); nhrp_peer_interface_del(ifp); if (nifp->ipsec_profile) diff --git a/nhrpd/nhrp_multicast.c b/nhrpd/nhrp_multicast.c new file mode 100644 index 000000000..b78afda2c --- /dev/null +++ b/nhrpd/nhrp_multicast.c @@ -0,0 +1,305 @@ +/* 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) +{ + 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: %pSU -> %pSU, ret = %d, size = %zu, addrlen = %zu", + &p->vc->local.nbma, &p->vc->remote.nbma, 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, + "Intercepted multicast packet leaving %s len %zu", + 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; + + 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); + + debugf(NHRP_DEBUG_COMMON, "Adding multicast entry (%pSU)", nbma_addr); + + 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; + + list_for_each_entry_safe(mcast, tmp, &nifp->afi[afi].mcastlist_head, + list_entry) + { + if (!sockunion_same(&mcast->nbma_addr, nbma_addr)) + continue; + + debugf(NHRP_DEBUG_COMMON, "Deleting multicast entry (%pSU)", + nbma_addr); + + 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); + } +} diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index a44190d29..5a7da703a 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -376,7 +376,7 @@ void nhrp_peer_send(struct nhrp_peer *p, struct zbuf *zb) 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); } diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 4358605e2..420ea12ec 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -187,6 +187,9 @@ static int nhrp_config_write(struct vty *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_group_cmd, 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" @@ -570,6 +598,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 @@ -732,8 +807,8 @@ static void show_ip_nhrp_nhs(struct nhrp_nhs *n, struct nhrp_registration *reg, 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], @@ -1047,19 +1122,20 @@ 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; - char buf[2][SU_ADDRSTRLEN]; 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->type == NHRP_CACHE_LOCAL - ? "local" : sockunion2str(&c->nbma, buf[1], sizeof(buf[1]))); + vty_out(vty, " %s nhrp map %pSU ", ctx->aficmd, &c->remote_addr); + if (c->type == NHRP_CACHE_LOCAL) + vty_out(vty, "local\n"); + else + vty_out(vty, "%pSU\n", &c->nbma); } static int interface_config_write(struct vty *vty) @@ -1069,9 +1145,9 @@ static int interface_config_write(struct vty *vty) 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]; int i; FOR_ALL_INTERFACES (vrf, ifp) { @@ -1122,21 +1198,31 @@ static int interface_config_write(struct vty *vty) .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) { - vty_out(vty, " %s nhrp nhs %s nbma %s\n", - aficmd, - sockunion_family(&nhs->proto_addr) - == AF_UNSPEC - ? "dynamic" - : sockunion2str( - &nhs->proto_addr, buf, - sizeof(buf)), - nhs->nbma_fqdn); + vty_out(vty, " %s nhrp nhs ", aficmd); + if (sockunion_family(&nhs->proto_addr) + == AF_UNSPEC) + vty_out(vty, "dynamic"); + else + vty_out(vty, "%pSU", &nhs->proto_addr); + vty_out(vty, "nbma %s\n", nhs->nbma_fqdn); + } + + list_for_each_entry(mcast, &ad->mcastlist_head, + list_entry) + { + vty_out(vty, " %s nhrp map multicast ", aficmd); + if (sockunion_family(&mcast->nbma_addr) + == AF_UNSPEC) + vty_out(vty, "dynamic\n"); + else + vty_out(vty, "%pSU\n", + &mcast->nbma_addr); } } @@ -1171,6 +1257,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); @@ -1192,6 +1280,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); } diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 136f855df..730f9b7d1 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -269,6 +269,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; @@ -314,6 +321,7 @@ struct nhrp_interface { unsigned short mtu; unsigned int holdtime; struct list_head nhslist_head; + struct list_head mcastlist_head; } afi[AFI_MAX]; }; @@ -356,6 +364,16 @@ void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, 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, diff --git a/nhrpd/os.h b/nhrpd/os.h index dd65d3cbe..2b9e07fa6 100644 --- 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); diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index 61b1fe31b..d00aecc1e 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -22,6 +22,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 \ diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 6e4bc7abf..334ed33ee 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -543,6 +543,8 @@ static struct ospf_if_params *ospf_new_if_params(void) oip->network_lsa_seqnum = htonl(OSPF_INITIAL_SEQUENCE_NUMBER); oip->is_v_wait_set = false; + oip->ptp_dmvpn = 0; + return oip; } diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index e2d732738..4a2114724 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -118,6 +118,9 @@ struct ospf_if_params { /* MPLS LDP-IGP Sync configuration */ struct ldp_sync_info *ldp_sync_info; + + /* point-to-point DMVPN configuration */ + uint8_t ptp_dmvpn; }; enum { MEMBER_ALLROUTERS = 0, @@ -180,6 +183,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; diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index cb1c565d3..6e9df77fb 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -469,6 +469,12 @@ char link_info_set(struct stream **s, struct in_addr id, struct in_addr data, } /* 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 stream **s, struct ospf_interface *oi) 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 stream **s, struct ospf_interface *oi) } /* 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. */ diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 0fd4803c7..aa98d7dd2 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -799,7 +799,13 @@ static int ospf_write(struct thread *thread) &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 %pI4, id %d, off %d, len %d, interface %s, mtu %u: %s", @@ -907,8 +913,11 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh, /* 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, @@ -2427,6 +2436,11 @@ static int ospf_check_network_mask(struct ospf_interface *oi, || 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; diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c index 95553dacd..0164bfac6 100644 --- a/ospfd/ospf_spf.c +++ b/ospfd/ospf_spf.c @@ -905,7 +905,9 @@ static unsigned int ospf_nexthop_calculation(struct ospf_area *area, * somehow. */ if (area->ospf->ti_lfa_enabled - || (oi && oi->type == OSPF_IFTYPE_POINTOPOINT)) { + || (oi && oi->type == OSPF_IFTYPE_POINTOPOINT) + || (oi && oi->type == OSPF_IFTYPE_POINTOMULTIPOINT + && oi->address->prefixlen == IPV4_MAX_BITLEN)) { struct ospf_neighbor *nbr_w = NULL; /* Calculating node is root node, link diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 2d06e6884..be446705e 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -8391,6 +8391,7 @@ DEFUN (no_ip_ospf_hello_interval, 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); @@ -8418,20 +8419,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) { @@ -8440,16 +8442,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); @@ -8501,6 +8509,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; @@ -11643,6 +11652,10 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) 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, " %pI4", &rn->p.u.prefix4); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 259209a73..9949a7833 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -1076,6 +1076,7 @@ struct ospf_interface *add_ospf_interface(struct connected *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); |