mirror of
https://git.proxmox.com/git/mirror_frr
synced 2026-01-07 09:04:21 +00:00
Merge pull request #8153 from reubendowle/nhrp-multicast
nhrp, ospf: add nhrp multicast for OSPF DMVPN
This commit is contained in:
commit
d75213d260
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
305
nhrpd/nhrp_multicast.c
Normal file
305
nhrpd/nhrp_multicast.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
130
nhrpd/nhrp_vty.c
130
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);
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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. */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user