Skip to content

Commit 9c07752

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 50734ed commit 9c07752

File tree

13 files changed

+1035
-0
lines changed

13 files changed

+1035
-0
lines changed

pimd/pim_bsm.c

Lines changed: 368 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: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5735,6 +5735,60 @@ DEFUN (show_ip_pim_bsrp,
57355735
return CMD_SUCCESS;
57365736
}
57375737

5738+
DEFUN (show_ip_pim_cand_rp,
5739+
show_ip_pim_cand_rp_cmd,
5740+
"show ip pim candidate-rp [vrf NAME] [json]",
5741+
SHOW_STR
5742+
IP_STR
5743+
PIM_STR
5744+
"PIM Candidate RP state\n"
5745+
VRF_CMD_HELP_STR
5746+
JSON_STR)
5747+
{
5748+
int idx = 2;
5749+
struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
5750+
struct pim_instance *pim;
5751+
struct bsm_scope *scope;
5752+
bool uj = use_json(argc, argv);
5753+
json_object *json = NULL;
5754+
5755+
if (!vrf || !vrf->info)
5756+
return CMD_WARNING;
5757+
5758+
pim = (struct pim_instance *)vrf->info;
5759+
scope = &pim->global_scope;
5760+
5761+
if (!scope->cand_rp_addrsel.run) {
5762+
if (uj)
5763+
vty_out(vty, "{}\n");
5764+
else
5765+
vty_out(vty,
5766+
"This router is not currently operating as Candidate RP\n");
5767+
return CMD_SUCCESS;
5768+
}
5769+
5770+
if (uj) {
5771+
char buf[INET_ADDRSTRLEN];
5772+
5773+
json = json_object_new_object();
5774+
inet_ntop(AF_INET, &scope->cand_rp_addrsel.run_addr, buf,
5775+
sizeof(buf));
5776+
json_object_string_add(json, "address", buf);
5777+
json_object_int_add(json, "priority", scope->cand_rp_prio);
5778+
5779+
vty_out(vty, "%s\n",
5780+
json_object_to_json_string_ext(
5781+
json, JSON_C_TO_STRING_PRETTY));
5782+
json_object_free(json);
5783+
return CMD_SUCCESS;
5784+
}
5785+
5786+
vty_out(vty, "Candidate-RP\nAddress: %pI4\nPriority: %u\n",
5787+
&scope->cand_rp_addrsel.run_addr, scope->cand_rp_prio);
5788+
5789+
return CMD_SUCCESS;
5790+
}
5791+
57385792
DEFUN (show_ip_pim_statistics,
57395793
show_ip_pim_statistics_cmd,
57405794
"show ip pim [vrf NAME] statistics [interface WORD] [json]",
@@ -7543,6 +7597,124 @@ DEFUN (no_ip_pim_rp_prefix_list,
75437597
return nb_cli_apply_changes(vty, NULL);
75447598
}
75457599

7600+
DEFPY (ip_pim_candidate_rp,
7601+
ip_pim_candidate_rp_cmd,
7602+
"[no] ip pim candidate-rp [{priority (0-255)|source <address A.B.C.D|interface IFNAME|loopback$loopback|any$any>}]",
7603+
NO_STR
7604+
IP_STR
7605+
"pim multicast routing\n"
7606+
"Make this router a Candidate RP\n"
7607+
"RP Priority (lower wins)\n"
7608+
"RP Priority (lower wins)\n"
7609+
"Specify IP address for RP operation\n"
7610+
"Local address to use\n"
7611+
"Local address to use\n"
7612+
"Interface to pick address from\n"
7613+
"Interface to pick address from\n"
7614+
"Pick highest loopback address (default)\n"
7615+
"Pick highest address from any interface\n")
7616+
{
7617+
char cand_rp_xpath[XPATH_MAXLEN];
7618+
const struct lyd_node *vrf_dnode;
7619+
const char *vrfname;
7620+
7621+
if (vty->xpath_index) {
7622+
vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
7623+
VTY_CURR_XPATH);
7624+
7625+
if (!vrf_dnode) {
7626+
vty_out(vty,
7627+
"%% Failed to get vrf dnode in candidate db\n");
7628+
return CMD_WARNING_CONFIG_FAILED;
7629+
}
7630+
7631+
vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7632+
} else
7633+
vrfname = VRF_DEFAULT_NAME;
7634+
7635+
snprintf(cand_rp_xpath, sizeof(cand_rp_xpath), FRR_PIM_CAND_RP_XPATH,
7636+
"frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4");
7637+
7638+
if (no)
7639+
nb_cli_enqueue_change(vty, cand_rp_xpath, NB_OP_DESTROY, NULL);
7640+
else {
7641+
char xpath2[XPATH_MAXLEN + 12];
7642+
7643+
nb_cli_enqueue_change(vty, cand_rp_xpath, NB_OP_CREATE, NULL);
7644+
7645+
if (any) {
7646+
snprintf(xpath2, sizeof(xpath2), "%s/if-any",
7647+
cand_rp_xpath);
7648+
nb_cli_enqueue_change(vty, xpath2, NB_OP_CREATE, NULL);
7649+
} else if (ifname) {
7650+
snprintf(xpath2, sizeof(xpath2), "%s/interface",
7651+
cand_rp_xpath);
7652+
nb_cli_enqueue_change(vty, xpath2, NB_OP_CREATE,
7653+
ifname);
7654+
} else if (address_str) {
7655+
snprintf(xpath2, sizeof(xpath2), "%s/address",
7656+
cand_rp_xpath);
7657+
nb_cli_enqueue_change(vty, xpath2, NB_OP_CREATE,
7658+
address_str);
7659+
} else {
7660+
snprintf(xpath2, sizeof(xpath2), "%s/if-loopback",
7661+
cand_rp_xpath);
7662+
nb_cli_enqueue_change(vty, xpath2, NB_OP_CREATE, NULL);
7663+
}
7664+
7665+
if (priority_str) {
7666+
snprintf(xpath2, sizeof(xpath2), "%s/rp-priority",
7667+
cand_rp_xpath);
7668+
nb_cli_enqueue_change(vty, xpath2, NB_OP_MODIFY,
7669+
priority_str);
7670+
}
7671+
}
7672+
7673+
return nb_cli_apply_changes(vty, NULL);
7674+
}
7675+
7676+
DEFPY (ip_pim_candidate_rp_group,
7677+
ip_pim_candidate_rp_group_cmd,
7678+
"[no] ip pim candidate-rp group A.B.C.D/M",
7679+
NO_STR
7680+
IP_STR
7681+
"pim multicast routing\n"
7682+
"Make this router a Candidate RP\n"
7683+
"Configure groups to become candidate RP for\n"
7684+
"Multicast group prefix\n")
7685+
{
7686+
char cand_rp_xpath[XPATH_MAXLEN];
7687+
const struct lyd_node *vrf_dnode;
7688+
const char *vrfname;
7689+
7690+
if (vty->xpath_index) {
7691+
vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
7692+
VTY_CURR_XPATH);
7693+
7694+
if (!vrf_dnode) {
7695+
vty_out(vty,
7696+
"%% Failed to get vrf dnode in candidate db\n");
7697+
return CMD_WARNING_CONFIG_FAILED;
7698+
}
7699+
7700+
vrfname = yang_dnode_get_string(vrf_dnode, "./name");
7701+
} else
7702+
vrfname = VRF_DEFAULT_NAME;
7703+
7704+
snprintf(cand_rp_xpath, sizeof(cand_rp_xpath),
7705+
FRR_PIM_CAND_RP_XPATH "/group-list", "frr-pim:pimd", "pim",
7706+
vrfname, "frr-routing:ipv4");
7707+
7708+
if (no)
7709+
nb_cli_enqueue_change(vty, cand_rp_xpath, NB_OP_DESTROY,
7710+
group_str);
7711+
else
7712+
nb_cli_enqueue_change(vty, cand_rp_xpath, NB_OP_CREATE,
7713+
group_str);
7714+
7715+
return nb_cli_apply_changes(vty, NULL);
7716+
}
7717+
75467718
DEFUN (ip_pim_ssm_prefix_list,
75477719
ip_pim_ssm_prefix_list_cmd,
75487720
"ip pim ssm prefix-list WORD",
@@ -11050,6 +11222,10 @@ void pim_cmd_init(void)
1105011222
install_element(VRF_NODE, &igmp_group_watermark_cmd);
1105111223
install_element(CONFIG_NODE, &no_igmp_group_watermark_cmd);
1105211224
install_element(VRF_NODE, &no_igmp_group_watermark_cmd);
11225+
install_element(CONFIG_NODE, &ip_pim_candidate_rp_cmd);
11226+
install_element(VRF_NODE, &ip_pim_candidate_rp_cmd);
11227+
install_element(CONFIG_NODE, &ip_pim_candidate_rp_group_cmd);
11228+
install_element(VRF_NODE, &ip_pim_candidate_rp_group_cmd);
1105311229

1105411230
install_element(INTERFACE_NODE, &interface_ip_igmp_cmd);
1105511231
install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd);
@@ -11150,6 +11326,7 @@ void pim_cmd_init(void)
1115011326
install_element(VIEW_NODE, &show_ip_pim_nexthop_lookup_cmd);
1115111327
install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd);
1115211328
install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd);
11329+
install_element(VIEW_NODE, &show_ip_pim_cand_rp_cmd);
1115311330
install_element(VIEW_NODE, &show_ip_pim_statistics_cmd);
1115411331

1115511332
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
@@ -1662,6 +1662,8 @@ int pim_ifp_up(struct interface *ifp)
16621662
}
16631663
}
16641664
}
1665+
1666+
pim_cand_addrs_changed();
16651667
return 0;
16661668
}
16671669

@@ -1696,6 +1698,7 @@ int pim_ifp_down(struct interface *ifp)
16961698
if (ifp->info)
16971699
pim_if_del_vif(ifp);
16981700

1701+
pim_cand_addrs_changed();
16991702
return 0;
17001703
}
17011704

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

pimd/pim_nb.c

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,64 @@ const struct frr_yang_module_info frr_pim_rp_info = {
365365
}
366366
};
367367

368+
const struct frr_yang_module_info frr_pim_candidate_info = {
369+
.name = "frr-pim-candidate",
370+
.nodes = {
371+
/* Candidate-RP */
372+
{
373+
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp",
374+
.cbs = {
375+
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_create,
376+
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_destroy,
377+
}
378+
},
379+
{
380+
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/rp-priority",
381+
.cbs = {
382+
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_priority_modify,
383+
}
384+
},
385+
{
386+
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/group-list",
387+
.cbs = {
388+
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_create,
389+
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_group_list_destroy,
390+
}
391+
},
392+
{
393+
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/address",
394+
.cbs = {
395+
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify,
396+
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
397+
}
398+
},
399+
{
400+
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/interface",
401+
.cbs = {
402+
.modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_modify,
403+
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
404+
}
405+
},
406+
{
407+
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/if-loopback",
408+
.cbs = {
409+
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create,
410+
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
411+
}
412+
},
413+
{
414+
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-candidate:candidate-rp/if-any",
415+
.cbs = {
416+
.create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_create,
417+
.destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_candidate_rp_addrsel_destroy,
418+
}
419+
},
420+
{
421+
.xpath = NULL,
422+
},
423+
}
424+
};
425+
368426
/* clang-format off */
369427
const struct frr_yang_module_info frr_igmp_info = {
370428
.name = "frr-igmp",

0 commit comments

Comments
 (0)