Implement MSDP MD5 authentication connection support.
Implementation details:
- Move the MSDP socket creation code to a generic function so it can be
parametrized to be used with/without authentication.
- The MSDP peer connection will not change when the configuration is
set, instead it will only be applied next connection or when
`clear ip msdp peer A.B.C.D` is called.
Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
return clear_ip_mroute_count_command(vty, name);
}
+DEFPY(clear_ip_msdp_peer, clear_ip_msdp_peer_cmd,
+ "clear ip msdp peer A.B.C.D$peer [vrf WORD$vrfname]",
+ CLEAR_STR
+ IP_STR
+ MSDP_STR
+ "Restart MSDP peer\n"
+ "MSDP peer address\n"
+ VRF_CMD_HELP_STR)
+{
+ const struct pim_instance *pim;
+ const struct listnode *node;
+ const struct vrf *vrf;
+ struct pim_msdp_peer *mp;
+
+ if (vrfname) {
+ vrf = vrf_lookup_by_name(vrfname);
+ if (vrf == NULL)
+ return CMD_WARNING;
+ } else
+ vrf = vrf_lookup_by_id(VRF_DEFAULT);
+
+ pim = vrf->info;
+ for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) {
+ if (mp->peer.s_addr != peer.s_addr)
+ continue;
+
+ pim_msdp_peer_restart(mp);
+ break;
+ }
+
+ return CMD_SUCCESS;
+}
+
DEFPY (show_ip_mroute_count,
show_ip_mroute_count_cmd,
"show ip mroute [vrf NAME] count [json$json]",
return ret;
}
+DEFPY(msdp_peer_md5, msdp_peer_md5_cmd,
+ "msdp peer A.B.C.D$peer password WORD$psk",
+ CFG_MSDP_STR
+ "Configure MSDP peer\n"
+ "MSDP Peer address\n"
+ "Use MD5 authentication\n"
+ "MD5 pre shared key\n")
+{
+ const struct lyd_node *peer_node;
+ char xpath[XPATH_MAXLEN + 24];
+
+ snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']",
+ VTY_CURR_XPATH, peer_str);
+ peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath);
+ if (peer_node == NULL) {
+ vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str);
+ return CMD_SUCCESS;
+ }
+
+ nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, "MD5");
+ nb_cli_enqueue_change(vty, "./authentication-key", NB_OP_MODIFY, psk);
+
+ return nb_cli_apply_changes(vty, "%s", xpath);
+}
+
+DEFPY(no_msdp_peer_md5, no_msdp_peer_md5_cmd,
+ "no msdp peer A.B.C.D$peer password [WORD]",
+ NO_STR
+ CFG_MSDP_STR
+ "Configure MSDP peer\n"
+ "MSDP Peer address\n"
+ "Use MD5 authentication\n"
+ "MD5 pre shared key\n")
+{
+ const struct lyd_node *peer_node;
+ char xpath[XPATH_MAXLEN + 24];
+
+ snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']",
+ VTY_CURR_XPATH, peer_str);
+ peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath);
+ if (peer_node == NULL) {
+ vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str);
+ return CMD_SUCCESS;
+ }
+
+ nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY,
+ "None");
+
+ return nb_cli_apply_changes(vty, "%s", xpath);
+}
+
DEFPY(pim_msdp_timers, pim_msdp_timers_cmd,
"msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]",
CFG_MSDP_STR
install_element(PIM_NODE, &pim_msdp_peer_cmd);
install_element(PIM_NODE, &no_pim_msdp_peer_cmd);
+ install_element(PIM_NODE, &msdp_peer_md5_cmd);
+ install_element(PIM_NODE, &no_msdp_peer_md5_cmd);
install_element(PIM_NODE, &pim_msdp_timers_cmd);
install_element(PIM_NODE, &no_pim_msdp_timers_cmd);
install_element(PIM_NODE, &msdp_peer_sa_filter_cmd);
install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd);
install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd);
+ install_element(ENABLE_NODE, &clear_ip_msdp_peer_cmd);
install_element(ENABLE_NODE, &clear_ip_interfaces_cmd);
install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd);
install_element(ENABLE_NODE, &clear_ip_mroute_cmd);
DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info");
DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer");
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name");
+DEFINE_MTYPE(PIMD, PIM_MSDP_AUTH_KEY, "PIM MSDP authentication key");
DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache");
DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group");
DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr");
DECLARE_MTYPE(PIM_MSDP_SA);
DECLARE_MTYPE(PIM_MSDP_MG);
DECLARE_MTYPE(PIM_MSDP_MG_MBR);
+DECLARE_MTYPE(PIM_MSDP_AUTH_KEY);
DECLARE_MTYPE(PIM_SEC_ADDR);
DECLARE_MTYPE(PIM_JP_AGG_GROUP);
DECLARE_MTYPE(PIM_JP_AGG_SOURCE);
* first listening peer is configured; but don't bother tearing it down
* when
* all the peers go down */
- pim_msdp_sock_listen(mp->pim);
+ if (mp->auth_type == MSDP_AUTH_NONE)
+ pim_msdp_sock_listen(mp->pim);
+ else
+ pim_msdp_sock_auth_listen(mp);
}
/* 11.2.A4 and 11.2.A5: transition active or passive peer to
mp->state = PIM_MSDP_INACTIVE;
mp->fd = -1;
+ mp->auth_listen_sock = -1;
strlcpy(mp->last_reset, "-", sizeof(mp->last_reset));
/* higher IP address is listener */
if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) {
stream_fifo_free(mp->obuf);
}
+ /* Free authentication data. */
+ event_cancel(&mp->auth_listen_ev);
+ XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key);
+ if (mp->auth_listen_sock != -1)
+ close(mp->auth_listen_sock);
+
XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name);
mp->pim = NULL;
*mp = NULL;
}
-void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
- const struct in_addr *addr)
+void pim_msdp_peer_restart(struct pim_msdp_peer *mp)
{
- pim_msdp_peer_stop_tcp_conn(mp, true);
+ /* Stop auth listening socket if any. */
+ event_cancel(&mp->auth_listen_ev);
+ if (mp->auth_listen_sock != -1) {
+ close(mp->auth_listen_sock);
+ mp->auth_listen_sock = -1;
+ }
- mp->local = *addr;
+ /* Stop previously running connection. */
+ pim_msdp_peer_stop_tcp_conn(mp, true);
+ /* Start connection again. */
if (PIM_MSDP_PEER_IS_LISTENER(mp))
pim_msdp_peer_listen(mp);
else
pim_msdp_peer_connect(mp);
}
+void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
+ const struct in_addr *addr)
+{
+ mp->local = *addr;
+ pim_msdp_peer_restart(mp);
+}
+
/* peer hash and peer list helpers */
static unsigned int pim_msdp_peer_hash_key_make(const void *p)
{
vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer,
&mp->local);
+ if (mp->auth_type == MSDP_AUTH_MD5)
+ vty_out(vty, " msdp peer %pI4 password %s\n", &mp->peer,
+ mp->auth_key);
+
if (mp->acl_in)
vty_out(vty, " msdp peer %pI4 sa-filter %s in\n",
&mp->peer, mp->acl_in);
PIM_MSDP_PEERF_IN_GROUP = (1 << 2),
};
+enum msdp_auth_type {
+ MSDP_AUTH_NONE = 0,
+ MSDP_AUTH_MD5 = 1,
+};
+
struct pim_msdp_peer {
struct pim_instance *pim;
char *mesh_group_name;
char key_str[INET_ADDRSTRLEN];
+ /* Authentication data. */
+ enum msdp_auth_type auth_type;
+ char *auth_key;
+
+ int auth_listen_sock;
+ struct event *auth_listen_ev;
+
/* state */
enum pim_msdp_peer_state state;
enum pim_msdp_peer_flags flags;
void pim_msdp_peer_change_source(struct pim_msdp_peer *mp,
const struct in_addr *addr);
+/**
+ * Restart peer's connection.
+ *
+ * This is used internally in MSDP and should be used by northbound
+ * when wanting to immediately apply connections settings such as
+ * authentication.
+ */
+void pim_msdp_peer_restart(struct pim_msdp_peer *mp);
+
#else /* PIM_IPV == 6 */
static inline void pim_msdp_init(struct pim_instance *pim,
struct event_loop *master)
}
}
+/**
+ * Helper function to reduce code duplication.
+ *
+ * \param vrf VRF pointer (`NULL` means default VRF)
+ * \param mp the MSDP session pointer.
+ * \returns valid file descriptor otherwise `-1`.
+ */
+static int _pim_msdp_sock_listen(const struct vrf *vrf,
+ const struct pim_msdp_peer *mp)
+{
+ const struct interface *ifp;
+ int sock;
+ int rv;
+ socklen_t socklen;
+ struct sockaddr_in sin = {};
+ union sockunion su_peer = {};
+
+ sock = socket(AF_INET, SOCK_STREAM, 0);
+ if (sock == -1) {
+ zlog_warn("%s: socket: %s", __func__, strerror(errno));
+ return -1;
+ }
+
+ socklen = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(PIM_MSDP_TCP_PORT);
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+ sin.sin_len = socklen;
+#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
+ if (mp)
+ sin.sin_addr = mp->local;
+
+ sockopt_reuseaddr(sock);
+ sockopt_reuseport(sock);
+
+ /* Bind socket to VRF/address. */
+ if (vrf && vrf->vrf_id != VRF_DEFAULT) {
+ ifp = if_lookup_by_name(vrf->name, vrf->vrf_id);
+ if (ifp == NULL) {
+ flog_err(EC_LIB_INTERFACE,
+ "%s: Unable to lookup vrf interface: %s",
+ __func__, vrf->name);
+ close(sock);
+ return -1;
+ }
+
+ if (vrf_bind(vrf->vrf_id, sock, ifp->name) == -1) {
+ flog_err_sys(EC_LIB_SOCKET,
+ "%s: Unable to bind to socket: %s",
+ __func__, safe_strerror(errno));
+ close(sock);
+ return -1;
+ }
+ }
+
+ frr_with_privs (&pimd_privs) {
+ rv = bind(sock, (struct sockaddr *)&sin, socklen);
+ }
+ if (rv == -1) {
+ flog_err_sys(EC_LIB_SOCKET,
+ "pim_msdp_socket bind to port %d: %s",
+ ntohs(sin.sin_port), safe_strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ /* Set MD5 authentication. */
+ if (mp && mp->auth_key) {
+ su_peer = mp->su_peer;
+ frr_with_privs (&pimd_privs) {
+ sockopt_tcp_signature(sock, &su_peer, mp->auth_key);
+ }
+ }
+
+
+ /* Start listening. */
+ rv = listen(sock, SOMAXCONN);
+ if (rv == -1) {
+ flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s",
+ safe_strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ /* Set socket DSCP byte */
+ if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) {
+ zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
+ sock, safe_strerror(errno));
+ }
+
+ return sock;
+}
+
+static void pim_msdp_sock_auth_accept(struct event *t)
+{
+ struct pim_msdp_peer *mp = EVENT_ARG(t);
+ int sock;
+ socklen_t sinlen;
+ struct sockaddr_in sin = {};
+
+ /* accept client connection. */
+ sinlen = sizeof(sin);
+ sock = accept(mp->auth_listen_sock, (struct sockaddr *)&sin, &sinlen);
+ if (sock == -1) {
+ flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)",
+ safe_strerror(errno));
+
+ /* Accept failed, schedule listen again. */
+ event_add_read(router->master, pim_msdp_sock_auth_accept, mp,
+ mp->auth_listen_sock, &mp->auth_listen_ev);
+ return;
+ }
+
+ /*
+ * Previous connection still going.
+ *
+ * We must wait for the user to close the previous connection in order
+ * to establish the new one. User can manually force that by calling
+ * `clear ip msdp peer A.B.C.D`.
+ */
+ if (mp->fd != -1) {
+ ++mp->pim->msdp.rejected_accepts;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ flog_err(EC_PIM_MSDP_PACKET,
+ "msdp peer connection refused from %pI4: old connection still running",
+ &sin.sin_addr);
+ }
+ close(sock);
+
+ /* Unexpected connection, schedule listen again. */
+ event_add_read(router->master, pim_msdp_sock_auth_accept, mp,
+ mp->auth_listen_sock, &mp->auth_listen_ev);
+ return;
+ }
+
+ /* Unexpected client connected. */
+ if (mp->peer.s_addr != sin.sin_addr.s_addr) {
+ ++mp->pim->msdp.rejected_accepts;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ flog_err(EC_PIM_MSDP_PACKET,
+ "msdp peer connection refused from %pI4",
+ &sin.sin_addr);
+ }
+ close(sock);
+
+ /* Unexpected peer, schedule listen again. */
+ event_add_read(router->master, pim_msdp_sock_auth_accept, mp,
+ mp->auth_listen_sock, &mp->auth_listen_ev);
+ return;
+ }
+
+ if (PIM_DEBUG_MSDP_INTERNAL)
+ zlog_debug("MSDP peer %s accept success", mp->key_str);
+
+ /* Configure socket. */
+ mp->fd = sock;
+ set_nonblocking(mp->fd);
+ pim_msdp_update_sock_send_buffer_size(mp->fd);
+ pim_msdp_peer_established(mp);
+
+ /* Stop listening. */
+ close(mp->auth_listen_sock);
+ mp->auth_listen_sock = -1;
+}
+
+int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp)
+{
+ /* Clear any listening connection if it exists. */
+ event_cancel(&mp->auth_listen_ev);
+ if (mp->auth_listen_sock != -1) {
+ close(mp->auth_listen_sock);
+ mp->auth_listen_sock = -1;
+ }
+
+ /* Start new listening socket. */
+ mp->auth_listen_sock = _pim_msdp_sock_listen(mp->pim->vrf, mp);
+ if (mp->auth_listen_sock == -1)
+ return -1;
+
+ /* Listen for connections and connected only with the expected end. */
+ event_add_read(router->master, pim_msdp_sock_auth_accept, mp,
+ mp->auth_listen_sock, &mp->auth_listen_ev);
+
+ return 0;
+}
+
/* passive peer socket accept */
static void pim_msdp_sock_accept(struct event *thread)
{
return;
}
+ /*
+ * If authentication is configured then we can not accept
+ * unauthenticated connections.
+ */
+ if (mp->auth_type != MSDP_AUTH_NONE) {
+ ++pim->msdp.rejected_accepts;
+ if (PIM_DEBUG_MSDP_EVENTS) {
+ flog_err(EC_PIM_MSDP_PACKET,
+ "msdp peer unauthenticated connection refused from %pSU",
+ &su);
+ }
+ close(msdp_sock);
+ return;
+ }
+
if (PIM_DEBUG_MSDP_INTERNAL) {
zlog_debug("MSDP peer %s accept success%s", mp->key_str,
mp->fd >= 0 ? "(dup)" : "");
int pim_msdp_sock_listen(struct pim_instance *pim)
{
int sock;
- int socklen;
- struct sockaddr_in sin;
- int rc;
struct pim_msdp_listener *listener = &pim->msdp.listener;
if (pim->msdp.flags & PIM_MSDPF_LISTENER) {
return 0;
}
- sock = socket(AF_INET, SOCK_STREAM, 0);
- if (sock < 0) {
- flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno));
- return sock;
- }
+ sock = _pim_msdp_sock_listen(pim->vrf, NULL);
+ if (sock == -1)
+ return -1;
- memset(&sin, 0, sizeof(struct sockaddr_in));
- sin.sin_family = AF_INET;
- sin.sin_port = htons(PIM_MSDP_TCP_PORT);
- socklen = sizeof(struct sockaddr_in);
+
+ memset(&listener->su.sin, 0, sizeof(listener->su.sin));
+ listener->su.sin.sin_family = AF_INET;
+ listener->su.sin.sin_port = htons(PIM_MSDP_TCP_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
- sin.sin_len = socklen;
+ listener->su.sin.sin_len = sizeof(listener->su.sin);
#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
- sockopt_reuseaddr(sock);
- sockopt_reuseport(sock);
-
- if (pim->vrf->vrf_id != VRF_DEFAULT) {
- struct interface *ifp =
- if_lookup_by_name(pim->vrf->name, pim->vrf->vrf_id);
- if (!ifp) {
- flog_err(EC_LIB_INTERFACE,
- "%s: Unable to lookup vrf interface: %s",
- __func__, pim->vrf->name);
- close(sock);
- return -1;
- }
- if (pim_socket_bind(sock, ifp)) {
- flog_err_sys(EC_LIB_SOCKET,
- "%s: Unable to bind to socket: %s",
- __func__, safe_strerror(errno));
- close(sock);
- return -1;
- }
- }
-
- frr_with_privs(&pimd_privs) {
- /* bind to well known TCP port */
- rc = bind(sock, (struct sockaddr *)&sin, socklen);
- }
-
- if (rc < 0) {
- flog_err_sys(EC_LIB_SOCKET,
- "pim_msdp_socket bind to port %d: %s",
- ntohs(sin.sin_port), safe_strerror(errno));
- close(sock);
- return rc;
- }
-
- rc = listen(sock, 3 /* backlog */);
- if (rc < 0) {
- flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s",
- safe_strerror(errno));
- close(sock);
- return rc;
- }
-
- /* Set socket DSCP byte */
- if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) {
- zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s",
- sock, safe_strerror(errno));
- }
-
/* add accept thread */
listener->fd = sock;
- memcpy(&listener->su, &sin, socklen);
event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock,
&listener->thread);
mp->fd, safe_strerror(errno));
}
+ /* Set authentication (if configured). */
+ if (mp->auth_key) {
+ frr_with_privs (&pimd_privs) {
+ sockopt_tcp_signature(mp->fd, &mp->su_peer,
+ mp->auth_key);
+ }
+ }
+
/* Connect to the remote mp. */
return (sockunion_connect(mp->fd, &mp->su_peer,
htons(PIM_MSDP_TCP_PORT), 0));
#ifndef PIM_MSDP_SOCKET_H
#define PIM_MSDP_SOCKET_H
+struct pim_msdp_peer;
+
+int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp);
int pim_msdp_sock_listen(struct pim_instance *pim);
int pim_msdp_sock_connect(struct pim_msdp_peer *mp);
#endif
.destroy = pim_msdp_peer_sa_filter_out_destroy,
}
},
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type",
+ .cbs = {
+ .modify = pim_msdp_peer_authentication_type_modify,
+ }
+ },
+ {
+ .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key",
+ .cbs = {
+ .modify = pim_msdp_peer_authentication_key_modify,
+ .destroy = pim_msdp_peer_authentication_key_destroy,
+ }
+ },
{
.xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag",
.cbs = {
int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args);
int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args);
int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args);
+int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args);
+int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args);
+int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create(
struct nb_cb_create_args *args);
int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy(
#include "pim_pim.h"
#include "pim_mlag.h"
#include "pim_bfd.h"
+#include "pim_msdp_socket.h"
#include "pim_static.h"
#include "pim_ssm.h"
#include "pim_ssmpingd.h"
nb_cb_destroy_args);
pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create,
nb_cb_create_args);
+pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args);
+pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args);
+pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args);
#if PIM_IPV != 6
/*
return NB_OK;
}
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type
+ */
+int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args)
+{
+ struct pim_msdp_peer *mp;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ mp = nb_running_get_entry(args->dnode, NULL, true);
+ mp->auth_type = yang_dnode_get_enum(args->dnode, NULL);
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key
+ */
+int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args)
+{
+ struct pim_msdp_peer *mp;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ if (strlen(yang_dnode_get_string(args->dnode, NULL)) >
+ TCP_MD5SIG_MAXKEYLEN) {
+ snprintf(args->errmsg, args->errmsg_len,
+ "MD5 authentication key too long");
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_APPLY:
+ mp = nb_running_get_entry(args->dnode, NULL, true);
+ XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key);
+ mp->auth_key = XSTRDUP(MTYPE_PIM_MSDP_AUTH_KEY,
+ yang_dnode_get_string(args->dnode, NULL));
+
+ /* We must start listening the new authentication key now. */
+ if (PIM_MSDP_PEER_IS_LISTENER(mp))
+ pim_msdp_sock_auth_listen(mp);
+ break;
+ }
+
+ return NB_OK;
+}
+
+int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args)
+{
+ struct pim_msdp_peer *mp;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ case NB_EV_APPLY:
+ mp = nb_running_get_entry(args->dnode, NULL, true);
+ XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key);
+ break;
+ }
+
+ return NB_OK;
+}
/*
* XPath: