forked from Mirror/frr
Merge pull request #16634 from nabahr/autorp
PIM: Implement AutoRP functionality
This commit is contained in:
commit
c0ccf381d4
|
@ -71,6 +71,31 @@ PIM Routers
|
|||
prefix of group ranges covered. This command is vrf aware, to configure for
|
||||
a vrf, specify the vrf in the router pim block.
|
||||
|
||||
.. clicmd:: no autorp discovery
|
||||
|
||||
In order to use pim, it is necessary to configure a RP for join messages to
|
||||
be sent to. FRR supports learning RP information dynamically via the AutoRP
|
||||
protocol and performs discovery by default. This command will disable the
|
||||
AutoRP discovery protocol.
|
||||
All routers in the pim network must agree on the network RP information, so
|
||||
all routers in the network should have AutoRP either enabled or disabled.
|
||||
This command is vrf aware, to configure for a vrf, specify the vrf in the
|
||||
router pim block.
|
||||
|
||||
.. clicmd:: autorp announce A.B.C.D [A.B.C.D/M | group-list PREFIX_LIST]
|
||||
|
||||
Configure the router to advertise itself as a candidate PIM-SM RP via AutoRP.
|
||||
The supported groups can be defined as a single group range, or multiple
|
||||
group ranges can be defined via a prefix list.
|
||||
|
||||
.. clicmd:: autorp announce {scope (1-255) | interval (1-65535) | holdtime (0-65535)}
|
||||
|
||||
Configure the AutoRP advertise messages. The scope defines the TTL value in the
|
||||
messages to limit the scope, defaults to 31. Interval defines the number of
|
||||
seconds elapsed between advertise messages sent, defaults to 60. Hold time defines
|
||||
how long the AutoRP mapping agent will consider the information valid, setting to
|
||||
0 will disable expiration of the candidate RP information, defaults to 3 * interval.
|
||||
|
||||
.. clicmd:: rp keep-alive-timer (1-65535)
|
||||
|
||||
Modify the time out value for a S,G flow from 1-65535 seconds at RP.
|
||||
|
@ -616,6 +641,11 @@ cause great confusion.
|
|||
192.168.10.123 239.0.0.0/8 eth2 yes Static ASM
|
||||
192.168.10.123 239.4.0.0/24 eth2 yes Static SSM
|
||||
|
||||
.. clicmd:: show ip pim [vrf NAME] autorp [json]
|
||||
|
||||
Display information about AutoRP. Including state of AutoRP Discovery parsing
|
||||
and configured AutoRP candidate RP information.
|
||||
|
||||
.. clicmd:: show ip pim rpf
|
||||
|
||||
Display information about currently being used S,G's and their RPF lookup
|
||||
|
@ -761,6 +791,10 @@ the config was written out.
|
|||
|
||||
This gathers data about events from zebra that come up through the ZAPI.
|
||||
|
||||
.. clicmd:: debug pim autorp
|
||||
|
||||
This turns on debugging for PIM AutoRP protocol events.
|
||||
|
||||
PIM Clear Commands
|
||||
==================
|
||||
Clear commands reset various variables.
|
||||
|
|
1147
pimd/pim_autorp.c
Normal file
1147
pimd/pim_autorp.c
Normal file
File diff suppressed because it is too large
Load diff
158
pimd/pim_autorp.h
Normal file
158
pimd/pim_autorp.h
Normal 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
|
147
pimd/pim_cmd.c
147
pimd/pim_cmd.c
|
@ -2820,6 +2820,75 @@ DEFPY (show_ip_pim_rp_vrf_all,
|
|||
(struct prefix *)group, !!json);
|
||||
}
|
||||
|
||||
DEFPY (show_ip_pim_autorp,
|
||||
show_ip_pim_autorp_cmd,
|
||||
"show ip pim [vrf NAME] autorp [json$json]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
PIM_STR
|
||||
VRF_CMD_HELP_STR
|
||||
"PIM AutoRP information\n"
|
||||
JSON_STR)
|
||||
{
|
||||
struct vrf *v;
|
||||
json_object *json_parent = NULL;
|
||||
|
||||
v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
|
||||
if (!v || !v->info) {
|
||||
if (!json)
|
||||
vty_out(vty, "%% Unable to find pim instance\n");
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (json)
|
||||
json_parent = json_object_new_object();
|
||||
|
||||
pim_autorp_show_autorp(vty, v->info, json_parent);
|
||||
|
||||
if (json)
|
||||
vty_json(vty, json_parent);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (show_ip_pim_autorp_vrf_all,
|
||||
show_ip_pim_autorp_vrf_all_cmd,
|
||||
"show ip pim vrf all autorp [json$json]",
|
||||
SHOW_STR
|
||||
IP_STR
|
||||
PIM_STR
|
||||
VRF_CMD_HELP_STR
|
||||
"PIM AutoRP information\n"
|
||||
JSON_STR)
|
||||
{
|
||||
struct vrf *vrf;
|
||||
json_object *json_parent = NULL;
|
||||
json_object *json_vrf = NULL;
|
||||
|
||||
if (json)
|
||||
json_parent = json_object_new_object();
|
||||
|
||||
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
|
||||
if (vrf->info) {
|
||||
if (!json)
|
||||
vty_out(vty, "VRF: %s\n", vrf->name);
|
||||
else
|
||||
json_vrf = json_object_new_object();
|
||||
|
||||
pim_autorp_show_autorp(vty, vrf->info, json_vrf);
|
||||
|
||||
if (json)
|
||||
json_object_object_add(json_parent, vrf->name,
|
||||
json_vrf);
|
||||
}
|
||||
}
|
||||
|
||||
if (json)
|
||||
vty_json(vty, json_parent);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFPY (show_ip_pim_rpf,
|
||||
show_ip_pim_rpf_cmd,
|
||||
"show ip pim [vrf NAME] rpf [json$json]",
|
||||
|
@ -4516,6 +4585,52 @@ DEFPY_ATTR(no_ip_pim_rp_prefix_list,
|
|||
return ret;
|
||||
}
|
||||
|
||||
DEFPY (pim_autorp_discovery,
|
||||
pim_autorp_discovery_cmd,
|
||||
"[no] autorp discovery",
|
||||
NO_STR
|
||||
"AutoRP\n"
|
||||
"Enable AutoRP discovery\n")
|
||||
{
|
||||
if (no)
|
||||
return pim_process_no_autorp_cmd(vty);
|
||||
else
|
||||
return pim_process_autorp_cmd(vty);
|
||||
}
|
||||
|
||||
DEFPY (pim_autorp_announce_rp,
|
||||
pim_autorp_announce_rp_cmd,
|
||||
"[no] autorp announce A.B.C.D$rpaddr ![A.B.C.D/M$grp|group-list PREFIX_LIST$plist]",
|
||||
NO_STR
|
||||
"AutoRP\n"
|
||||
"AutoRP Candidate RP announcement\n"
|
||||
"AutoRP Candidate RP address\n"
|
||||
"Group prefix\n"
|
||||
"Prefix list\n"
|
||||
"List name\n")
|
||||
{
|
||||
return pim_process_autorp_candidate_rp_cmd(vty, no, rpaddr_str, grp,
|
||||
plist);
|
||||
}
|
||||
|
||||
DEFPY (pim_autorp_announce_scope_int,
|
||||
pim_autorp_announce_scope_int_cmd,
|
||||
"[no] autorp announce ![{scope (1-255) | interval (1-65535) | holdtime (0-65535)}]",
|
||||
NO_STR
|
||||
"AutoRP\n"
|
||||
"AutoRP Candidate RP announcement\n"
|
||||
"Packet scope (TTL)\n"
|
||||
"TTL value\n"
|
||||
"Announcement interval\n"
|
||||
"Time in seconds\n"
|
||||
"Announcement holdtime\n"
|
||||
"Time in seconds\n")
|
||||
{
|
||||
return pim_process_autorp_announce_scope_int_cmd(vty, no, scope_str,
|
||||
interval_str,
|
||||
holdtime_str);
|
||||
}
|
||||
|
||||
DEFPY (pim_bsr_candidate_bsr,
|
||||
pim_bsr_candidate_bsr_cmd,
|
||||
"[no] bsr candidate-bsr [{priority (0-255)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]",
|
||||
|
@ -6377,6 +6492,29 @@ DEFUN (no_debug_bsm,
|
|||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (debug_autorp,
|
||||
debug_autorp_cmd,
|
||||
"debug pim autorp",
|
||||
DEBUG_STR
|
||||
DEBUG_PIM_STR
|
||||
DEBUG_PIM_AUTORP_STR)
|
||||
{
|
||||
PIM_DO_DEBUG_AUTORP;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN (no_debug_autorp,
|
||||
no_debug_autorp_cmd,
|
||||
"no debug pim autorp",
|
||||
NO_STR
|
||||
DEBUG_STR
|
||||
DEBUG_PIM_STR
|
||||
DEBUG_PIM_AUTORP_STR)
|
||||
{
|
||||
PIM_DONT_DEBUG_AUTORP;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
DEFUN_NOSH (show_debugging_pim,
|
||||
show_debugging_pim_cmd,
|
||||
|
@ -8714,6 +8852,9 @@ void pim_cmd_init(void)
|
|||
install_element(PIM_NODE, &no_pim_rp_cmd);
|
||||
install_element(PIM_NODE, &pim_rp_prefix_list_cmd);
|
||||
install_element(PIM_NODE, &no_pim_rp_prefix_list_cmd);
|
||||
install_element(PIM_NODE, &pim_autorp_discovery_cmd);
|
||||
install_element(PIM_NODE, &pim_autorp_announce_rp_cmd);
|
||||
install_element(PIM_NODE, &pim_autorp_announce_scope_int_cmd);
|
||||
install_element(PIM_NODE, &no_pim_ssm_prefix_list_cmd);
|
||||
install_element(PIM_NODE, &no_pim_ssm_prefix_list_name_cmd);
|
||||
install_element(PIM_NODE, &pim_ssm_prefix_list_cmd);
|
||||
|
@ -8868,6 +9009,8 @@ void pim_cmd_init(void)
|
|||
install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_pim_rp_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_pim_rp_vrf_all_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_pim_autorp_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_pim_autorp_vrf_all_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_pim_bsr_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_multicast_cmd);
|
||||
install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd);
|
||||
|
@ -8975,6 +9118,8 @@ void pim_cmd_init(void)
|
|||
install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd);
|
||||
install_element(ENABLE_NODE, &debug_ssmpingd_cmd);
|
||||
install_element(CONFIG_NODE, &debug_ssmpingd_cmd);
|
||||
install_element(ENABLE_NODE, &debug_autorp_cmd);
|
||||
install_element(ENABLE_NODE, &no_debug_autorp_cmd);
|
||||
install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd);
|
||||
install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd);
|
||||
install_element(ENABLE_NODE, &debug_pim_zebra_cmd);
|
||||
|
@ -9007,6 +9152,8 @@ void pim_cmd_init(void)
|
|||
install_element(CONFIG_NODE, &debug_bsm_cmd);
|
||||
install_element(ENABLE_NODE, &no_debug_bsm_cmd);
|
||||
install_element(CONFIG_NODE, &no_debug_bsm_cmd);
|
||||
install_element(CONFIG_NODE, &debug_autorp_cmd);
|
||||
install_element(CONFIG_NODE, &no_debug_autorp_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd);
|
||||
install_element(VRF_NODE, &ip_igmp_group_watermark_cmd);
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#define DEBUG_MSDP_PACKETS_STR "MSDP protocol packets\n"
|
||||
#define DEBUG_MTRACE_STR "Mtrace protocol activity\n"
|
||||
#define DEBUG_PIM_BSM_STR "BSR message processing activity\n"
|
||||
#define DEBUG_PIM_AUTORP_STR "AutoRP message processing activity\n"
|
||||
|
||||
|
||||
void pim_cmd_init(void);
|
||||
|
|
|
@ -606,6 +606,165 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
|
|||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
int pim_process_autorp_cmd(struct vty *vty)
|
||||
{
|
||||
char xpath[XPATH_MAXLEN];
|
||||
|
||||
snprintf(xpath, sizeof(xpath), "%s/%s", FRR_PIM_AUTORP_XPATH,
|
||||
"discovery-enabled");
|
||||
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true");
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
int pim_process_no_autorp_cmd(struct vty *vty)
|
||||
{
|
||||
char xpath[XPATH_MAXLEN];
|
||||
|
||||
snprintf(xpath, sizeof(xpath), "%s/%s", FRR_PIM_AUTORP_XPATH,
|
||||
"discovery-enabled");
|
||||
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
int pim_process_autorp_candidate_rp_cmd(struct vty *vty, bool no,
|
||||
const char *rpaddr_str,
|
||||
const struct prefix_ipv4 *grp,
|
||||
const char *plist)
|
||||
{
|
||||
char xpath[XPATH_MAXLEN];
|
||||
char grpstr[64];
|
||||
|
||||
if (no) {
|
||||
if (!is_default_prefix((const struct prefix *)grp) || plist) {
|
||||
/* If any single values are set, only destroy those */
|
||||
if (!is_default_prefix((const struct prefix *)grp)) {
|
||||
snprintfrr(xpath, sizeof(xpath),
|
||||
"%s/candidate-rp-list[rp-address='%s']/group",
|
||||
FRR_PIM_AUTORP_XPATH, rpaddr_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
|
||||
NULL);
|
||||
}
|
||||
if (plist) {
|
||||
snprintfrr(xpath, sizeof(xpath),
|
||||
"%s/candidate-rp-list[rp-address='%s']/prefix-list",
|
||||
FRR_PIM_AUTORP_XPATH, rpaddr_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
|
||||
NULL);
|
||||
}
|
||||
} else {
|
||||
/* No values set, remove the entire RP */
|
||||
snprintfrr(xpath, sizeof(xpath),
|
||||
"%s/candidate-rp-list[rp-address='%s']",
|
||||
FRR_PIM_AUTORP_XPATH, rpaddr_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||
}
|
||||
} else {
|
||||
if (!is_default_prefix((const struct prefix *)grp) || plist) {
|
||||
snprintfrr(xpath, sizeof(xpath),
|
||||
"%s/candidate-rp-list[rp-address='%s']",
|
||||
FRR_PIM_AUTORP_XPATH, rpaddr_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
|
||||
if (!is_default_prefix((const struct prefix *)grp)) {
|
||||
snprintfrr(xpath, sizeof(xpath),
|
||||
"%s/candidate-rp-list[rp-address='%s']/group",
|
||||
FRR_PIM_AUTORP_XPATH, rpaddr_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
prefix2str(grp, grpstr,
|
||||
sizeof(grpstr)));
|
||||
}
|
||||
if (plist) {
|
||||
snprintfrr(xpath, sizeof(xpath),
|
||||
"%s/candidate-rp-list[rp-address='%s']/prefix-list",
|
||||
FRR_PIM_AUTORP_XPATH, rpaddr_str);
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
plist);
|
||||
}
|
||||
} else {
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
int pim_process_autorp_announce_scope_int_cmd(struct vty *vty, bool no,
|
||||
const char *scope,
|
||||
const char *interval,
|
||||
const char *holdtime)
|
||||
{
|
||||
char xpath[XPATH_MAXLEN];
|
||||
|
||||
if (no) {
|
||||
if (scope || interval || holdtime) {
|
||||
/* If any single values are set, only destroy those */
|
||||
if (scope) {
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH,
|
||||
"announce-scope");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
|
||||
NULL);
|
||||
}
|
||||
if (interval) {
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH,
|
||||
"announce-interval");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
|
||||
NULL);
|
||||
}
|
||||
if (holdtime) {
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH,
|
||||
"announce-holdtime");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY,
|
||||
NULL);
|
||||
}
|
||||
} else {
|
||||
/* No values set, remove all */
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH, "announce-scope");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH, "announce-interval");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH, "announce-holdtime");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
|
||||
}
|
||||
} else {
|
||||
if (scope || interval || holdtime) {
|
||||
if (scope) {
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH,
|
||||
"announce-scope");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
scope);
|
||||
}
|
||||
if (interval) {
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH,
|
||||
"announce-interval");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
interval);
|
||||
}
|
||||
if (holdtime) {
|
||||
snprintfrr(xpath, sizeof(xpath), "%s/%s",
|
||||
FRR_PIM_AUTORP_XPATH,
|
||||
"announce-holdtime");
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY,
|
||||
holdtime);
|
||||
}
|
||||
} else {
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match)
|
||||
{
|
||||
return (pim_addr_is_any(match.grp) ||
|
||||
|
|
|
@ -35,7 +35,16 @@ int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str,
|
|||
const char *prefix_list);
|
||||
int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str,
|
||||
const char *prefix_list);
|
||||
|
||||
int pim_process_autorp_cmd(struct vty *vty);
|
||||
int pim_process_no_autorp_cmd(struct vty *vty);
|
||||
int pim_process_autorp_candidate_rp_cmd(struct vty *vty, bool no,
|
||||
const char *rpaddr_str,
|
||||
const struct prefix_ipv4 *grp,
|
||||
const char *plist);
|
||||
int pim_process_autorp_announce_scope_int_cmd(struct vty *vty, bool no,
|
||||
const char *scope,
|
||||
const char *interval,
|
||||
const char *holdtime);
|
||||
int pim_process_ip_pim_cmd(struct vty *vty);
|
||||
int pim_process_no_ip_pim_cmd(struct vty *vty);
|
||||
int pim_process_ip_pim_passive_cmd(struct vty *vty, bool enable);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -379,6 +379,55 @@ const struct frr_yang_module_info frr_pim_rp_info = {
|
|||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled",
|
||||
.cbs = {
|
||||
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope",
|
||||
.cbs = {
|
||||
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval",
|
||||
.cbs = {
|
||||
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-holdtime",
|
||||
.cbs = {
|
||||
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list",
|
||||
.cbs = {
|
||||
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/group",
|
||||
.cbs = {
|
||||
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/prefix-list",
|
||||
.cbs = {
|
||||
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify,
|
||||
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy,
|
||||
}
|
||||
},
|
||||
{
|
||||
.xpath = NULL,
|
||||
},
|
||||
|
|
|
@ -159,6 +159,34 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp
|
|||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create(
|
||||
struct nb_cb_create_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify(
|
||||
struct nb_cb_modify_args *args);
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy(
|
||||
struct nb_cb_destroy_args *args);
|
||||
|
||||
/* frr-cand-bsr */
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_bsr_create(
|
||||
|
@ -258,6 +286,7 @@ int routing_control_plane_protocols_name_validate(
|
|||
"mroute[source-addr='%s'][group-addr='%s']"
|
||||
#define FRR_PIM_STATIC_RP_XPATH \
|
||||
"frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']"
|
||||
#define FRR_PIM_AUTORP_XPATH "./frr-pim-rp:rp/auto-rp"
|
||||
#define FRR_GMP_INTERFACE_XPATH \
|
||||
"./frr-gmp:gmp/address-family[address-family='%s']"
|
||||
#define FRR_GMP_ENABLE_XPATH \
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "lib_errors.h"
|
||||
#include "pim_util.h"
|
||||
#include "pim6_mld.h"
|
||||
#include "pim_autorp.h"
|
||||
#include "pim_igmp.h"
|
||||
|
||||
#if PIM_IPV == 6
|
||||
|
@ -147,6 +148,11 @@ static int pim_cmd_interface_add(struct interface *ifp)
|
|||
pim_if_membership_refresh(ifp);
|
||||
|
||||
pim_if_create_pimreg(pim_ifp->pim);
|
||||
|
||||
#if PIM_IPV == 4
|
||||
pim_autorp_add_ifp(ifp);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2680,6 +2686,365 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp
|
|||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
bool enabled;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
enabled = yang_dnode_get_bool(args->dnode, NULL);
|
||||
if (enabled)
|
||||
pim_autorp_start_discovery(pim);
|
||||
else
|
||||
pim_autorp_stop_discovery(pim);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
bool enabled;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
enabled = yang_dnode_get_bool(args->dnode, NULL);
|
||||
/* Run AutoRP discovery by default */
|
||||
if (!enabled)
|
||||
pim_autorp_start_discovery(pim);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
uint8_t scope;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
scope = yang_dnode_get_uint8(args->dnode, NULL);
|
||||
pim_autorp_announce_scope(pim, scope);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
pim_autorp_announce_scope(pim, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
uint16_t interval;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
interval = yang_dnode_get_uint16(args->dnode, NULL);
|
||||
pim_autorp_announce_interval(pim, interval);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
pim_autorp_announce_interval(pim, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-holdtime
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
uint16_t holdtime;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
holdtime = yang_dnode_get_uint16(args->dnode, NULL);
|
||||
pim_autorp_announce_holdtime(pim, holdtime);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
/* 0 is a valid value, so -1 indicates deleting (go back to default) */
|
||||
pim_autorp_announce_holdtime(pim, -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create(
|
||||
struct nb_cb_create_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
case NB_EV_APPLY:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
pim_addr rp_addr;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
yang_dnode_get_pimaddr(&rp_addr, args->dnode, "rp-address");
|
||||
if (!pim_autorp_rm_candidate_rp(pim, rp_addr))
|
||||
return NB_ERR_INCONSISTENCY;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/group
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
struct prefix group;
|
||||
pim_addr rp_addr;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address");
|
||||
yang_dnode_get_prefix(&group, args->dnode, NULL);
|
||||
apply_mask(&group);
|
||||
pim_autorp_add_candidate_rp_group(pim, rp_addr, group);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
struct prefix group;
|
||||
pim_addr rp_addr;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address");
|
||||
yang_dnode_get_prefix(&group, args->dnode, NULL);
|
||||
apply_mask(&group);
|
||||
if (!pim_autorp_rm_candidate_rp_group(pim, rp_addr, group))
|
||||
return NB_ERR_INCONSISTENCY;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/prefix-list
|
||||
*/
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify(
|
||||
struct nb_cb_modify_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
pim_addr rp_addr;
|
||||
const char *plist;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
plist = yang_dnode_get_string(args->dnode, NULL);
|
||||
yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address");
|
||||
pim_autorp_add_candidate_rp_plist(pim, rp_addr, plist);
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy(
|
||||
struct nb_cb_destroy_args *args)
|
||||
{
|
||||
#if PIM_IPV == 4
|
||||
struct vrf *vrf;
|
||||
struct pim_instance *pim;
|
||||
pim_addr rp_addr;
|
||||
const char *plist;
|
||||
|
||||
switch (args->event) {
|
||||
case NB_EV_VALIDATE:
|
||||
case NB_EV_PREPARE:
|
||||
case NB_EV_ABORT:
|
||||
break;
|
||||
case NB_EV_APPLY:
|
||||
vrf = nb_running_get_entry(args->dnode, NULL, true);
|
||||
pim = vrf->info;
|
||||
yang_dnode_get_pimaddr(&rp_addr, args->dnode, "../rp-address");
|
||||
plist = yang_dnode_get_string(args->dnode, NULL);
|
||||
if (!pim_autorp_rm_candidate_rp_plist(pim, rp_addr, plist))
|
||||
return NB_ERR_INCONSISTENCY;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NB_OK;
|
||||
}
|
||||
|
||||
static void yang_addrsel(struct cand_addrsel *addrsel,
|
||||
const struct lyd_node *node)
|
||||
{
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -165,6 +165,11 @@ int pim_debug_config_write(struct vty *vty)
|
|||
++writes;
|
||||
}
|
||||
|
||||
if (PIM_DEBUG_AUTORP) {
|
||||
vty_out(vty, "debug pim autorp\n");
|
||||
++writes;
|
||||
}
|
||||
|
||||
return writes;
|
||||
}
|
||||
|
||||
|
@ -182,6 +187,9 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty)
|
|||
}
|
||||
|
||||
writes += pim_rp_config_write(pim, vty);
|
||||
#if PIM_IPV == 4
|
||||
writes += pim_autorp_config_write(pim, vty);
|
||||
#endif
|
||||
writes += pim_cand_config_write(pim, vty);
|
||||
|
||||
if (pim->vrf->vrf_id == VRF_DEFAULT) {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -1745,6 +1745,49 @@ def verify_pim_rp_info(
|
|||
return True
|
||||
|
||||
|
||||
@retry(retry_timeout=60, diag_pct=0)
|
||||
def verify_pim_rp_info_is_empty(tgen, dut, af="ipv4"):
|
||||
"""
|
||||
Verify pim rp info by running "show ip pim rp-info" cli
|
||||
|
||||
Parameters
|
||||
----------
|
||||
* `tgen`: topogen object
|
||||
* `dut`: device under test
|
||||
|
||||
Usage
|
||||
-----
|
||||
dut = "r1"
|
||||
result = verify_pim_rp_info_is_empty(tgen, dut)
|
||||
|
||||
Returns
|
||||
-------
|
||||
errormsg(str) or True
|
||||
"""
|
||||
|
||||
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
|
||||
|
||||
if dut not in tgen.routers():
|
||||
return False
|
||||
|
||||
rnode = tgen.routers()[dut]
|
||||
|
||||
ip_cmd = "ip"
|
||||
if af == "ipv6":
|
||||
ip_cmd = "ipv6"
|
||||
|
||||
logger.info("[DUT: %s]: Verifying %s rp info", dut, ip_cmd)
|
||||
cmd = "show {} pim rp-info json".format(ip_cmd)
|
||||
show_ip_rp_info_json = run_frr_cmd(rnode, cmd, isjson=True)
|
||||
|
||||
if show_ip_rp_info_json:
|
||||
errormsg = "[DUT %s]: Verifying empty rp-info [FAILED]!!" % (dut)
|
||||
return errormsg
|
||||
|
||||
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
|
||||
return True
|
||||
|
||||
|
||||
@retry(retry_timeout=60, diag_pct=0)
|
||||
def verify_pim_state(
|
||||
tgen,
|
||||
|
@ -2411,10 +2454,11 @@ def clear_igmp_interfaces(tgen, dut):
|
|||
|
||||
# Verify uptime for groups
|
||||
for group in group_before_clear.keys():
|
||||
d1 = datetime.datetime.strptime(group_before_clear[group], "%H:%M:%S")
|
||||
d2 = datetime.datetime.strptime(group_after_clear[group], "%H:%M:%S")
|
||||
if d2 >= d1:
|
||||
errormsg = ("[DUT: %s]: IGMP group is not cleared", " [FAILED!!]", dut)
|
||||
if group in group_after_clear:
|
||||
d1 = datetime.datetime.strptime(group_before_clear[group], "%H:%M:%S")
|
||||
d2 = datetime.datetime.strptime(group_after_clear[group], "%H:%M:%S")
|
||||
if d2 >= d1:
|
||||
errormsg = ("[DUT: %s]: IGMP group is not cleared", " [FAILED!!]", dut)
|
||||
|
||||
logger.info("[DUT: %s]: IGMP group is cleared [PASSED!!]")
|
||||
|
||||
|
@ -2751,6 +2795,48 @@ def scapy_send_bsr_raw_packet(tgen, topo, senderRouter, receiverRouter, packet=N
|
|||
return True
|
||||
|
||||
|
||||
def scapy_send_autorp_raw_packet(tgen, senderRouter, senderInterface, packet=None):
|
||||
"""
|
||||
Using scapy Raw() method to send AutoRP raw packet from one FRR
|
||||
to other
|
||||
|
||||
Parameters:
|
||||
-----------
|
||||
* `tgen` : Topogen object
|
||||
* `senderRouter` : Sender router
|
||||
* `senderInterface` : SenderInterface
|
||||
* `packet` : AutoRP packet in raw format
|
||||
|
||||
returns:
|
||||
--------
|
||||
errormsg or True
|
||||
"""
|
||||
|
||||
global CWD
|
||||
result = ""
|
||||
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
|
||||
|
||||
python3_path = tgen.net.get_exec_path(["python3", "python"])
|
||||
# send_bsr_packet.py has no direct ties to bsr, just sends a raw packet out
|
||||
# a given interface, so just reuse it
|
||||
script_path = os.path.join(CWD, "send_bsr_packet.py")
|
||||
node = tgen.net[senderRouter]
|
||||
|
||||
cmd = [
|
||||
python3_path,
|
||||
script_path,
|
||||
packet,
|
||||
senderInterface,
|
||||
"--interval=1",
|
||||
"--count=1",
|
||||
]
|
||||
logger.info("Scapy cmd: \n %s", cmd)
|
||||
node.cmd_raises(cmd)
|
||||
|
||||
logger.debug("Exiting lib API: scapy_send_autorp_raw_packet")
|
||||
return True
|
||||
|
||||
|
||||
def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None):
|
||||
"""
|
||||
Find which RP is having lowest prioriy and returns rp IP
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
|
||||
{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"totalGroups":5,
|
||||
"watermarkLimit":0,
|
||||
"l1-i1-eth1":{
|
||||
"name":"l1-i1-eth1",
|
||||
|
@ -48,4 +47,3 @@
|
|||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
|
||||
{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.1","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.2","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.3","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.4","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]},{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
{
|
||||
"totalGroups":5,
|
||||
"watermarkLimit":0,
|
||||
"l1-i1-eth1":{
|
||||
"name":"l1-i1-eth1",
|
||||
|
|
|
@ -1 +1 @@
|
|||
{"totalGroups":5,"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
|
||||
{"watermarkLimit":0,"l1-i1-eth1":{"name":"l1-i1-eth1","state":"up","address":"10.0.8.2","index":"*","flagMulticast":true,"flagBroadcast":true,"lanDelayEnabled":true,"groups":[{"group":"225.1.1.5","timer":"*","sourcesCount":1,"version":2,"uptime":"*","sources":[{"source":"*","timer":"*","forwarded":true,"uptime":"*"}]}]}}
|
||||
|
|
0
tests/topotests/pim_autorp/__init__.py
Executable file
0
tests/topotests/pim_autorp/__init__.py
Executable file
16
tests/topotests/pim_autorp/r1/frr.conf
Normal file
16
tests/topotests/pim_autorp/r1/frr.conf
Normal file
|
@ -0,0 +1,16 @@
|
|||
!
|
||||
hostname r1
|
||||
password zebra
|
||||
log file /tmp/r1-frr.log
|
||||
debug pim autorp
|
||||
!
|
||||
interface r1-eth0
|
||||
ip address 10.10.76.1/24
|
||||
ip igmp
|
||||
ip pim
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
router pim
|
||||
autorp discovery
|
||||
!
|
16
tests/topotests/pim_autorp/r2/frr.conf
Normal file
16
tests/topotests/pim_autorp/r2/frr.conf
Normal file
|
@ -0,0 +1,16 @@
|
|||
!
|
||||
hostname r2
|
||||
password zebra
|
||||
log file /tmp/r2-frr.log
|
||||
debug pim autorp
|
||||
!
|
||||
interface r2-eth0
|
||||
ip address 10.10.76.2/24
|
||||
ip igmp
|
||||
ip pim
|
||||
!
|
||||
ip forwarding
|
||||
!
|
||||
router pim
|
||||
autorp discovery
|
||||
!
|
207
tests/topotests/pim_autorp/test_pim_autorp.py
Normal file
207
tests/topotests/pim_autorp/test_pim_autorp.py
Normal file
|
@ -0,0 +1,207 @@
|
|||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: ISC
|
||||
|
||||
#
|
||||
# test_pim_autorp.py
|
||||
#
|
||||
# Copyright (c) 2024 ATCorp
|
||||
# Nathan Bahr
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pytest
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
from lib.topolog import logger
|
||||
from lib.pim import scapy_send_autorp_raw_packet, verify_pim_rp_info, verify_pim_rp_info_is_empty
|
||||
from lib.common_config import step, write_test_header
|
||||
|
||||
from time import sleep
|
||||
|
||||
"""
|
||||
test_pim_autorp.py: Test general PIM AutoRP functionality
|
||||
"""
|
||||
|
||||
TOPOLOGY = """
|
||||
Basic AutoRP functionality
|
||||
|
||||
+---+---+ +---+---+
|
||||
| | 10.10.76.0/24 | |
|
||||
+ R1 + <------------------> + R2 |
|
||||
| | .1 .2 | |
|
||||
+---+---+ +---+---+
|
||||
"""
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join(CWD, "../"))
|
||||
|
||||
# Required to instantiate the topology builder class.
|
||||
pytestmark = [pytest.mark.pimd]
|
||||
|
||||
|
||||
def build_topo(tgen):
|
||||
"Build function"
|
||||
|
||||
# Create routers
|
||||
tgen.add_router("r1")
|
||||
tgen.add_router("r2")
|
||||
|
||||
# Create link between router 1 and 2
|
||||
switch = tgen.add_switch("s1-2")
|
||||
switch.add_link(tgen.gears["r1"])
|
||||
switch.add_link(tgen.gears["r2"])
|
||||
|
||||
def setup_module(mod):
|
||||
logger.info("PIM AutoRP basic functionality:\n {}".format(TOPOLOGY))
|
||||
|
||||
tgen = Topogen(build_topo, mod.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
# Router 1 will be the router configured with "fake" autorp configuration, so give it a default route
|
||||
# to router 2 so that routing to the RP address is not an issue
|
||||
# r1_defrt_setup_cmds = [
|
||||
# "ip route add default via 10.10.76.1 dev r1-eth0",
|
||||
# ]
|
||||
# for cmd in r1_defrt_setup_cmds:
|
||||
# tgen.net["r1"].cmd(cmd)
|
||||
|
||||
logger.info("Testing PIM AutoRP support")
|
||||
router_list = tgen.routers()
|
||||
for rname, router in router_list.items():
|
||||
logger.info("Loading router %s" % rname)
|
||||
router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
|
||||
|
||||
# Initialize all routers.
|
||||
tgen.start_router()
|
||||
for router in router_list.values():
|
||||
if router.has_version("<", "4.0"):
|
||||
tgen.set_error("unsupported version")
|
||||
|
||||
|
||||
def teardown_module(mod):
|
||||
"Teardown the pytest environment"
|
||||
tgen = get_topogen()
|
||||
tgen.stop_topology()
|
||||
|
||||
def test_pim_autorp_discovery_single_rp(request):
|
||||
"Test PIM AutoRP Discovery with single RP"
|
||||
tgen = get_topogen()
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
step("Start with no RP configuration")
|
||||
result = verify_pim_rp_info_is_empty(tgen, "r1")
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
step("Send AutoRP packet from r1 to r2")
|
||||
# 1 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/4
|
||||
data = "01005e00012800127f55cfb1080045c00030700c000008110abe0a0a4c01e000012801f001f0001c798b12010005000000000a0a4c0103010004e0000000"
|
||||
scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data)
|
||||
|
||||
step("Verify rp-info from AutoRP packet")
|
||||
result = verify_pim_rp_info(tgen, None, "r2", "224.0.0.0/4", "r2-eth0", "10.10.76.1", "AutoRP", False, "ipv4", True)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
step("Verify AutoRP configuration times out")
|
||||
result = verify_pim_rp_info_is_empty(tgen, "r2")
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
def test_pim_autorp_discovery_multiple_rp(request):
|
||||
"Test PIM AutoRP Discovery with multiple RP's"
|
||||
tgen = get_topogen()
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip("skipped because of router(s) failure")
|
||||
|
||||
step("Start with no RP configuration")
|
||||
result = verify_pim_rp_info_is_empty(tgen, "r2")
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
step("Send AutoRP packet from r1 to r2")
|
||||
# 2 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/8, 10.10.76.3, group(s) 225.0.0.0/8
|
||||
data = "01005e00012800127f55cfb1080045c0003c700c000008110ab20a0a4c01e000012801f001f000283f5712020005000000000a0a4c0103010008e00000000a0a4c0303010008e1000000"
|
||||
scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data)
|
||||
|
||||
step("Verify rp-info from AutoRP packet")
|
||||
result = verify_pim_rp_info(tgen, None, "r2", "224.0.0.0/8", "r2-eth0", "10.10.76.1", "AutoRP", False, "ipv4", True)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
result = verify_pim_rp_info(tgen, None, "r2", "225.0.0.0/8", "r2-eth0", "10.10.76.3", "AutoRP", False, "ipv4", True)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
|
||||
def test_pim_autorp_discovery_static(request):
|
||||
"Test PIM AutoRP Discovery with Static RP"
|
||||
tgen = get_topogen()
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip("skipped because of router(s) failure")
|
||||
|
||||
step("Start with no RP configuration")
|
||||
result = verify_pim_rp_info_is_empty(tgen, "r2")
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
step("Add static RP configuration to r2")
|
||||
rnode = tgen.routers()["r2"]
|
||||
rnode.cmd("vtysh -c 'conf t' -c 'router pim' -c 'rp 10.10.76.3 224.0.0.0/4'")
|
||||
|
||||
step("Verify static rp-info from r2")
|
||||
result = verify_pim_rp_info(tgen, None, "r2", "224.0.0.0/4", "r2-eth0", "10.10.76.3", "Static", False, "ipv4", True)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
step("Send AutoRP packet from r1 to r2")
|
||||
# 1 RP(s), hold time 5 secs, 10.10.76.1, group(s) 224.0.0.0/4
|
||||
data = "01005e00012800127f55cfb1080045c00030700c000008110abe0a0a4c01e000012801f001f0001c798b12010005000000000a0a4c0103010004e0000000"
|
||||
scapy_send_autorp_raw_packet(tgen, "r1", "r1-eth0", data)
|
||||
|
||||
step("Verify rp-info from AutoRP packet")
|
||||
result = verify_pim_rp_info(tgen, None, "r2", "224.0.0.0/4", "r2-eth0", "10.10.76.1", "AutoRP", False, "ipv4", True)
|
||||
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
|
||||
|
||||
|
||||
def test_pim_autorp_announce_group(request):
|
||||
"Test PIM AutoRP Announcement with a single group"
|
||||
tgen = get_topogen()
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip("skipped because of router(s) failure")
|
||||
|
||||
step("Add candidate RP configuration to r1")
|
||||
rnode = tgen.routers()["r1"]
|
||||
rnode.cmd("vtysh -c 'conf t' -c 'router pim' -c 'send-rp-announce 10.10.76.1 224.0.0.0/4'")
|
||||
step("Verify Announcement sent data")
|
||||
# TODO: Verify AutoRP mapping agent receives candidate RP announcement
|
||||
# Mapping agent is not yet implemented
|
||||
#sleep(10)
|
||||
step("Change AutoRP Announcement packet parameters")
|
||||
rnode.cmd("vtysh -c 'conf t' -c 'router pim' -c 'send-rp-announce scope 8 interval 10 holdtime 60'")
|
||||
step("Verify Announcement sent data")
|
||||
# TODO: Verify AutoRP mapping agent receives updated candidate RP announcement
|
||||
# Mapping agent is not yet implemented
|
||||
#sleep(10)
|
||||
|
||||
|
||||
def test_memory_leak():
|
||||
"Run the memory leak test and report results."
|
||||
tgen = get_topogen()
|
||||
if not tgen.is_memleak_enabled():
|
||||
pytest.skip("Memory leak test/report is disabled")
|
||||
|
||||
tgen.report_memory_leaks()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
|
@ -111,6 +111,70 @@ module frr-pim-rp {
|
|||
} // static-rp
|
||||
} // static-rp-container
|
||||
|
||||
grouping auto-rp-container {
|
||||
description
|
||||
"Grouping of AutoRP container.";
|
||||
|
||||
container auto-rp {
|
||||
description
|
||||
"Containing AutoRP attributes.";
|
||||
|
||||
leaf discovery-enabled {
|
||||
type boolean;
|
||||
description
|
||||
"Flag indicating if Auto RP discovery is enabled.";
|
||||
}
|
||||
|
||||
leaf announce-scope {
|
||||
type uint8;
|
||||
description
|
||||
"The TTL of the C-RP Announcement packet.";
|
||||
}
|
||||
|
||||
leaf announce-interval {
|
||||
type uint16;
|
||||
description
|
||||
"The time between sending C-RP announcement packets.";
|
||||
}
|
||||
|
||||
leaf announce-holdtime {
|
||||
type uint16;
|
||||
description
|
||||
"The hold time in seconds advertised in the announcement packet.";
|
||||
}
|
||||
|
||||
list candidate-rp-list {
|
||||
key "rp-address";
|
||||
description
|
||||
"A list of Candidate RP addresses.";
|
||||
|
||||
leaf rp-address {
|
||||
type inet:ip-address;
|
||||
description
|
||||
"Specifies a candidate RP address.";
|
||||
}
|
||||
|
||||
choice group-or-prefix-list {
|
||||
description "Use group or prefix-list";
|
||||
case group {
|
||||
leaf group {
|
||||
type frr-route-types:ip-multicast-group-prefix;
|
||||
description
|
||||
"Multicast group prefix.";
|
||||
}
|
||||
}
|
||||
case prefix-list {
|
||||
leaf prefix-list {
|
||||
type plist-ref;
|
||||
description
|
||||
"Group prefix-list filter";
|
||||
}
|
||||
}
|
||||
}
|
||||
} // candidate-rp-list
|
||||
} // auto-rp
|
||||
} // auto-rp-container
|
||||
|
||||
/*
|
||||
* Configuration data nodes
|
||||
*/
|
||||
|
@ -123,6 +187,13 @@ module frr-pim-rp {
|
|||
description
|
||||
"PIM RP configuration data.";
|
||||
uses static-rp-container;
|
||||
|
||||
uses auto-rp-container {
|
||||
when "../frr-pim:address-family = 'frr-rt:ipv4'" {
|
||||
description
|
||||
"Only applicable to IPv4 address family.";
|
||||
}
|
||||
}
|
||||
} // rp
|
||||
} // augment
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue