diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 3fabe1706c..1d89ec100a 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -8851,6 +8851,24 @@ done: return ret; } +DEFPY_YANG(pim_rpf_lookup_mode, pim_rpf_lookup_mode_cmd, + "[no] rpf-lookup-mode ![urib-only|mrib-only|mrib-then-urib|lower-distance|longer-prefix]$mode", + NO_STR + "RPF lookup behavior\n" + "Lookup in unicast RIB only\n" + "Lookup in multicast RIB only\n" + "Try multicast RIB first, fall back to unicast RIB\n" + "Lookup both, use entry with lower distance\n" + "Lookup both, use entry with longer prefix\n") +{ + if (no) + nb_cli_enqueue_change(vty, "./mcast-rpf-lookup", NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, "./mcast-rpf-lookup", NB_OP_MODIFY, mode); + + return nb_cli_apply_changes(vty, NULL); +} + struct cmd_node pim_node = { .name = "pim", .node = PIM_NODE, @@ -9017,6 +9035,8 @@ void pim_cmd_init(void) install_element(PIM_NODE, &pim_bsr_candidate_rp_group_cmd); install_element(PIM_NODE, &pim_bsr_candidate_bsr_cmd); + install_element(PIM_NODE, &pim_rpf_lookup_mode_cmd); + install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_join_cmd); diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index 93acb5e9fd..d491cd63c6 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -116,6 +116,7 @@ struct pim_instance { char *register_plist; struct hash *rpf_hash; + enum pim_rpf_lookup_mode rpf_mode; void *ssm_info; /* per-vrf SSM configuration */ diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index b5d20419dd..7bb529d44c 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -256,6 +256,12 @@ const struct frr_yang_module_info frr_pim_info = { .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mcast-rpf-lookup", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_mcast_rpf_lookup_modify, + } + }, { .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 7d30db04be..15ae74e711 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -100,6 +100,8 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_re struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy( struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mcast_rpf_lookup_modify( + struct nb_cb_modify_args *args); int lib_interface_pim_address_family_dr_priority_modify( struct nb_cb_modify_args *args); int lib_interface_pim_address_family_create(struct nb_cb_create_args *args); diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index fb7047aa49..905bc5a137 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -1846,6 +1846,34 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_re return NB_OK; } +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mcast-rpf-lookup + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mcast_rpf_lookup_modify( + struct nb_cb_modify_args *args) +{ + struct vrf *vrf; + struct pim_instance *pim; + enum pim_rpf_lookup_mode old_mode; + + 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; + old_mode = pim->rpf_mode; + pim->rpf_mode = yang_dnode_get_enum(args->dnode, NULL); + + /* TODO: Signal to redo lookups? */ + break; + } + + return NB_OK; +} + /* * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family */ @@ -2666,9 +2694,8 @@ int lib_interface_pim_address_family_mroute_oif_modify( #ifdef PIM_ENFORCE_LOOPFREE_MFC iif = nb_running_get_entry(args->dnode, NULL, false); - if (!iif) { + if (!iif) return NB_OK; - } pim_iifp = iif->info; pim = pim_iifp->pim; diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index 7dae53f8fc..6ff4d87b55 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -41,6 +41,17 @@ struct pim_rpf { enum pim_rpf_result { PIM_RPF_OK = 0, PIM_RPF_CHANGED, PIM_RPF_FAILURE }; +/* RPF lookup behaviour */ +enum pim_rpf_lookup_mode { + MCAST_NO_CONFIG = 0, /* MIX_MRIB_FIRST, but no show in config write */ + MCAST_MRIB_ONLY, /* MRIB only */ + MCAST_URIB_ONLY, /* URIB only */ + MCAST_MIX_MRIB_FIRST, /* MRIB, if nothing at all then URIB */ + MCAST_MIX_DISTANCE, /* MRIB & URIB, lower distance wins */ + MCAST_MIX_PFXLEN, /* MRIB & URIB, longer prefix wins */ + /* on equal value, MRIB wins for last 2 */ +}; + struct pim_upstream; unsigned int pim_rpf_hash_key(const void *arg); diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index fc9781b239..974cf30cf1 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -275,6 +275,16 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) } } + if (pim->rpf_mode != MCAST_NO_CONFIG) { + ++writes; + vty_out(vty, " rpf-lookup-mode %s\n", + pim->rpf_mode == MCAST_URIB_ONLY ? "urib-only" + : pim->rpf_mode == MCAST_MRIB_ONLY ? "mrib-only" + : pim->rpf_mode == MCAST_MIX_MRIB_FIRST ? "mrib-then-urib" + : pim->rpf_mode == MCAST_MIX_DISTANCE ? "lower-distance" + : "longer-prefix"); + } + return writes; } diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 6e5fc3c6ce..e371894474 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -82,6 +82,47 @@ module frr-pim { type string; } + /* + * Multicast RPF mode configurable type + */ + + typedef mcast-rpf-lookup-mode { + type enumeration { + enum "none" { + value 0; + description + "No mode set."; + } + enum "mrib-only" { + value 1; + description + "Lookup in unicast RIB only."; + } + enum "urib-only" { + value 2; + description + "Lookup in multicast RIB only."; + } + enum "mrib-then-urib" { + value 3; + description + "Try multicast RIB first, fall back to unicast RIB."; + } + enum "lower-distance" { + value 4; + description + "Lookup both unicast and mcast, use entry with lower distance."; + } + enum "longer-prefix" { + value 5; + description + "Lookup both unicast and mcast, use entry with longer prefix."; + } + } + description + "Multicast RPF lookup behavior"; + } + /* * Groupings */ @@ -161,20 +202,27 @@ module frr-pim { description "A grouping defining per address family pim global attributes"; + leaf mcast-rpf-lookup { + type mcast-rpf-lookup-mode; + default "none"; + description + "Multicast RPF lookup behavior."; + } + leaf ecmp { type boolean; default "false"; description "Enable PIM ECMP."; } - + leaf ecmp-rebalance { type boolean; default "false"; description "Enable PIM ECMP Rebalance."; } - + leaf keep-alive-timer { type uint16 { range "1..max"; @@ -183,7 +231,7 @@ module frr-pim { description "Keep alive Timer in seconds."; } - + leaf rp-keep-alive-timer { type uint16 { range "1..max";