pimd: Add AutoRP functionality to PIMD

Perform AutoRP discovery and candidate RP announcements using the
AutoRP protocol.
Mapping agent is not yet implemented, but this feature is not
necessary for FRR to support AutoRP as we only need one AutoRP
mapping agent in the network.

Signed-off-by: Nathan Bahr <nbahr@atcorp.com>
This commit is contained in:
Nathan Bahr 2024-09-17 02:32:59 +00:00
parent 269d63a5c1
commit f182255c0f
11 changed files with 1374 additions and 6 deletions

1147
pimd/pim_autorp.c Normal file

File diff suppressed because it is too large Load diff

158
pimd/pim_autorp.h Normal file
View file

@ -0,0 +1,158 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* pim_autorp.h: PIM Auto RP handling related
*
* Copyright (C) 20224 ATCorp.
* Nathan Bahr
*/
#ifndef __PIM_AUTORP_H__
#define __PIM_AUTORP_H__
#include <typesafe.h>
#define AUTORP_VERSION 1
#define AUTORP_ANNOUNCEMENT_TYPE 1
#define AUTORP_DISCOVERY_TYPE 2
#define PIM_VUNKNOWN 0
#define PIM_V1 1
#define PIM_V2 2
#define PIM_V1_2 3
#define DEFAULT_ANNOUNCE_INTERVAL 60
#define DEFAULT_ANNOUNCE_SCOPE 31
#define DEFAULT_ANNOUNCE_HOLDTIME -1
PREDECL_SORTLIST_UNIQ(pim_autorp_rp);
struct autorp_pkt_grp {
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t negprefix : 1;
uint8_t reserved : 7;
#elif __BYTE_ORDER == __BIG_ENDIAN
uint8_t reserved : 7;
uint8_t negprefix : 1;
#else
#error "Please fix <bits/endian.h>"
#endif
uint8_t masklen;
uint32_t addr;
} __attribute__((__packed__));
struct autorp_pkt_rp {
uint32_t addr;
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t pimver : 2;
uint8_t reserved : 6;
#elif __BYTE_ORDER == __BIG_ENDIAN
uint8_t reserved : 6;
uint8_t pimver : 2;
#else
#error "Please fix <bits/endian.h>"
#endif
uint8_t grpcnt;
} __attribute__((__packed__));
struct autorp_pkt_hdr {
#if __BYTE_ORDER == __LITTLE_ENDIAN
uint8_t type : 4;
uint8_t version : 4;
#elif __BYTE_ORDER == __BIG_ENDIAN
uint8_t version : 4;
uint8_t type : 4;
#else
#error "Please fix <bits/endian.h>"
#endif
uint8_t rpcnt;
uint16_t holdtime;
uint32_t reserved;
} __attribute__((__packed__));
#define MIN_AUTORP_PKT_SZ \
(sizeof(struct autorp_pkt_hdr) + sizeof(struct autorp_pkt_rp) + \
sizeof(struct autorp_pkt_grp))
struct pim_autorp_rp {
struct pim_autorp *autorp;
struct in_addr addr;
uint16_t holdtime;
struct event *hold_timer;
struct prefix grp;
char grplist[32];
struct pim_autorp_rp_item list;
};
struct pim_autorp {
/* backpointer to pim instance */
struct pim_instance *pim;
/* UDP socket bound to AutoRP port, used for sending and receiving all AutoRP packets */
int sock;
/* Event for reading AutoRP packets */
struct event *read_event;
/* Event for sending announcement packets */
struct event *announce_timer;
/* Event for sending discovery packets*/
/* struct event *discovery_timer; */
/* Flag enabling reading discovery packets */
bool do_discovery;
/* Flag enabling mapping agent (reading announcements and sending discovery)*/
/* bool do_mapping; */
/* List of RP's in received discovery packets */
struct pim_autorp_rp_head discovery_rp_list;
/* List of configured candidate RP's to send in announcement packets */
struct pim_autorp_rp_head candidate_rp_list;
/* List of announced RP's to send in discovery packets */
/* struct pim_autorp_rp_head mapping_rp_list; */
/* Packet parameters for sending announcement packets */
uint8_t announce_scope;
uint16_t announce_interval;
int32_t announce_holdtime;
/* Pre-built announcement packet, only changes when configured RP's or packet parameters change */
uint8_t *annouce_pkt;
uint16_t annouce_pkt_sz;
/* TODO: Packet parameters for sending discovery packets
* int discovery_scope;
* int discovery_interval;
* int discovery_holdtime;
*/
};
#define AUTORP_GRPLEN 6
#define AUTORP_RPLEN 6
#define AUTORP_HDRLEN 8
bool pim_autorp_rm_candidate_rp(struct pim_instance *pim, pim_addr rpaddr);
void pim_autorp_add_candidate_rp_group(struct pim_instance *pim,
pim_addr rpaddr, struct prefix group);
bool pim_autorp_rm_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr,
struct prefix group);
void pim_autorp_add_candidate_rp_plist(struct pim_instance *pim,
pim_addr rpaddr, const char *plist);
bool pim_autorp_rm_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr,
const char *plist);
void pim_autorp_announce_scope(struct pim_instance *pim, uint8_t scope);
void pim_autorp_announce_interval(struct pim_instance *pim, uint16_t interval);
void pim_autorp_announce_holdtime(struct pim_instance *pim, int32_t holdtime);
void pim_autorp_add_ifp(struct interface *ifp);
void pim_autorp_rm_ifp(struct interface *ifp);
void pim_autorp_start_discovery(struct pim_instance *pim);
void pim_autorp_stop_discovery(struct pim_instance *pim);
void pim_autorp_init(struct pim_instance *pim);
void pim_autorp_finish(struct pim_instance *pim);
int pim_autorp_config_write(struct pim_instance *pim, struct vty *vty);
void pim_autorp_show_autorp(struct vty *vty, struct pim_instance *pim,
json_object *json);
#endif

View file

@ -1914,6 +1914,12 @@ static int pim_ifp_up(struct interface *ifp)
}
}
#if PIM_IPV == 4
if (pim->autorp && pim->autorp->do_discovery && pim_ifp &&
pim_ifp->pim_enable)
pim_autorp_add_ifp(ifp);
#endif
pim_cand_addrs_changed();
return 0;
}
@ -1951,6 +1957,10 @@ static int pim_ifp_down(struct interface *ifp)
pim_ifstat_reset(ifp);
}
#if PIM_IPV == 4
pim_autorp_rm_ifp(ifp);
#endif
pim_cand_addrs_changed();
return 0;
}
@ -2023,6 +2033,11 @@ void pim_pim_interface_delete(struct interface *ifp)
if (!pim_ifp)
return;
#if PIM_IPV == 4
if (pim_ifp->pim_enable)
pim_autorp_rm_ifp(ifp);
#endif
pim_ifp->pim_enable = false;
pim_if_membership_clear(ifp);

View file

@ -57,6 +57,10 @@ static void pim_instance_terminate(struct pim_instance *pim)
pim_mroute_socket_disable(pim);
#if PIM_IPV == 4
pim_autorp_finish(pim);
#endif
XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
@ -125,6 +129,10 @@ static struct pim_instance *pim_instance_init(struct vrf *vrf)
pim->msdp.keep_alive = PIM_MSDP_PEER_KA_TIME;
pim->msdp.connection_retry = PIM_MSDP_PEER_CONNECT_RETRY_TIME;
#if PIM_IPV == 4
pim_autorp_init(pim);
#endif
return pim;
}

View file

@ -17,6 +17,7 @@
#include "pim_oil.h"
#include "pim_upstream.h"
#include "pim_mroute.h"
#include "pim_autorp.h"
enum pim_spt_switchover {
PIM_SPT_IMMEDIATE,
@ -152,6 +153,8 @@ struct pim_instance {
struct pim_msdp msdp;
struct pim_vxlan_instance vxlan;
struct pim_autorp *autorp;
struct list *ssmpingd_list;
pim_addr ssmpingd_group_addr;

View file

@ -1140,7 +1140,8 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty)
if (pim_rpf_addr_is_inaddr_any(&rp_info->rp))
continue;
if (rp_info->rp_src == RP_SRC_BSR)
if (rp_info->rp_src != RP_SRC_NONE &&
rp_info->rp_src != RP_SRC_STATIC)
continue;
rp_addr = rp_info->rp.rpf_addr;
@ -1200,6 +1201,8 @@ void pim_rp_show_information(struct pim_instance *pim, struct prefix *range,
strlcpy(source, "Static", sizeof(source));
else if (rp_info->rp_src == RP_SRC_BSR)
strlcpy(source, "BSR", sizeof(source));
else if (rp_info->rp_src == RP_SRC_AUTORP)
strlcpy(source, "AutoRP", sizeof(source));
else
strlcpy(source, "None", sizeof(source));
if (json) {

View file

@ -16,11 +16,7 @@
struct pim_interface;
enum rp_source {
RP_SRC_NONE = 0,
RP_SRC_STATIC,
RP_SRC_BSR
};
enum rp_source { RP_SRC_NONE = 0, RP_SRC_STATIC, RP_SRC_BSR, RP_SRC_AUTORP };
struct rp_info {
struct prefix group;

View file

@ -292,6 +292,36 @@ int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
return ret;
}
int pim_socket_leave(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
struct pim_interface *pim_ifp)
{
int ret;
#if PIM_IPV == 4
ret = setsockopt_ipv4_multicast(fd, IP_DROP_MEMBERSHIP, ifaddr,
group.s_addr, ifindex);
#else
struct ipv6_mreq opt;
memcpy(&opt.ipv6mr_multiaddr, &group, 16);
opt.ipv6mr_interface = ifindex;
ret = setsockopt(fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &opt, sizeof(opt));
#endif
if (ret) {
flog_err(EC_LIB_SOCKET,
"Failure socket leaving fd=%d group %pPAs on interface address %pPAs: %m",
fd, &group, &ifaddr);
pim_ifp->igmp_ifstat_joins_failed++;
return ret;
}
if (PIM_DEBUG_TRACE)
zlog_debug("Socket fd=%d left group %pPAs on interface address %pPAs",
fd, &group, &ifaddr);
return ret;
}
#if PIM_IPV == 4
static void cmsg_getdstaddr(struct msghdr *mh, struct sockaddr_storage *dst,
ifindex_t *ifindex)

View file

@ -32,6 +32,8 @@ int pim_socket_mcast(int protocol, pim_addr ifaddr, struct interface *ifp,
uint8_t loop);
int pim_socket_join(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
struct pim_interface *pim_ifp);
int pim_socket_leave(int fd, pim_addr group, pim_addr ifaddr, ifindex_t ifindex,
struct pim_interface *pim_ifp);
int pim_socket_recvfromto(int fd, uint8_t *buf, size_t len,
struct sockaddr_storage *from, socklen_t *fromlen,
struct sockaddr_storage *to, socklen_t *tolen,

View file

@ -95,6 +95,7 @@
#define PIM_MASK_VXLAN (1 << 26)
#define PIM_MASK_BSM_PROC (1 << 27)
#define PIM_MASK_MLAG (1 << 28)
#define PIM_MASK_AUTORP (1 << 29)
/* Remember 32 bits!!! */
/* PIM error codes */
@ -167,6 +168,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
#define PIM_DEBUG_MTRACE (router->debugs & PIM_MASK_MTRACE)
#define PIM_DEBUG_VXLAN (router->debugs & PIM_MASK_VXLAN)
#define PIM_DEBUG_BSM (router->debugs & PIM_MASK_BSM_PROC)
#define PIM_DEBUG_AUTORP (router->debugs & PIM_MASK_AUTORP)
#define PIM_DEBUG_EVENTS \
(router->debugs & (PIM_MASK_PIM_EVENTS | PIM_MASK_GM_EVENTS | \
@ -209,6 +211,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
#define PIM_DO_DEBUG_PIM_NHT_RP (router->debugs |= PIM_MASK_PIM_NHT_RP)
#define PIM_DO_DEBUG_MTRACE (router->debugs |= PIM_MASK_MTRACE)
#define PIM_DO_DEBUG_VXLAN (router->debugs |= PIM_MASK_VXLAN)
#define PIM_DO_DEBUG_AUTORP (router->debugs |= PIM_MASK_AUTORP)
#define PIM_DONT_DEBUG_PIM_EVENTS (router->debugs &= ~PIM_MASK_PIM_EVENTS)
#define PIM_DONT_DEBUG_PIM_PACKETS (router->debugs &= ~PIM_MASK_PIM_PACKETS)
@ -243,6 +246,7 @@ extern uint8_t qpim_ecmp_rebalance_enable;
#define PIM_DONT_DEBUG_MTRACE (router->debugs &= ~PIM_MASK_MTRACE)
#define PIM_DONT_DEBUG_VXLAN (router->debugs &= ~PIM_MASK_VXLAN)
#define PIM_DONT_DEBUG_BSM (router->debugs &= ~PIM_MASK_BSM_PROC)
#define PIM_DONT_DEBUG_AUTORP (router->debugs &= ~PIM_MASK_AUTORP)
/* RFC 3376: 8.1. Robustness Variable - Default: 2 for IGMP */
/* RFC 2710: 7.1. Robustness Variable - Default: 2 for MLD */

View file

@ -59,6 +59,7 @@ pim_common = \
pimd_pimd_SOURCES = \
$(pim_common) \
pimd/pim_autorp.c \
pimd/pim_cmd.c \
pimd/pim_igmp.c \
pimd/pim_igmp_mtrace.c \
@ -98,6 +99,7 @@ nodist_pimd_pim6d_SOURCES = \
noinst_HEADERS += \
pimd/pim_addr.h \
pimd/pim_assert.h \
pimd/pim_autorp.h \
pimd/pim_bfd.h \
pimd/pim_bsm.h \
pimd/pim_cmd.h \