Skip to content

Commit 2500f17

Browse files
committed
UNTESTED: pimd: Candidate-RP support
WORK IN PROGRESS. Should be mostly functional, but only tested superficially at this point. Signed-off-by: David Lamparter <[email protected]>
1 parent 63220fa commit 2500f17

File tree

13 files changed

+1052
-0
lines changed

13 files changed

+1052
-0
lines changed

pimd/pim_bsm.c

Lines changed: 379 additions & 0 deletions
Large diffs are not rendered by default.

pimd/pim_bsm.h

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
#define PIM_BS_TIME 60 /* RFC 5059 - Sec 5 */
3636
#define PIM_BSR_DEFAULT_TIMEOUT 130 /* RFC 5059 - Sec 5 */
3737

38+
#define PIM_CRP_ADV_TRIGCOUNT 3
39+
#define PIM_CRP_ADV_INTERVAL 60
40+
#define PIM_CRP_HOLDTIME 150
41+
3842
/* These structures are only encoded IPv4 specific */
3943
#define PIM_BSM_HDR_LEN sizeof(struct bsm_hdr)
4044
#define PIM_BSM_GRP_LEN sizeof(struct bsmmsg_grpinfo)
@@ -54,7 +58,31 @@ enum ncbsr_state {
5458
ACCEPT_PREFERRED
5559
};
5660

61+
enum cand_addr {
62+
CAND_ADDR_LO = 0,
63+
CAND_ADDR_ANY,
64+
CAND_ADDR_IFACE,
65+
CAND_ADDR_EXPLICIT,
66+
};
67+
68+
/* used separately for Cand-RP, and (TBD) Cand-BSR */
69+
struct cand_addrsel {
70+
bool cfg_enable;
71+
enum cand_addr cfg_mode : 8;
72+
73+
/* only valid for mode==CAND_ADDR_IFACE */
74+
char cfg_ifname[INTERFACE_NAMSIZ];
75+
/* only valid for mode==CAND_ADDR_EXPLICIT */
76+
struct in_addr cfg_addr;
77+
78+
/* running state updated based on above on zebra events */
79+
struct in_addr run_addr;
80+
bool run;
81+
};
82+
83+
5784
PREDECL_DLIST(bsm_frags);
85+
PREDECL_RBTREE_UNIQ(cand_rp_groups);
5886

5987
/* BSM scope - bsm processing is per scope */
6088
struct bsm_scope {
@@ -74,6 +102,25 @@ struct bsm_scope {
74102

75103
struct route_table *bsrp_table; /* group2rp mapping rcvd from BSR */
76104
struct thread *bs_timer; /* Boot strap timer */
105+
106+
/* Candidate RP config */
107+
struct cand_addrsel cand_rp_addrsel;
108+
uint8_t cand_rp_prio;
109+
struct cand_rp_groups_head cand_rp_groups[1];
110+
111+
/* Candidate RP state */
112+
int unicast_sock;
113+
struct thread *cand_rp_adv_timer;
114+
unsigned int cand_rp_adv_trigger; /* # trigg. C-RP-Adv left to send */
115+
116+
/* for sending holdtime=0 zap */
117+
struct in_addr cand_rp_prev_addr;
118+
};
119+
120+
struct cand_rp_group {
121+
struct cand_rp_groups_item item;
122+
123+
struct prefix_ipv4 p;
77124
};
78125

79126
/* BSM packet (= fragment) - this is stored as list in bsm_frags inside scope
@@ -202,6 +249,14 @@ struct bsmmsg_rpinfo {
202249
uint8_t reserved;
203250
} __attribute__((packed));
204251

252+
struct cand_rp_msg {
253+
uint8_t prefix_cnt;
254+
uint8_t rp_prio;
255+
uint16_t rp_holdtime;
256+
struct pim_encoded_ipv4_unicast rp_addr;
257+
struct pim_encoded_group_ipv4 groups[0];
258+
} __attribute__((packed));
259+
205260
/* API */
206261
void pim_bsm_proc_init(struct pim_instance *pim);
207262
void pim_bsm_proc_free(struct pim_instance *pim);
@@ -215,4 +270,15 @@ int pim_bsm_process(struct interface *ifp,
215270
bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp);
216271
struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope,
217272
struct prefix *grp);
273+
274+
void pim_cand_rp_apply(struct bsm_scope *scope);
275+
void pim_cand_rp_trigger(struct bsm_scope *scope);
276+
void pim_cand_rp_grp_add(struct bsm_scope *scope, const struct prefix_ipv4 *p);
277+
void pim_cand_rp_grp_del(struct bsm_scope *scope, const struct prefix_ipv4 *p);
278+
279+
void pim_cand_addrs_changed(void);
280+
281+
int pim_cand_config_write(struct pim_instance *pim, struct vty *vty,
282+
const char *indent);
283+
218284
#endif

pimd/pim_cmd.c

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5647,6 +5647,66 @@ DEFUN (show_ip_pim_bsrp,
56475647
return CMD_SUCCESS;
56485648
}
56495649

5650+
DEFUN (show_ip_pim_cand_rp,
5651+
show_ip_pim_cand_rp_cmd,
5652+
"show ip pim candidate-rp [vrf NAME] [json]",
5653+
SHOW_STR
5654+
IP_STR
5655+
PIM_STR
5656+
"PIM Candidate RP state\n"
5657+
VRF_CMD_HELP_STR
5658+
JSON_STR)
5659+
{
5660+
int idx = 2;
5661+
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
5662+
struct pim_instance *pim;
5663+
struct bsm_scope *scope;
5664+
bool uj = use_json(argc, argv);
5665+
json_object *json = NULL;
5666+
5667+
if (!vrf || !vrf->info)
5668+
return CMD_WARNING;
5669+
5670+
pim = (struct pim_instance *)vrf->info;
5671+
scope = &pim->global_scope;
5672+
5673+
if (!scope->cand_rp_addrsel.run) {
5674+
if (uj)
5675+
vty_out(vty, "{}\n");
5676+
else
5677+
vty_out(vty,
5678+
"This router is not currently operating as Candidate RP\n");
5679+
return CMD_SUCCESS;
5680+
}
5681+
5682+
if (uj) {
5683+
char buf[INET_ADDRSTRLEN];
5684+
5685+
json = json_object_new_object();
5686+
inet_ntop(AF_INET, &scope->cand_rp_addrsel.run_addr, buf,
5687+
sizeof(buf));
5688+
json_object_string_add(json, "address", buf);
5689+
json_object_int_add(json, "priority", scope->cand_rp_prio);
5690+
json_object_int_add(
5691+
json, "nextAdvertisementMsec",
5692+
pim_time_timer_remain_msec(scope->cand_rp_adv_timer));
5693+
5694+
vty_out(vty, "%s\n",
5695+
json_object_to_json_string_ext(
5696+
json, JSON_C_TO_STRING_PRETTY));
5697+
json_object_free(json);
5698+
return CMD_SUCCESS;
5699+
}
5700+
5701+
vty_out(vty, "Candidate-RP\nAddress: %pI4\nPriority: %u\n\n",
5702+
&scope->cand_rp_addrsel.run_addr, scope->cand_rp_prio);
5703+
vty_out(vty, "Next adv.: %lu msec\n",
5704+
pim_time_timer_remain_msec(scope->cand_rp_adv_timer));
5705+
5706+
5707+
return CMD_SUCCESS;
5708+
}
5709+
56505710
DEFUN (show_ip_pim_statistics,
56515711
show_ip_pim_statistics_cmd,
56525712
"show ip pim [vrf NAME] statistics [interface WORD] [json]",
@@ -7441,6 +7501,124 @@ DEFUN (no_ip_pim_rp_prefix_list,
74417501
return nb_cli_apply_changes(vty, NULL);
74427502
}
74437503

7504+
DEFPY (ip_pim_candidate_rp,
7505+
ip_pim_candidate_rp_cmd,
7506+
"[no] ip pim candidate-rp [{priority (0-255)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]",
7507+
NO_STR
7508+
IP_STR
7509+
"pim multicast routing\n"
7510+
"Make this router a Candidate RP\n"
7511+
"RP Priority (lower wins)\n"
7512+
"RP Priority (lower wins)\n"
7513+
"Specify IP address for RP operation\n"
7514+
"Local address to use\n"
7515+
"Local address to use\n"
7516+
"Interface to pick address from\n"
7517+
"Interface to pick address from\n"
7518+
"Pick highest loopback address (default)\n"
7519+
"Pick highest address from any interface\n")
7520+
{
7521+
char cand_rp_xpath[XPATH_MAXLEN];
7522+
const struct lyd_node *vrf_dnode;
7523+
const char *vrfname;
7524+
7525+
if (vty->xpath_index) {
7526+
vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
7527+
VTY_CURR_XPATH);
7528+
7529+
if (!vrf_dnode) {
7530+
vty_out(vty,
7531+
"%% Failed to get vrf dnode in candidate db\n");
7532+
return CMD_WARNING_CONFIG_FAILED;
7533+
}
7534+
7535+
vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7536+
} else
7537+
vrfname = VRF_DEFAULT_NAME;
7538+
7539+
snprintf(cand_rp_xpath, sizeof(cand_rp_xpath), FRR_PIM_CAND_RP_XPATH,
7540+
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
7541+
7542+
if (no)
7543+
nb_cli_enqueue_change(vty, cand_rp_xpath, NB_OP_DESTROY, NULL);
7544+
else {
7545+
char xpath2[XPATH_MAXLEN + 12];
7546+
7547+
nb_cli_enqueue_change(vty, cand_rp_xpath, NB_OP_CREATE, NULL);
7548+
7549+
if (any) {
7550+
snprintf(xpath2, sizeof(xpath2), "%s/if-any",
7551+
cand_rp_xpath);
7552+
nb_cli_enqueue_change(vty, xpath2, NB_OP_CREATE, NULL);
7553+
} else if (ifname) {
7554+
snprintf(xpath2, sizeof(xpath2), "%s/interface",
7555+
cand_rp_xpath);
7556+
nb_cli_enqueue_change(vty, xpath2, NB_OP_CREATE,
7557+
ifname);
7558+
} else if (address_str) {
7559+
snprintf(xpath2, sizeof(xpath2), "%s/address",
7560+
cand_rp_xpath);
7561+
nb_cli_enqueue_change(vty, xpath2, NB_OP_CREATE,
7562+
address_str);
7563+
} else {
7564+
snprintf(xpath2, sizeof(xpath2), "%s/if-loopback",
7565+
cand_rp_xpath);
7566+
nb_cli_enqueue_change(vty, xpath2, NB_OP_CREATE, NULL);
7567+
}
7568+
7569+
if (priority_str) {
7570+
snprintf(xpath2, sizeof(xpath2), "%s/rp-priority",
7571+
cand_rp_xpath);
7572+
nb_cli_enqueue_change(vty, xpath2, NB_OP_MODIFY,
7573+
priority_str);
7574+
}
7575+
}
7576+
7577+
return nb_cli_apply_changes(vty, NULL);
7578+
}
7579+
7580+
DEFPY (ip_pim_candidate_rp_group,
7581+
ip_pim_candidate_rp_group_cmd,
7582+
"[no] ip pim candidate-rp group A.B.C.D/M",
7583+
NO_STR
7584+
IP_STR
7585+
"pim multicast routing\n"
7586+
"Make this router a Candidate RP\n"
7587+
"Configure groups to become candidate RP for\n"
7588+
"Multicast group prefix\n")
7589+
{
7590+
char cand_rp_xpath[XPATH_MAXLEN];
7591+
const struct lyd_node *vrf_dnode;
7592+
const char *vrfname;
7593+
7594+
if (vty->xpath_index) {
7595+
vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
7596+
VTY_CURR_XPATH);
7597+
7598+
if (!vrf_dnode) {
7599+
vty_out(vty,
7600+
"%% Failed to get vrf dnode in candidate db\n");
7601+
return CMD_WARNING_CONFIG_FAILED;
7602+
}
7603+
7604+
vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7605+
} else
7606+
vrfname = VRF_DEFAULT_NAME;
7607+
7608+
snprintf(cand_rp_xpath, sizeof(cand_rp_xpath),
7609+
FRR_PIM_CAND_RP_XPATH "/group-list", "frr-pim:pimd", "pim",
7610+
vrfname, "frr-routing:ipv4");
7611+
7612+
if (no)
7613+
nb_cli_enqueue_change(vty, cand_rp_xpath, NB_OP_DESTROY,
7614+
group_str);
7615+
else
7616+
nb_cli_enqueue_change(vty, cand_rp_xpath, NB_OP_CREATE,
7617+
group_str);
7618+
7619+
return nb_cli_apply_changes(vty, NULL);
7620+
}
7621+
74447622
DEFUN (ip_pim_ssm_prefix_list,
74457623
ip_pim_ssm_prefix_list_cmd,
74467624
"ip pim ssm prefix-list WORD",
@@ -10942,6 +11120,10 @@ void pim_cmd_init(void)
1094211120
install_element(VRF_NODE, &igmp_group_watermark_cmd);
1094311121
install_element(CONFIG_NODE, &no_igmp_group_watermark_cmd);
1094411122
install_element(VRF_NODE, &no_igmp_group_watermark_cmd);
11123+
install_element(CONFIG_NODE, &ip_pim_candidate_rp_cmd);
11124+
install_element(VRF_NODE, &ip_pim_candidate_rp_cmd);
11125+
install_element(CONFIG_NODE, &ip_pim_candidate_rp_group_cmd);
11126+
install_element(VRF_NODE, &ip_pim_candidate_rp_group_cmd);
1094511127

1094611128
install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
1094711129
install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
@@ -11042,6 +11224,7 @@ void pim_cmd_init(void)
1104211224
install_element(VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd);
1104311225
install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd);
1104411226
install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd);
11227+
install_element(VIEW_NODE, &show_ip_pim_cand_rp_cmd);
1104511228
install_element(VIEW_NODE, &show_ip_pim_statistics_cmd);
1104611229

1104711230
install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd);

pimd/pim_iface.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,8 @@ int pim_ifp_up(struct interface *ifp)
16661666
}
16671667
}
16681668
}
1669+
1670+
pim_cand_addrs_changed();
16691671
return 0;
16701672
}
16711673

@@ -1700,6 +1702,7 @@ int pim_ifp_down(struct interface *ifp)
17001702
if (ifp->info)
17011703
pim_if_del_vif(ifp);
17021704

1705+
pim_cand_addrs_changed();
17031706
return 0;
17041707
}
17051708

pimd/pim_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = {
8181
&frr_routing_info,
8282
&frr_pim_info,
8383
&frr_pim_rp_info,
84+
&frr_pim_candidate_info,
8485
&frr_igmp_info,
8586
};
8687

0 commit comments

Comments
 (0)