mirror_frr/pimd/pim_nb_config.c
Igor Ryzhov 4ba756ed9c *: fix aborts when validating configuration
There are places in the code where function nb_running_get_entry is used
with abort_if_not_found set to true during the config validation stage.
This is incorrect because when used in transactional CLI, the running
entry won't be set until the apply stage, and such usage leads to crash.

Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
2021-03-16 17:25:49 +03:00

3071 lines
70 KiB
C

/*
* Copyright (C) 2020 VmWare
* Sarita Patra
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "pimd.h"
#include "pim_nb.h"
#include "lib/northbound_cli.h"
#include "pim_igmpv3.h"
#include "pim_pim.h"
#include "pim_mlag.h"
#include "pim_bfd.h"
#include "pim_static.h"
#include "pim_ssm.h"
#include "pim_ssmpingd.h"
#include "pim_vxlan.h"
#include "log.h"
#include "lib_errors.h"
static void pim_if_membership_clear(struct interface *ifp)
{
struct pim_interface *pim_ifp;
pim_ifp = ifp->info;
zassert(pim_ifp);
if (PIM_IF_TEST_PIM(pim_ifp->options)
&& PIM_IF_TEST_IGMP(pim_ifp->options)) {
return;
}
pim_ifchannel_membership_clear(ifp);
}
/*
* When PIM is disabled on interface, IGMPv3 local membership
* information is not injected into PIM interface state.
* The function pim_if_membership_refresh() fetches all IGMPv3 local
* membership information into PIM. It is intented to be called
* whenever PIM is enabled on the interface in order to collect missed
* local membership information.
*/
static void pim_if_membership_refresh(struct interface *ifp)
{
struct pim_interface *pim_ifp;
struct listnode *sock_node;
struct igmp_sock *igmp;
pim_ifp = ifp->info;
zassert(pim_ifp);
if (!PIM_IF_TEST_PIM(pim_ifp->options))
return;
if (!PIM_IF_TEST_IGMP(pim_ifp->options))
return;
/*
* First clear off membership from all PIM (S,G) entries on the
* interface
*/
pim_ifchannel_membership_clear(ifp);
/*
* Then restore PIM (S,G) membership from all IGMPv3 (S,G) entries on
* the interface
*/
/* scan igmp sockets */
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
struct listnode *grpnode;
struct igmp_group *grp;
/* scan igmp groups */
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grpnode,
grp)) {
struct listnode *srcnode;
struct igmp_source *src;
/* scan group sources */
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
srcnode, src)) {
if (IGMP_SOURCE_TEST_FORWARDING(
src->source_flags)) {
struct prefix_sg sg;
memset(&sg, 0,
sizeof(struct prefix_sg));
sg.src = src->source_addr;
sg.grp = grp->group_addr;
pim_ifchannel_local_membership_add(
ifp, &sg, false /*is_vxlan*/);
}
} /* scan group sources */
} /* scan igmp groups */
} /* scan igmp sockets */
/*
* Finally delete every PIM (S,G) entry lacking all state info
*/
pim_ifchannel_delete_on_noinfo(ifp);
}
static int pim_cmd_interface_add(struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp)
pim_ifp = pim_if_new(ifp, false, true, false, false);
else
PIM_IF_DO_PIM(pim_ifp->options);
pim_if_addr_add_all(ifp);
pim_if_membership_refresh(ifp);
pim_if_create_pimreg(pim_ifp->pim);
return 1;
}
static int pim_cmd_interface_delete(struct interface *ifp)
{
struct pim_interface *pim_ifp = ifp->info;
if (!pim_ifp)
return 1;
PIM_IF_DONT_PIM(pim_ifp->options);
pim_if_membership_clear(ifp);
/*
* pim_sock_delete() removes all neighbors from
* pim_ifp->pim_neighbor_list.
*/
pim_sock_delete(ifp, "pim unconfigured on interface");
if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
pim_if_addr_del_all(ifp);
pim_if_delete(ifp);
}
return 1;
}
static int interface_pim_use_src_cmd_worker(struct interface *ifp,
struct in_addr source_addr,
char *errmsg, size_t errmsg_len)
{
int result;
int ret = NB_OK;
result = pim_update_source_set(ifp, source_addr);
switch (result) {
case PIM_SUCCESS:
break;
case PIM_IFACE_NOT_FOUND:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"Pim not enabled on this interface %s",
ifp->name);
break;
case PIM_UPDATE_SOURCE_DUP:
ret = NB_ERR;
snprintf(errmsg, errmsg_len, "Source already set");
break;
default:
ret = NB_ERR;
snprintf(errmsg, errmsg_len, "Source set failed");
}
return ret;
}
static int pim_cmd_spt_switchover(struct pim_instance *pim,
enum pim_spt_switchover spt,
const char *plist)
{
pim->spt.switchover = spt;
switch (pim->spt.switchover) {
case PIM_SPT_IMMEDIATE:
XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
pim_upstream_add_lhr_star_pimreg(pim);
break;
case PIM_SPT_INFINITY:
pim_upstream_remove_lhr_star_pimreg(pim, plist);
XFREE(MTYPE_PIM_PLIST_NAME, pim->spt.plist);
if (plist)
pim->spt.plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist);
break;
}
return NB_OK;
}
static int pim_ssm_cmd_worker(struct pim_instance *pim, const char *plist,
char *errmsg, size_t errmsg_len)
{
int result = pim_ssm_range_set(pim, pim->vrf_id, plist);
int ret = NB_ERR;
if (result == PIM_SSM_ERR_NONE)
return NB_OK;
switch (result) {
case PIM_SSM_ERR_NO_VRF:
snprintf(errmsg, errmsg_len,
"VRF doesn't exist");
break;
case PIM_SSM_ERR_DUP:
snprintf(errmsg, errmsg_len,
"duplicate config");
break;
default:
snprintf(errmsg, errmsg_len,
"ssm range config failed");
}
return ret;
}
static int ip_no_msdp_mesh_group_cmd_worker(struct pim_instance *pim,
const char *mg,
char *errmsg, size_t errmsg_len)
{
enum pim_msdp_err result;
result = pim_msdp_mg_del(pim, mg);
switch (result) {
case PIM_MSDP_ERR_NONE:
break;
case PIM_MSDP_ERR_NO_MG:
snprintf(errmsg, errmsg_len,
"%% mesh-group does not exist");
break;
default:
snprintf(errmsg, errmsg_len,
"mesh-group source del failed");
}
return result ? NB_ERR : NB_OK;
}
static int ip_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
const char *mg,
struct in_addr mbr_ip,
char *errmsg, size_t errmsg_len)
{
enum pim_msdp_err result;
int ret = NB_OK;
result = pim_msdp_mg_mbr_add(pim, mg, mbr_ip);
switch (result) {
case PIM_MSDP_ERR_NONE:
break;
case PIM_MSDP_ERR_OOM:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"%% Out of memory");
break;
case PIM_MSDP_ERR_MG_MBR_EXISTS:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"%% mesh-group member exists");
break;
case PIM_MSDP_ERR_MAX_MESH_GROUPS:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"%% Only one mesh-group allowed currently");
break;
default:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"%% member add failed");
}
return ret;
}
static int ip_no_msdp_mesh_group_member_cmd_worker(struct pim_instance *pim,
const char *mg,
struct in_addr mbr_ip,
char *errmsg,
size_t errmsg_len)
{
enum pim_msdp_err result;
result = pim_msdp_mg_mbr_del(pim, mg, mbr_ip);
switch (result) {
case PIM_MSDP_ERR_NONE:
break;
case PIM_MSDP_ERR_NO_MG:
snprintf(errmsg, errmsg_len,
"%% mesh-group does not exist");
break;
case PIM_MSDP_ERR_NO_MG_MBR:
snprintf(errmsg, errmsg_len,
"%% mesh-group member does not exist");
break;
default:
snprintf(errmsg, errmsg_len,
"%% mesh-group member del failed");
}
return result ? NB_ERR : NB_OK;
}
static int ip_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
const char *mg,
struct in_addr src_ip,
char *errmsg, size_t errmsg_len)
{
enum pim_msdp_err result;
result = pim_msdp_mg_src_add(pim, mg, src_ip);
switch (result) {
case PIM_MSDP_ERR_NONE:
break;
case PIM_MSDP_ERR_OOM:
snprintf(errmsg, errmsg_len,
"%% Out of memory");
break;
case PIM_MSDP_ERR_MAX_MESH_GROUPS:
snprintf(errmsg, errmsg_len,
"%% Only one mesh-group allowed currently");
break;
default:
snprintf(errmsg, errmsg_len,
"%% source add failed");
}
return result ? NB_ERR : NB_OK;
}
static int ip_no_msdp_mesh_group_source_cmd_worker(struct pim_instance *pim,
const char *mg,
char *errmsg,
size_t errmsg_len)
{
enum pim_msdp_err result;
result = pim_msdp_mg_src_del(pim, mg);
switch (result) {
case PIM_MSDP_ERR_NONE:
break;
case PIM_MSDP_ERR_NO_MG:
snprintf(errmsg, errmsg_len,
"%% mesh-group does not exist");
break;
default:
snprintf(errmsg, errmsg_len,
"%% mesh-group source del failed");
}
return result ? NB_ERR : NB_OK;
}
static int ip_msdp_peer_cmd_worker(struct pim_instance *pim,
struct in_addr peer_addr,
struct in_addr local_addr,
char *errmsg, size_t errmsg_len)
{
enum pim_msdp_err result;
int ret = NB_OK;
result = pim_msdp_peer_add(pim, peer_addr, local_addr, "default",
NULL /* mp_p */);
switch (result) {
case PIM_MSDP_ERR_NONE:
break;
case PIM_MSDP_ERR_OOM:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"%% Out of memory");
break;
case PIM_MSDP_ERR_PEER_EXISTS:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"%% Peer exists");
break;
case PIM_MSDP_ERR_MAX_MESH_GROUPS:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"%% Only one mesh-group allowed currently");
break;
default:
ret = NB_ERR;
snprintf(errmsg, errmsg_len,
"%% peer add failed");
}
return ret;
}
static int ip_no_msdp_peer_cmd_worker(struct pim_instance *pim,
struct in_addr peer_addr,
char *errmsg, size_t errmsg_len)
{
enum pim_msdp_err result;
result = pim_msdp_peer_del(pim, peer_addr);
switch (result) {
case PIM_MSDP_ERR_NONE:
break;
case PIM_MSDP_ERR_NO_PEER:
snprintf(errmsg, errmsg_len,
"%% Peer does not exist");
break;
default:
snprintf(errmsg, errmsg_len,
"%% peer del failed");
}
return result ? NB_ERR : NB_OK;
}
static int pim_rp_cmd_worker(struct pim_instance *pim,
struct in_addr rp_addr,
struct prefix group, const char *plist,
char *errmsg, size_t errmsg_len)
{
char rp_str[INET_ADDRSTRLEN];
int result;
inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str));
result = pim_rp_new(pim, rp_addr, group, plist, RP_SRC_STATIC);
if (result == PIM_RP_NO_PATH) {
snprintf(errmsg, errmsg_len,
"No Path to RP address specified: %s", rp_str);
return NB_ERR_INCONSISTENCY;
}
if (result == PIM_GROUP_OVERLAP) {
snprintf(errmsg, errmsg_len,
"Group range specified cannot exact match another");
return NB_ERR_INCONSISTENCY;
}
if (result == PIM_GROUP_PFXLIST_OVERLAP) {
snprintf(errmsg, errmsg_len,
"This group is already covered by a RP prefix-list");
return NB_ERR_INCONSISTENCY;
}
if (result == PIM_RP_PFXLIST_IN_USE) {
snprintf(errmsg, errmsg_len,
"The same prefix-list cannot be applied to multiple RPs");
return NB_ERR_INCONSISTENCY;
}
return NB_OK;
}
static int pim_no_rp_cmd_worker(struct pim_instance *pim,
struct in_addr rp_addr, struct prefix group,
const char *plist,
char *errmsg, size_t errmsg_len)
{
char rp_str[INET_ADDRSTRLEN];
char group_str[PREFIX2STR_BUFFER];
int result;
inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str));
prefix2str(&group, group_str, sizeof(group_str));
result = pim_rp_del(pim, rp_addr, group, plist, RP_SRC_STATIC);
if (result == PIM_GROUP_BAD_ADDRESS) {
snprintf(errmsg, errmsg_len,
"Bad group address specified: %s", group_str);
return NB_ERR_INCONSISTENCY;
}
if (result == PIM_RP_BAD_ADDRESS) {
snprintf(errmsg, errmsg_len,
"Bad RP address specified: %s", rp_str);
return NB_ERR_INCONSISTENCY;
}
if (result == PIM_RP_NOT_FOUND) {
snprintf(errmsg, errmsg_len,
"Unable to find specified RP");
return NB_ERR_INCONSISTENCY;
}
return NB_OK;
}
static bool is_pim_interface(const struct lyd_node *dnode)
{
char if_xpath[XPATH_MAXLEN];
const struct lyd_node *pim_enable_dnode;
const struct lyd_node *igmp_enable_dnode;
yang_dnode_get_path(dnode, if_xpath, sizeof(if_xpath));
pim_enable_dnode = yang_dnode_get(dnode, "%s/frr-pim:pim/pim-enable",
if_xpath);
igmp_enable_dnode = yang_dnode_get(dnode,
"%s/frr-igmp:igmp/igmp-enable",
if_xpath);
if (((pim_enable_dnode) &&
(yang_dnode_get_bool(pim_enable_dnode, "."))) ||
((igmp_enable_dnode) &&
(yang_dnode_get_bool(igmp_enable_dnode, "."))))
return true;
return false;
}
static int pim_cmd_igmp_start(struct interface *ifp)
{
struct pim_interface *pim_ifp;
uint8_t need_startup = 0;
pim_ifp = ifp->info;
if (!pim_ifp) {
pim_ifp = pim_if_new(ifp, true, false, false, false);
need_startup = 1;
} else {
if (!PIM_IF_TEST_IGMP(pim_ifp->options)) {
PIM_IF_DO_IGMP(pim_ifp->options);
need_startup = 1;
}
}
pim_if_create_pimreg(pim_ifp->pim);
/* 'ip igmp' executed multiple times, with need_startup
* avoid multiple if add all and membership refresh
*/
if (need_startup) {
pim_if_addr_add_all(ifp);
pim_if_membership_refresh(ifp);
}
return NB_OK;
}
/*
* CLI reconfiguration affects the interface level (struct pim_interface).
* This function propagates the reconfiguration to every active socket
* for that interface.
*/
static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
zassert(igmp);
/* other querier present? */
if (igmp->t_other_querier_timer)
return;
/* this is the querier */
zassert(igmp->interface);
zassert(igmp->interface->info);
ifp = igmp->interface;
pim_ifp = ifp->info;
if (PIM_DEBUG_IGMP_TRACE) {
char ifaddr_str[INET_ADDRSTRLEN];
pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
sizeof(ifaddr_str));
zlog_debug("%s: Querier %s on %s reconfig query_interval=%d",
__func__, ifaddr_str, ifp->name,
pim_ifp->igmp_default_query_interval);
}
/*
* igmp_startup_mode_on() will reset QQI:
* igmp->querier_query_interval = pim_ifp->igmp_default_query_interval;
*/
igmp_startup_mode_on(igmp);
}
static void igmp_sock_query_reschedule(struct igmp_sock *igmp)
{
if (igmp->mtrace_only)
return;
if (igmp->t_igmp_query_timer) {
/* other querier present */
zassert(igmp->t_igmp_query_timer);
zassert(!igmp->t_other_querier_timer);
pim_igmp_general_query_off(igmp);
pim_igmp_general_query_on(igmp);
zassert(igmp->t_igmp_query_timer);
zassert(!igmp->t_other_querier_timer);
} else {
/* this is the querier */
zassert(!igmp->t_igmp_query_timer);
zassert(igmp->t_other_querier_timer);
pim_igmp_other_querier_timer_off(igmp);
pim_igmp_other_querier_timer_on(igmp);
zassert(!igmp->t_igmp_query_timer);
zassert(igmp->t_other_querier_timer);
}
}
static void change_query_interval(struct pim_interface *pim_ifp,
int query_interval)
{
struct listnode *sock_node;
struct igmp_sock *igmp;
pim_ifp->igmp_default_query_interval = query_interval;
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
igmp_sock_query_interval_reconfig(igmp);
igmp_sock_query_reschedule(igmp);
}
}
static void change_query_max_response_time(struct pim_interface *pim_ifp,
int query_max_response_time_dsec)
{
struct listnode *sock_node;
struct igmp_sock *igmp;
pim_ifp->igmp_query_max_response_time_dsec =
query_max_response_time_dsec;
/*
* Below we modify socket/group/source timers in order to quickly
* reflect the change. Otherwise, those timers would args->eventually
* catch up.
*/
/* scan all sockets */
for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) {
struct listnode *grp_node;
struct igmp_group *grp;
/* reschedule socket general query */
igmp_sock_query_reschedule(igmp);
/* scan socket groups */
for (ALL_LIST_ELEMENTS_RO(igmp->igmp_group_list, grp_node,
grp)) {
struct listnode *src_node;
struct igmp_source *src;
/* reset group timers for groups in EXCLUDE mode */
if (grp->group_filtermode_isexcl)
igmp_group_reset_gmi(grp);
/* scan group sources */
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
src_node, src)) {
/* reset source timers for sources with running
* timers
*/
if (src->t_source_timer)
igmp_source_reset_gmi(igmp, grp, src);
}
}
}
}
int routing_control_plane_protocols_name_validate(
struct nb_cb_create_args *args)
{
const char *name;
name = yang_dnode_get_string(args->dnode, "./name");
if (!strmatch(name, "pim")) {
snprintf(args->errmsg, args->errmsg_len,
"pim supports only one instance with name pimd");
return NB_ERR_VALIDATION;
}
return NB_OK;
}
/*
* XPath: /frr-pim:pim/packets
*/
int pim_packets_modify(struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
router->packet_process = yang_dnode_get_uint8(args->dnode,
NULL);
break;
}
return NB_OK;
}
/*
* XPath: /frr-pim:pim/join-prune-interval
*/
int pim_join_prune_interval_modify(struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
router->t_periodic = yang_dnode_get_uint16(args->dnode, NULL);
break;
}
return NB_OK;
}
/*
* XPath: /frr-pim:pim/register-suppress-time
*/
int pim_register_suppress_time_modify(struct nb_cb_modify_args *args)
{
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->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL);
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp
*/
int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify(
struct nb_cb_modify_args *args)
{
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->ecmp_enable = yang_dnode_get_bool(args->dnode, NULL);
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp-rebalance
*/
int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify(
struct nb_cb_modify_args *args)
{
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->ecmp_rebalance_enable =
yang_dnode_get_bool(args->dnode, NULL);
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/keep-alive-timer
*/
int routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify(
struct nb_cb_modify_args *args)
{
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->keep_alive_time = yang_dnode_get_uint16(args->dnode, NULL);
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/rp-keep-alive-timer
*/
int routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify(
struct nb_cb_modify_args *args)
{
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->rp_keep_alive_time = yang_dnode_get_uint16(args->dnode,
NULL);
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_create(
struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
/* TODO: implement me. */
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/send-v6-secondary
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_modify(
struct nb_cb_modify_args *args)
{
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->send_v6_secondary = yang_dnode_get_bool(args->dnode, NULL);
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_send_v6_secondary_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover
*/
void routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_apply_finish(
struct nb_cb_apply_finish_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
int spt_switch_action;
const char *prefix_list = NULL;
vrf = nb_running_get_entry(args->dnode, NULL, true);
pim = vrf->info;
spt_switch_action = yang_dnode_get_enum(args->dnode, "./spt-action");
switch (spt_switch_action) {
case PIM_SPT_INFINITY:
if (yang_dnode_exists(args->dnode,
"./spt-infinity-prefix-list"))
prefix_list = yang_dnode_get_string(
args->dnode, "./spt-infinity-prefix-list");
pim_cmd_spt_switchover(pim, PIM_SPT_INFINITY,
prefix_list);
break;
case PIM_SPT_IMMEDIATE:
pim_cmd_spt_switchover(pim, PIM_SPT_IMMEDIATE, NULL);
}
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-action
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_action_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/spt-switchover/spt-infinity-prefix-list
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_spt_switchover_spt_infinity_prefix_list_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-prefix-list
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_modify(
struct nb_cb_modify_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
const char *plist_name;
int result;
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_name = yang_dnode_get_string(args->dnode, NULL);
result = pim_ssm_cmd_worker(pim, plist_name, args->errmsg,
args->errmsg_len);
if (result)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_prefix_list_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
int result;
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;
result = pim_ssm_cmd_worker(pim, NULL, args->errmsg,
args->errmsg_len);
if (result)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ssm-pingd-source-ip
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_create(
struct nb_cb_create_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
int result;
struct ipaddr source_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_ip(&source_addr, args->dnode, NULL);
result = pim_ssmpingd_start(pim, source_addr.ip._v4_addr);
if (result) {
char source_str[INET_ADDRSTRLEN];
ipaddr2str(&source_addr, source_str,
sizeof(source_str));
snprintf(args->errmsg, args->errmsg_len,
"%% Failure starting ssmpingd for source %s: %d",
source_str, result);
return NB_ERR_INCONSISTENCY;
}
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ssm_pingd_source_ip_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
int result;
struct ipaddr source_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_ip(&source_addr, args->dnode, NULL);
result = pim_ssmpingd_stop(pim, source_addr.ip._v4_addr);
if (result) {
char source_str[INET_ADDRSTRLEN];
ipaddr2str(&source_addr, source_str,
sizeof(source_str));
snprintf(args->errmsg, args->errmsg_len,
"%% Failure stopping ssmpingd for source %s: %d",
source_str, result);
return NB_ERR_INCONSISTENCY;
}
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_create(
struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
const char *mesh_group_name;
int result;
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;
mesh_group_name = yang_dnode_get_string(args->dnode, "mesh-group-name");
result = ip_no_msdp_mesh_group_cmd_worker(pim, mesh_group_name,
args->errmsg,
args->errmsg_len);
if (result != PIM_MSDP_ERR_NONE)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/mesh-group-name
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_modify(
struct nb_cb_modify_args *args)
{
const char *mesh_group_name;
const char *mesh_group_name_old;
char xpath[XPATH_MAXLEN];
switch (args->event) {
case NB_EV_VALIDATE:
mesh_group_name = yang_dnode_get_string(args->dnode, ".");
yang_dnode_get_path(args->dnode, xpath, sizeof(xpath));
if (yang_dnode_exists(running_config->dnode, xpath) == false)
break;
mesh_group_name_old = yang_dnode_get_string(
running_config->dnode,
xpath);
if (strcmp(mesh_group_name, mesh_group_name_old)) {
/* currently only one mesh-group can exist at a time */
snprintf(args->errmsg, args->errmsg_len,
"Only one mesh-group allowed currently");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_mesh_group_name_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/member-ip
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_create(
struct nb_cb_create_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
const char *mesh_group_name;
struct ipaddr mbr_ip;
enum pim_msdp_err result;
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;
mesh_group_name = yang_dnode_get_string(args->dnode,
"../mesh-group-name");
yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
result = ip_msdp_mesh_group_member_cmd_worker(
pim, mesh_group_name, mbr_ip.ip._v4_addr,
args->errmsg, args->errmsg_len);
if (result != PIM_MSDP_ERR_NONE)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_member_ip_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
const char *mesh_group_name;
struct ipaddr mbr_ip;
enum pim_msdp_err result;
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;
mesh_group_name = yang_dnode_get_string(args->dnode,
"../mesh-group-name");
yang_dnode_get_ip(&mbr_ip, args->dnode, NULL);
result = ip_no_msdp_mesh_group_member_cmd_worker(
pim, mesh_group_name, mbr_ip.ip._v4_addr,
args->errmsg, args->errmsg_len);
if (result != PIM_MSDP_ERR_NONE)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-group/source-ip
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_modify(
struct nb_cb_modify_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
const char *mesh_group_name;
struct ipaddr src_ip;
enum pim_msdp_err result;
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;
mesh_group_name = yang_dnode_get_string(args->dnode,
"../mesh-group-name");
yang_dnode_get_ip(&src_ip, args->dnode, NULL);
result = ip_msdp_mesh_group_source_cmd_worker(
pim, mesh_group_name, src_ip.ip._v4_addr,
args->errmsg, args->errmsg_len);
if (result != PIM_MSDP_ERR_NONE)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_mesh_group_source_ip_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
const char *mesh_group_name;
enum pim_msdp_err result;
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;
mesh_group_name = yang_dnode_get_string(args->dnode,
"../mesh-group-name");
result = ip_no_msdp_mesh_group_source_cmd_worker(
pim, mesh_group_name, args->errmsg,
args->errmsg_len);
if (result != PIM_MSDP_ERR_NONE)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create(
struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy(
struct nb_cb_destroy_args *args)
{
int result;
struct pim_instance *pim;
struct ipaddr peer_ip;
struct vrf *vrf;
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_ip(&peer_ip, args->dnode, "./peer-ip");
result = ip_no_msdp_peer_cmd_worker(pim, peer_ip.ip._v4_addr,
args->errmsg,
args->errmsg_len);
if (result)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/source-ip
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify(
struct nb_cb_modify_args *args)
{
int result;
struct vrf *vrf;
struct pim_instance *pim;
struct ipaddr peer_ip;
struct ipaddr source_ip;
const struct lyd_node *mesh_group_name_dnode;
const char *mesh_group_name;
switch (args->event) {
case NB_EV_VALIDATE:
mesh_group_name_dnode =
yang_dnode_get(args->dnode,
"../../msdp-mesh-group/mesh-group-name");
if (mesh_group_name_dnode) {
mesh_group_name =
yang_dnode_get_string(mesh_group_name_dnode,
".");
if (strcmp(mesh_group_name, "default")) {
/* currently only one mesh-group can exist at a
* time
*/
snprintf(args->errmsg, args->errmsg_len,
"%% Only one mesh-group allowed currently");
return NB_ERR_VALIDATION;
}
}
break;
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_ip(&peer_ip, args->dnode, "../peer-ip");
yang_dnode_get_ip(&source_ip, args->dnode, NULL);
result = ip_msdp_peer_cmd_worker(pim, peer_ip.ip._v4_addr,
source_ip.ip._v4_addr,
args->errmsg,
args->errmsg_len);
if (result)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create(
struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy(
struct nb_cb_destroy_args *args)
{
struct in_addr addr;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
addr.s_addr = 0;
pim_vxlan_mlag_update(true/*mlag_enable*/,
false/*peer_state*/, MLAG_ROLE_NONE,
NULL/*peerlink*/, &addr);
}
return NB_OK;
}
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag
*/
void routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_apply_finish(
struct nb_cb_apply_finish_args *args)
{
const char *ifname;
uint32_t role;
bool peer_state;
struct interface *ifp;
struct ipaddr reg_addr;
ifname = yang_dnode_get_string(args->dnode, "./peerlink-rif");
ifp = if_lookup_by_name(ifname, VRF_DEFAULT);
if (!ifp) {
snprintf(args->errmsg, args->errmsg_len,
"No such interface name %s", ifname);
return;
}
role = yang_dnode_get_enum(args->dnode, "./my-role");
peer_state = yang_dnode_get_bool(args->dnode, "./peer-state");
yang_dnode_get_ip(&reg_addr, args->dnode, "./reg-address");
pim_vxlan_mlag_update(true, peer_state, role, ifp,
&reg_addr.ip._v4_addr);
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peerlink-rif
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peerlink_rif_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/reg-address
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_reg_address_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/my-role
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_my_role_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag/peer-state
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_peer_state_modify(
struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/register-accept-list
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_modify(
struct nb_cb_modify_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
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);
XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
pim->register_plist = XSTRDUP(MTYPE_PIM_PLIST_NAME, plist);
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy(
struct nb_cb_destroy_args *args)
{
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;
XFREE(MTYPE_PIM_PLIST_NAME, pim->register_plist);
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim
*/
int lib_interface_pim_create(struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int lib_interface_pim_destroy(struct nb_cb_destroy_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
if (!pim_ifp)
return NB_OK;
if (!pim_cmd_interface_delete(ifp)) {
snprintf(args->errmsg, args->errmsg_len,
"Unable to delete interface information %s",
ifp->name);
return NB_ERR_INCONSISTENCY;
}
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/pim-enable
*/
int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
int mcast_if_count;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
mcast_if_count =
yang_get_list_elements_count(if_dnode);
/* Limiting mcast interfaces to number of VIFs */
if (mcast_if_count == MAXVIFS) {
snprintf(args->errmsg, args->errmsg_len,
"Max multicast interfaces(%d) reached.",
MAXVIFS);
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
if (yang_dnode_get_bool(args->dnode, NULL)) {
if (!pim_cmd_interface_add(ifp)) {
snprintf(args->errmsg, args->errmsg_len,
"Could not enable PIM SM on interface %s",
ifp->name);
return NB_ERR_INCONSISTENCY;
}
} else {
pim_ifp = ifp->info;
if (!pim_ifp)
return NB_ERR_INCONSISTENCY;
if (!pim_cmd_interface_delete(ifp)) {
snprintf(args->errmsg, args->errmsg_len,
"Unable to delete interface information");
return NB_ERR_INCONSISTENCY;
}
}
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/hello-interval
*/
int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
pim_ifp->pim_hello_period =
yang_dnode_get_uint8(args->dnode, NULL);
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/hello-holdtime
*/
int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
pim_ifp->pim_default_holdtime =
yang_dnode_get_uint8(args->dnode, NULL);
break;
}
return NB_OK;
}
int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
pim_ifp->pim_default_holdtime = -1;
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/bfd
*/
int lib_interface_pim_bfd_create(struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
snprintf(args->errmsg, args->errmsg_len,
"Pim not enabled on this interface");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode->parent, NULL, true);
pim_ifp = ifp->info;
if (pim_ifp->bfd_info) {
pim_bfd_reg_dereg_all_nbr(ifp,
ZEBRA_BFD_DEST_DEREGISTER);
bfd_info_free(&(pim_ifp->bfd_info));
}
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/bfd
*/
void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
uint32_t min_rx;
uint32_t min_tx;
uint8_t detect_mult;
ifp = nb_running_get_entry(args->dnode->parent, NULL, true);
pim_ifp = ifp->info;
if (!pim_ifp) {
zlog_debug("Pim not enabled on this interface");
return;
}
min_rx = yang_dnode_get_uint16(args->dnode, "./min-rx-interval");
min_tx = yang_dnode_get_uint16(args->dnode, "./min-tx-interval");
detect_mult = yang_dnode_get_uint8(args->dnode, "./detect_mult");
if ((min_rx == BFD_DEF_MIN_RX) && (min_tx == BFD_DEF_MIN_TX)
&& (detect_mult == BFD_DEF_DETECT_MULT))
pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 1);
else
pim_bfd_if_param_set(ifp, min_rx, min_tx, detect_mult, 0);
nb_running_set_entry(args->dnode, pim_ifp->bfd_info);
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/min-rx-interval
*/
int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/min-tx-interval
*/
int lib_interface_pim_bfd_min_tx_interval_modify(struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/detect_mult
*/
int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/bsm
*/
int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
pim_ifp->bsm_enable = yang_dnode_get_bool(args->dnode, NULL);
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/unicast-bsm
*/
int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
pim_ifp->ucast_bsm_accept =
yang_dnode_get_bool(args->dnode, NULL);
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/active-active
*/
int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
if (yang_dnode_get_bool(args->dnode, NULL)) {
if (PIM_DEBUG_MLAG)
zlog_debug(
"Configuring PIM active-active on Interface: %s",
ifp->name);
pim_if_configure_mlag_dualactive(pim_ifp);
} else {
if (PIM_DEBUG_MLAG)
zlog_debug(
"UnConfiguring PIM active-active on Interface: %s",
ifp->name);
pim_if_unconfigure_mlag_dualactive(pim_ifp);
}
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/dr-priority
*/
int lib_interface_pim_dr_priority_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
uint32_t old_dr_prio;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
snprintf(args->errmsg, args->errmsg_len,
"Pim not enabled on this interface");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
old_dr_prio = pim_ifp->pim_dr_priority;
pim_ifp->pim_dr_priority = yang_dnode_get_uint32(args->dnode,
NULL);
if (old_dr_prio != pim_ifp->pim_dr_priority) {
pim_if_dr_election(ifp);
pim_hello_restart_now(ifp);
}
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/address-family
*/
int lib_interface_pim_address_family_create(struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/use-source
*/
int lib_interface_pim_address_family_use_source_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct ipaddr source_addr;
int result;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
snprintf(args->errmsg, args->errmsg_len,
"Pim not enabled on this interface");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
yang_dnode_get_ip(&source_addr, args->dnode, NULL);
result = interface_pim_use_src_cmd_worker(
ifp, source_addr.ip._v4_addr,
args->errmsg, args->errmsg_len);
if (result != PIM_SUCCESS)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
int lib_interface_pim_address_family_use_source_destroy(
struct nb_cb_destroy_args *args)
{
struct interface *ifp;
struct in_addr source_addr = {INADDR_ANY};
int result;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
snprintf(args->errmsg, args->errmsg_len,
"Pim not enabled on this interface");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
result = interface_pim_use_src_cmd_worker(ifp, source_addr,
args->errmsg,
args->errmsg_len);
if (result != PIM_SUCCESS)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/multicast-boundary-oil
*/
int lib_interface_pim_address_family_multicast_boundary_oil_modify(
struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
const char *plist;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
snprintf(args->errmsg, args->errmsg_len,
"Pim not enabled on this interface");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
plist = yang_dnode_get_string(args->dnode, NULL);
if (pim_ifp->boundary_oil_plist)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
pim_ifp->boundary_oil_plist =
XSTRDUP(MTYPE_PIM_INTERFACE, plist);
break;
}
return NB_OK;
}
int lib_interface_pim_address_family_multicast_boundary_oil_destroy(
struct nb_cb_destroy_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
snprintf(args->errmsg, args->errmsg_len,
"%% Enable PIM and/or IGMP on this interface first");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_ABORT:
case NB_EV_PREPARE:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
if (pim_ifp->boundary_oil_plist)
XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute
*/
int lib_interface_pim_address_family_mroute_create(
struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int lib_interface_pim_address_family_mroute_destroy(
struct nb_cb_destroy_args *args)
{
struct pim_instance *pim;
struct pim_interface *pim_iifp;
struct interface *iif;
struct interface *oif;
const char *oifname;
struct ipaddr source_addr;
struct ipaddr group_addr;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
snprintf(args->errmsg, args->errmsg_len,
"%% Enable PIM and/or IGMP on this interface first");
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
iif = nb_running_get_entry(args->dnode, NULL, true);
pim_iifp = iif->info;
pim = pim_iifp->pim;
oifname = yang_dnode_get_string(args->dnode, "./oif");
oif = if_lookup_by_name(oifname, pim->vrf_id);
if (!oif) {
snprintf(args->errmsg, args->errmsg_len,
"No such interface name %s",
oifname);
return NB_ERR_INCONSISTENCY;
}
yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
if (pim_static_del(pim, iif, oif, group_addr.ip._v4_addr,
source_addr.ip._v4_addr)) {
snprintf(args->errmsg, args->errmsg_len,
"Failed to remove static mroute");
return NB_ERR_INCONSISTENCY;
}
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/mroute/oif
*/
int lib_interface_pim_address_family_mroute_oif_modify(
struct nb_cb_modify_args *args)
{
struct pim_instance *pim;
struct pim_interface *pim_iifp;
struct interface *iif;
struct interface *oif;
const char *oifname;
struct ipaddr source_addr;
struct ipaddr group_addr;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
snprintf(args->errmsg, args->errmsg_len,
"%% Enable PIM and/or IGMP on this interface first");
return NB_ERR_VALIDATION;
}
#ifdef PIM_ENFORCE_LOOPFREE_MFC
iif = nb_running_get_entry(args->dnode, NULL, false);
if (!iif) {
return NB_OK;
}
pim_iifp = iif->info;
pim = pim_iifp->pim;
oifname = yang_dnode_get_string(args->dnode, NULL);
oif = if_lookup_by_name(oifname, pim->vrf_id);
if (oif && (iif->ifindex == oif->ifindex)) {
strlcpy(args->errmsg,
"% IIF same as OIF and loopfree enforcement is enabled; rejecting",
args->errmsg_len);
return NB_ERR_VALIDATION;
}
#endif
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
iif = nb_running_get_entry(args->dnode, NULL, true);
pim_iifp = iif->info;
pim = pim_iifp->pim;
oifname = yang_dnode_get_string(args->dnode, NULL);
oif = if_lookup_by_name(oifname, pim->vrf_id);
if (!oif) {
snprintf(args->errmsg, args->errmsg_len,
"No such interface name %s",
oifname);
return NB_ERR_INCONSISTENCY;
}
yang_dnode_get_ip(&source_addr, args->dnode, "../source-addr");
yang_dnode_get_ip(&group_addr, args->dnode, "../group-addr");
if (pim_static_add(pim, iif, oif, group_addr.ip._v4_addr,
source_addr.ip._v4_addr)) {
snprintf(args->errmsg, args->errmsg_len,
"Failed to add static mroute");
return NB_ERR_INCONSISTENCY;
}
break;
}
return NB_OK;
}
int lib_interface_pim_address_family_mroute_oif_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_create(
struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct prefix group;
struct ipaddr rp_addr;
const char *plist;
int result = 0;
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_ip(&rp_addr, args->dnode, "./rp-address");
if (yang_dnode_get(args->dnode, "./group-list")) {
yang_dnode_get_ipv4p(&group, args->dnode,
"./group-list");
apply_mask_ipv4((struct prefix_ipv4 *)&group);
result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr,
group, NULL, args->errmsg,
args->errmsg_len);
}
else if (yang_dnode_get(args->dnode, "./prefix-list")) {
plist = yang_dnode_get_string(args->dnode,
"./prefix-list");
if (!str2prefix("224.0.0.0/4", &group)) {
flog_err(
EC_LIB_DEVELOPMENT,
"Unable to convert 224.0.0.0/4 to prefix");
return NB_ERR_INCONSISTENCY;
}
result = pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr,
group, plist,
args->errmsg,
args->errmsg_len);
}
if (result)
return NB_ERR_INCONSISTENCY;
break;
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list/group-list
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_create(
struct nb_cb_create_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct prefix group;
struct ipaddr 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_ip(&rp_addr, args->dnode, "../rp-address");
yang_dnode_get_ipv4p(&group, args->dnode, NULL);
apply_mask_ipv4((struct prefix_ipv4 *)&group);
return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group,
NULL, args->errmsg, args->errmsg_len);
}
return NB_OK;
}
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_group_list_destroy(
struct nb_cb_destroy_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct prefix group;
struct ipaddr 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_ip(&rp_addr, args->dnode, "../rp-address");
yang_dnode_get_ipv4p(&group, args->dnode, NULL);
apply_mask_ipv4((struct prefix_ipv4 *)&group);
return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group,
NULL, args->errmsg,
args->errmsg_len);
}
return NB_OK;
}
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/static-rp/rp-list/prefix-list
*/
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_modify(
struct nb_cb_modify_args *args)
{
struct vrf *vrf;
struct pim_instance *pim;
struct prefix group;
struct ipaddr 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_ip(&rp_addr, args->dnode, "../rp-address");
if (!str2prefix("224.0.0.0/4", &group)) {
flog_err(EC_LIB_DEVELOPMENT,
"Unable to convert 224.0.0.0/4 to prefix");
return NB_ERR_INCONSISTENCY;
}
return pim_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group,
plist, args->errmsg, args->errmsg_len);
}
return NB_OK;
}
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)
{
struct vrf *vrf;
struct pim_instance *pim;
struct prefix group;
struct ipaddr 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_ip(&rp_addr, args->dnode, "../rp-address");
plist = yang_dnode_get_string(args->dnode, NULL);
if (!str2prefix("224.0.0.0/4", &group)) {
flog_err(EC_LIB_DEVELOPMENT,
"Unable to convert 224.0.0.0/4 to prefix");
return NB_ERR_INCONSISTENCY;
}
return pim_no_rp_cmd_worker(pim, rp_addr.ip._v4_addr, group,
plist, args->errmsg,
args->errmsg_len);
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp
*/
int lib_interface_igmp_create(struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
if (!pim_ifp)
return NB_OK;
PIM_IF_DONT_IGMP(pim_ifp->options);
pim_if_membership_clear(ifp);
pim_if_addr_del_all_igmp(ifp);
if (!PIM_IF_TEST_PIM(pim_ifp->options))
pim_if_delete(ifp);
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp/igmp-enable
*/
int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
bool igmp_enable;
struct pim_interface *pim_ifp;
int mcast_if_count;
const char *ifp_name;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
mcast_if_count =
yang_get_list_elements_count(if_dnode);
/* Limiting mcast interfaces to number of VIFs */
if (mcast_if_count == MAXVIFS) {
ifp_name = yang_dnode_get_string(if_dnode, "name");
snprintf(args->errmsg, args->errmsg_len,
"Max multicast interfaces(%d) Reached. Could not enable IGMP on interface %s",
MAXVIFS, ifp_name);
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
igmp_enable = yang_dnode_get_bool(args->dnode, NULL);
if (igmp_enable)
return pim_cmd_igmp_start(ifp);
else {
pim_ifp = ifp->info;
if (!pim_ifp)
return NB_ERR_INCONSISTENCY;
PIM_IF_DONT_IGMP(pim_ifp->options);
pim_if_membership_clear(ifp);
pim_if_addr_del_all_igmp(ifp);
if (!PIM_IF_TEST_PIM(pim_ifp->options))
pim_if_delete(ifp);
}
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp/version
*/
int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
int igmp_version, old_version = 0;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
if (!pim_ifp)
return NB_ERR_INCONSISTENCY;
igmp_version = yang_dnode_get_uint8(args->dnode, NULL);
old_version = pim_ifp->igmp_version;
pim_ifp->igmp_version = igmp_version;
/* Current and new version is different refresh existing
* membership. Going from 3 -> 2 or 2 -> 3.
*/
if (old_version != igmp_version)
pim_if_membership_refresh(ifp);
break;
}
return NB_OK;
}
int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp/query-interval
*/
int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
int query_interval;
int query_interval_dsec;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
query_interval = yang_dnode_get_uint16(args->dnode, NULL);
query_interval_dsec = 10 * query_interval;
if (query_interval_dsec <=
pim_ifp->igmp_query_max_response_time_dsec) {
snprintf(args->errmsg, args->errmsg_len,
"Can't set general query interval %d dsec <= query max response time %d dsec.",
query_interval_dsec,
pim_ifp->igmp_query_max_response_time_dsec);
return NB_ERR_INCONSISTENCY;
}
change_query_interval(pim_ifp, query_interval);
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp/query-max-response-time
*/
int lib_interface_igmp_query_max_response_time_modify(
struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
int query_max_response_time_dsec;
int default_query_interval_dsec;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
query_max_response_time_dsec =
yang_dnode_get_uint8(args->dnode, NULL);
default_query_interval_dsec =
10 * pim_ifp->igmp_default_query_interval;
if (query_max_response_time_dsec
>= default_query_interval_dsec) {
snprintf(args->errmsg, args->errmsg_len,
"Can't set query max response time %d sec >= general query interval %d sec",
query_max_response_time_dsec,
pim_ifp->igmp_default_query_interval);
return NB_ERR_INCONSISTENCY;
}
change_query_max_response_time(pim_ifp,
query_max_response_time_dsec);
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp/last-member-query-interval
*/
int lib_interface_igmp_last_member_query_interval_modify(
struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
int last_member_query_interval;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
last_member_query_interval = yang_dnode_get_uint8(args->dnode,
NULL);
pim_ifp->igmp_specific_query_max_response_time_dsec =
last_member_query_interval;
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp/robustness-variable
*/
int lib_interface_igmp_robustness_variable_modify(
struct nb_cb_modify_args *args)
{
struct interface *ifp;
struct pim_interface *pim_ifp;
int last_member_query_count;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
pim_ifp = ifp->info;
last_member_query_count = yang_dnode_get_uint8(args->dnode,
NULL);
pim_ifp->igmp_last_member_query_count = last_member_query_count;
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp/address-family
*/
int lib_interface_igmp_address_family_create(struct nb_cb_create_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
case NB_EV_APPLY:
break;
}
return NB_OK;
}
/*
* XPath: /frr-interface:lib/interface/frr-igmp:igmp/address-family/static-group
*/
int lib_interface_igmp_address_family_static_group_create(
struct nb_cb_create_args *args)
{
struct interface *ifp;
struct ipaddr source_addr;
struct ipaddr group_addr;
int result;
const char *ifp_name;
const struct lyd_node *if_dnode;
switch (args->event) {
case NB_EV_VALIDATE:
if_dnode = yang_dnode_get_parent(args->dnode, "interface");
if (!is_pim_interface(if_dnode)) {
ifp_name = yang_dnode_get_string(if_dnode, "name");
snprintf(args->errmsg, args->errmsg_len,
"multicast not enabled on interface %s",
ifp_name);
return NB_ERR_VALIDATION;
}
break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
result = pim_if_igmp_join_add(ifp, group_addr.ip._v4_addr,
source_addr.ip._v4_addr);
if (result) {
snprintf(args->errmsg, args->errmsg_len,
"Failure joining IGMP group");
return NB_ERR_INCONSISTENCY;
}
}
return NB_OK;
}
int lib_interface_igmp_address_family_static_group_destroy(
struct nb_cb_destroy_args *args)
{
struct interface *ifp;
struct ipaddr source_addr;
struct ipaddr group_addr;
int result;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
yang_dnode_get_ip(&source_addr, args->dnode, "./source-addr");
yang_dnode_get_ip(&group_addr, args->dnode, "./group-addr");
result = pim_if_igmp_join_del(ifp, group_addr.ip._v4_addr,
source_addr.ip._v4_addr);
if (result) {
char src_str[INET_ADDRSTRLEN];
char grp_str[INET_ADDRSTRLEN];
ipaddr2str(&source_addr, src_str, sizeof(src_str));
ipaddr2str(&group_addr, grp_str, sizeof(grp_str));
snprintf(args->errmsg, args->errmsg_len,
"%% Failure leaving IGMP group %s %s on interface %s: %d",
src_str, grp_str, ifp->name, result);
return NB_ERR_INCONSISTENCY;
}
break;
}
return NB_OK;
}