From 4eddfde2c67309d2efb98ab8291708491e91753f Mon Sep 17 00:00:00 2001 From: Nathan Bahr Date: Thu, 22 Aug 2024 22:36:00 +0000 Subject: [PATCH] pim,yang: Implement AutoRP announcements Signed-off-by: Nathan Bahr --- pimd/pim_autorp.c | 862 ++++++++++++++++++++++++++++++++++-------- pimd/pim_autorp.h | 83 +++- pimd/pim_cmd.c | 113 +++++- pimd/pim_cmd_common.c | 141 ++++++- pimd/pim_cmd_common.h | 8 + pimd/pim_iface.c | 3 +- pimd/pim_nb.c | 50 ++- pimd/pim_nb.h | 30 +- pimd/pim_nb_config.c | 327 +++++++++++++++- yang/frr-pim-rp.yang | 71 +++- 10 files changed, 1484 insertions(+), 204 deletions(-) diff --git a/pimd/pim_autorp.c b/pimd/pim_autorp.c index 9fe29fcfe091..5192fac274a6 100644 --- a/pimd/pim_autorp.c +++ b/pimd/pim_autorp.c @@ -8,10 +8,12 @@ #include -#include "plist.h" -#include "plist_int.h" +#include "lib/plist.h" +#include "lib/plist_int.h" #include "lib/sockopt.h" #include "lib/network.h" +#include "lib/termtable.h" +#include "lib/json.h" #include "pimd.h" #include "pim_iface.h" @@ -22,6 +24,8 @@ DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP, "PIM AutoRP info"); DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_RP, "PIM AutoRP advertised RP info"); +DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_CRP, "PIM AutoRP candidate RP info"); +DEFINE_MTYPE_STATIC(PIMD, PIM_AUTORP_ANNOUNCE, "PIM AutoRP announcement packet"); static const char *PIM_AUTORP_ANNOUNCEMENT_GRP = "224.0.1.39"; static const char *PIM_AUTORP_DISCOVERY_GRP = "224.0.1.40"; @@ -60,86 +64,99 @@ static void pim_autorp_rplist_free(struct pim_autorp_rp_head *head) pim_autorp_rp_free(rp); } +static void pim_autorp_rplist_cfree(struct pim_autorp_rp_head *head) +{ + struct pim_autorp_rp *rp; + + while ((rp = pim_autorp_rp_pop(head))) + XFREE(MTYPE_PIM_AUTORP_CRP, rp); +} + static void pim_autorp_free(struct pim_autorp *autorp) { - pim_autorp_rplist_free(&(autorp->rplist)); - pim_autorp_rp_fini(&(autorp->rplist)); + pim_autorp_rplist_free(&(autorp->discovery_rp_list)); + pim_autorp_rp_fini(&(autorp->discovery_rp_list)); + + pim_autorp_rplist_cfree(&(autorp->candidate_rp_list)); + pim_autorp_rp_fini(&(autorp->candidate_rp_list)); } static int pim_autorp_join_groups(struct interface *ifp) { - struct pim_instance *pim; struct pim_interface *pim_ifp; + struct pim_instance *pim; + struct pim_autorp *autorp; pim_addr grp; - pim_ifp = ifp->info; - if (pim_ifp && pim_ifp->pim_enable) { - pim = pim_ifp->pim; - if (pim->autorp->enable) { - inet_pton(PIM_AF, PIM_AUTORP_DISCOVERY_GRP, &grp); - if (pim_socket_join(pim->autorp->sock, grp, - pim_ifp->primary_address, - ifp->ifindex, pim_ifp)) { - zlog_err("Failed to join group %pI4 on interface %s", - &grp, ifp->name); - return errno; - } - inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &grp); - if (pim_socket_join(pim->autorp->sock, grp, - pim_ifp->primary_address, - ifp->ifindex, pim_ifp)) { - zlog_err("Failed to join group %pI4 on interface %s", - &grp, ifp->name); - return errno; - } + pim_ifp = ifp->info; + pim = pim_ifp->pim; + autorp = pim->autorp; + + inet_pton(PIM_AF, PIM_AUTORP_DISCOVERY_GRP, &grp); + if (pim_socket_join(autorp->sock, grp, pim_ifp->primary_address, + ifp->ifindex, pim_ifp)) { + zlog_err("Failed to join group %pI4 on interface %s", &grp, + ifp->name); + return errno; + } - if (PIM_DEBUG_AUTORP) - zlog_debug("%s: Joined AutoRP groups on interface %s", - __func__, ifp->name); - } + /* + inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &grp); + if (pim_socket_join(pim->autorp->sock, grp, + pim_ifp->primary_address, + ifp->ifindex, pim_ifp)) { + zlog_err("Failed to join group %pI4 on interface %s", + &grp, ifp->name); + return errno; } +*/ + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Joined AutoRP groups on interface %s", __func__, + ifp->name); + return 0; } static int pim_autorp_leave_groups(struct interface *ifp) { - struct pim_instance *pim; struct pim_interface *pim_ifp; + struct pim_instance *pim; + struct pim_autorp *autorp; pim_addr grp; - pim_ifp = ifp->info; - if (pim_ifp && pim_ifp->pim_enable) { - pim = pim_ifp->pim; - if (pim->autorp->enable) { - inet_pton(PIM_AF, PIM_AUTORP_DISCOVERY_GRP, &grp); - if (pim_socket_leave(pim->autorp->sock, grp, - pim_ifp->primary_address, - ifp->ifindex, pim_ifp)) { - zlog_err("Failed to leave group %pI4 on interface %s", - &grp, ifp->name); - return errno; - } - inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &grp); - if (pim_socket_leave(pim->autorp->sock, grp, - pim_ifp->primary_address, - ifp->ifindex, pim_ifp)) { - zlog_err("Failed to leave group %pI4 on interface %s", - &grp, ifp->name); - return errno; - } + pim_ifp = ifp->info; + pim = pim_ifp->pim; + autorp = pim->autorp; + + inet_pton(PIM_AF, PIM_AUTORP_DISCOVERY_GRP, &grp); + if (pim_socket_leave(autorp->sock, grp, pim_ifp->primary_address, + ifp->ifindex, pim_ifp)) { + zlog_err("Failed to leave group %pI4 on interface %s", &grp, + ifp->name); + return errno; + } - if (PIM_DEBUG_AUTORP) - zlog_debug("%s: Left AutoRP groups on interface %s", - __func__, ifp->name); - } + /* + inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &grp); + if (pim_socket_leave(pim->autorp->sock, grp, + pim_ifp->primary_address, + ifp->ifindex, pim_ifp)) { + zlog_err("Failed to leave group %pI4 on interface %s", + &grp, ifp->name); + return errno; } +*/ + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Left AutoRP groups on interface %s", __func__, + ifp->name); + return 0; } static int pim_autorp_setup(struct pim_autorp *autorp) { - struct interface *ifp; - int data; socklen_t data_len = sizeof(data); @@ -165,6 +182,12 @@ static int pim_autorp_setup(struct pim_autorp *autorp) return errno; } + if (sockopt_reuseaddr(autorp->sock)) { + zlog_err("Could not set reuse addr on socket fd=%d: errno=%d: %s", + autorp->sock, errno, safe_strerror(errno)); + return errno; + } + if (bind(autorp->sock, (const struct sockaddr *)&autorp_addr, sizeof(autorp_addr)) < 0) { zlog_err("Could not bind socket: %pSUp, fd=%d, errno=%d, %s", @@ -173,15 +196,6 @@ static int pim_autorp_setup(struct pim_autorp *autorp) return errno; } - FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) { - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && - pim_autorp_join_groups(ifp)) { - zlog_err("Could not join AutoRP groups, errno=%d, %s", - errno, safe_strerror(errno)); - return errno; - } - } - if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP finished setup", __func__); @@ -192,6 +206,7 @@ static int pim_autorp_announcement(struct pim_autorp *autorp, uint8_t rpcnt, uint16_t holdtime, const char *buf, size_t buf_size) { + /* TODO: Implement AutoRP mapping agent logic using received announcement messages */ if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP processed announcement message", __func__); @@ -202,7 +217,7 @@ static void autorp_rp_holdtime(struct event *evt) { /* RP hold time expired, remove the RP */ struct pim_autorp_rp *rp = EVENT_ARG(evt); - pim_autorp_rp_del(&(rp->autorp->rplist), rp); + pim_autorp_rp_del(&(rp->autorp->discovery_rp_list), rp); pim_autorp_rp_free(rp); if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP hold time expired, RP removed: addr=%pI4, grp=%pFX, grplist=%s", @@ -240,10 +255,10 @@ static int pim_autorp_add_rp(struct pim_autorp *autorp, pim_addr rpaddr, } rp->holdtime = holdtime; rp->hold_timer = NULL; - trp = pim_autorp_rp_add(&(autorp->rplist), rp); + trp = pim_autorp_rp_add(&(autorp->discovery_rp_list), rp); if (trp == NULL) { /* RP was brand new */ - trp = pim_autorp_rp_find(&(autorp->rplist), + trp = pim_autorp_rp_find(&(autorp->discovery_rp_list), (const struct pim_autorp_rp *)rp); } else { /* RP already existed */ @@ -301,60 +316,46 @@ static int pim_autorp_discovery(struct pim_autorp *autorp, uint8_t rpcnt, offset += AUTORP_RPLEN; rp_addr.s_addr = rp->addr; - /* TODO: What so do with pim version? */ + /* TODO: What so do with pim version? + * rp->pimver; + */ - if (rp->grpcnt == 1) { - /* Only one group, we can use the standard RP API */ - if ((buf_size - offset) < AUTORP_GRPLEN) { - return -1; - } - grp = (const struct autorp_pkt_grp *)(buf + offset); - offset += AUTORP_GRPLEN; - - if (grp->negprefix) { - /* TODO: Handle negative group prefix */ - /* If there is only one group and it's negative, then make a prefix list for this case */ - zlog_warn("%s: Negative group prefix is not supported, not using RP %pI4", - __func__, &rp_addr); - continue; - } + if (rp->grpcnt == 0) { + /* No groups?? */ + zlog_warn("%s: Discovery message has no groups for RP %pI4", + __func__, &(rp->addr)); + continue; + } + if ((buf_size - offset) < AUTORP_GRPLEN) + return -1; + + grp = (const struct autorp_pkt_grp *)(buf + offset); + offset += AUTORP_GRPLEN; + + if (rp->grpcnt == 1 && grp->negprefix == 0) { + /* Only one group with positive prefix, we can use the standard RP API */ grppfix.family = AF_INET; grppfix.prefixlen = grp->masklen; grppfix.u.prefix4.s_addr = grp->addr; - ret += pim_autorp_add_rp(autorp, rp_addr, grppfix, NULL, holdtime); - } else if (rp->grpcnt > 1) { - /* More than one grp, need to make a prefix list for this RP */ + } else { + /* More than one grp, or the the only group is a negative prefix, need to make a prefix list for this RP */ snprintfrr(plname, sizeof(plname), "__AUTORP_%pI4__", &rp_addr); pl = prefix_list_get(AFI_IP, 0, plname); for (j = 0; j < rp->grpcnt; ++j) { - if ((buf_size - offset) < AUTORP_GRPLEN) { - return -1; - } - grp = (const struct autorp_pkt_grp *)(buf + - offset); - offset += AUTORP_GRPLEN; - - if (grp->negprefix) { - /* TODO: Handle negative group prefix */ - zlog_warn("%s: Negative group prefix is not supported, not using RP %pI4", - __func__, &rp_addr); - prefix_list_delete(pl); - pl = NULL; - break; - } - + /* grp is already pointing at the first group in the buffer */ ple = prefix_list_entry_new(); ple->pl = pl; ple->seq = seq; seq += 5; memset(&ple->prefix, 0, sizeof(ple->prefix)); prefix_list_entry_update_start(ple); - ple->type = PREFIX_PERMIT; + ple->type = (grp->negprefix ? PREFIX_DENY + : PREFIX_PERMIT); ple->prefix.family = AF_INET; ple->prefix.prefixlen = grp->masklen; ple->prefix.u.prefix4.s_addr = grp->addr; @@ -362,17 +363,17 @@ static int pim_autorp_discovery(struct pim_autorp *autorp, uint8_t rpcnt, ple->ge = 0; ple->le = 32; prefix_list_entry_update_finish(ple); - } - if (pl != NULL) { - ret += pim_autorp_add_rp(autorp, rp_addr, - grppfix, plname, - holdtime); + if ((buf_size - offset) < AUTORP_GRPLEN) { + return -1; + } + grp = (const struct autorp_pkt_grp *)(buf + + offset); + offset += AUTORP_GRPLEN; } - } else { - /* No groups?? */ - zlog_warn("%s: Discovery message has no groups for RP %pI4", - __func__, &(rp->addr)); + + ret += pim_autorp_add_rp(autorp, rp_addr, grppfix, + plname, holdtime); } } @@ -417,15 +418,15 @@ static void autorp_read(struct event *t); static void autorp_read_on(struct pim_autorp *autorp) { event_add_read(router->master, autorp_read, autorp, autorp->sock, - &(autorp->ev_msg)); + &(autorp->read_event)); if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP socket read enabled", __func__); } static void autorp_read_off(struct pim_autorp *autorp) { - if (autorp->ev_msg) { - event_cancel(&(autorp->ev_msg)); + if (autorp->read_event) { + event_cancel(&(autorp->read_event)); if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP socket read disabled", __func__); } @@ -489,8 +490,6 @@ static int pim_autorp_socket_enable(struct pim_autorp *autorp) } } - autorp_read_on(autorp); - if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP socket enabled", __func__); @@ -514,6 +513,379 @@ static int pim_autorp_socket_disable(struct pim_autorp *autorp) return 0; } +static void autorp_send_announcement(struct event *evt) +{ + struct pim_autorp *autorp = EVENT_ARG(evt); + struct interface *ifp; + struct pim_interface *pim_ifp; + struct sockaddr_in announceGrp; + announceGrp.sin_family = AF_INET; + announceGrp.sin_port = htons(PIM_AUTORP_PORT); + inet_pton(PIM_AF, PIM_AUTORP_ANNOUNCEMENT_GRP, &announceGrp.sin_addr); + + if (autorp->annouce_pkt_sz >= MIN_AUTORP_PKT_SZ) { + // setsockopt(autorp->sock, IPPROTO_IP, IP_TTL, &(autorp->announce_scope), sizeof(autorp->announce_scope)); + setsockopt(autorp->sock, IPPROTO_IP, IP_MULTICAST_TTL, + &(autorp->announce_scope), + sizeof(autorp->announce_scope)); + + // TODO Or maybe we just send on the loopback or any old interface and rely on multicast routing to forward it? + FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) { + pim_ifp = ifp->info; + /* Only send on active interfaces with full pim enabled, non-passive */ + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && + pim_ifp && pim_ifp->pim_enable && + !pim_ifp->pim_passive_enable) { + /* Make sure the address is set */ + if (!pim_addr_is_any(pim_ifp->primary_address)) { + setsockopt(autorp->sock, IPPROTO_IP, + IP_MULTICAST_IF, + &(pim_ifp->primary_address), + sizeof(pim_ifp->primary_address)); + sendto(autorp->sock, autorp->annouce_pkt, + autorp->annouce_pkt_sz, 0, + &announceGrp, + sizeof(announceGrp)); + } else { + /* Unable to send on this interface */ + } + } + } + } + + /* Start the new timer for the entire announce interval */ + event_add_timer(router->master, autorp_send_announcement, autorp, + autorp->announce_interval, &(autorp->announce_timer)); +} + +static void autorp_announcement_on(struct pim_autorp *autorp) +{ + int interval = 5; + if (interval > autorp->announce_interval) { + /* If the configured interval is less than 5 seconds, then just use that */ + interval = autorp->announce_interval; + } + event_add_timer(router->master, autorp_send_announcement, autorp, + interval, &(autorp->announce_timer)); + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP announcement sending enabled", __func__); +} + +static void autorp_announcement_off(struct pim_autorp *autorp) +{ + if (autorp->announce_timer) { + event_cancel(&(autorp->announce_timer)); + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP announcement sending disabled", + __func__); + } +} + +/* Pack the groups of the RP + * rp - Pointer to the RP + * buf - Pointer to the buffer where to start packing groups + * returns - Total group count packed + */ +static uint8_t pim_autorp_new_announcement_rp_grps(struct pim_autorp_rp *rp, + uint8_t *buf) +{ + struct prefix_list *plist; + struct prefix_list_entry *ple; + struct autorp_pkt_grp *grpp = (struct autorp_pkt_grp *)buf; + uint8_t cnt = 0; + in_addr_t taddr; + + if (is_default_prefix(&(rp->grp))) { + /* No group so pack from the prefix list + * The grplist should be set and the prefix list exist with at least one group address + */ + plist = prefix_list_lookup(AFI_IP, rp->grplist); + for (ple = plist->head; ple; ple = ple->next) { + taddr = ntohl(ple->prefix.u.prefix4.s_addr); + if ((taddr & 0xF0000000) == 0xE0000000) { + grpp->addr = ple->prefix.u.prefix4.s_addr; + grpp->masklen = ple->prefix.prefixlen; + grpp->negprefix = + (ple->type == PREFIX_PERMIT ? 0 : 1); + grpp->reserved = 0; + + ++cnt; + grpp = (struct autorp_pkt_grp + *)(buf + + (sizeof(struct autorp_pkt_grp) * + cnt)); + } + } + + return cnt; + } else { + /* Only one of group or prefix list should be defined */ + grpp->addr = rp->grp.u.prefix4.s_addr; + grpp->masklen = rp->grp.prefixlen; + grpp->negprefix = 0; + grpp->reserved = 0; + return 1; + } +} + +/* Pack a single candidate RP + * rp - Pointer to the RP to pack + * buf - Pointer to the buffer where to start packing the RP + * returns - Buffer pointer pointing to the start of the next RP + */ +static uint8_t *pim_autorp_new_announcement_rp(struct pim_autorp_rp *rp, + uint8_t *buf) +{ + struct autorp_pkt_rp *brp = (struct autorp_pkt_rp *)buf; + + brp->addr = + rp->addr.s_addr; /* Since this is an in_addr, assume it's already the right byte order */ + /* TODO What is the right PIM version here? */ + brp->pimver = PIMV1_2; + brp->reserved = 0; + brp->grpcnt = + pim_autorp_new_announcement_rp_grps(rp, + buf + sizeof(struct autorp_pkt_rp)); + return buf + sizeof(struct autorp_pkt_rp) + + (brp->grpcnt * sizeof(struct autorp_pkt_grp)); +} + +/* Pack the candidate RP's on the announcement packet + * autorp - Pointer to the AutoRP instance + * buf - Pointer to the buffer where to start packing the first RP + * bufsz - Output parameter to track size of packed bytes + * returns - Total count of RP's packed + */ +static int pim_autorp_new_announcement_rps(struct pim_autorp *autorp, + uint8_t *buf, uint16_t *bufsz) +{ + int cnt = 0; + struct pim_autorp_rp *rp; + /* Keep the original buffer pointer to calculate final size after packing */ + uint8_t *obuf = buf; + struct prefix_list *plist; + struct prefix_list_entry *ple; + in_addr_t taddr; + + frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) { + /* We must have an rp address and either group or list in order to pack this RP, so skip this one */ + if (pim_addr_is_any(rp->addr) || + (is_default_prefix(&(rp->grp)) && strlen(rp->grplist) == 0)) + continue; + + /* Group is net set, so list must be set, make sure the prefix list exists and has valid multicast groups */ + if (is_default_prefix(&(rp->grp))) { + plist = prefix_list_lookup(AFI_IP, rp->grplist); + if (plist == NULL) + continue; + plist = prefix_list_lookup(AFI_IP, rp->grplist); + for (ple = plist->head; ple; ple = ple->next) { + taddr = ntohl(ple->prefix.u.prefix4.s_addr); + if ((taddr & 0xF0000000) == 0xE0000000) { + break; + } + } + + /* If we went through the entire list without finding a multicast prefix, then skip this RP */ + if (ple == NULL) + continue; + } + + /* Now we know for sure we will pack this RP, so count it */ + ++cnt; + /* This will return the buffer pointer at the location to start packing the next RP */ + buf = pim_autorp_new_announcement_rp(rp, buf); + } + + if (cnt > 0) + *bufsz = buf - obuf; + + return cnt; +} + +/* Build the new announcement packet. If there is a packet to send, restart the send timer with a short wait + * Returns <0 if an error occurred, otherwise 0 (Not having an announcement to send is not an error) + */ +static int pim_autorp_new_announcement(struct pim_instance *pim) +{ + struct pim_autorp *autorp = pim->autorp; + struct autorp_pkt_hdr *hdr; + int32_t holdtime; + + /* First disable any existing send timer */ + autorp_announcement_off(autorp); + + if (!autorp->annouce_pkt) { + /* + * First time building, allocate the space + * Allocate the max packet size of 65536 so we don't need to resize later. + * This should be ok since we are only allocating the memory once for a single packet (potentially per vrf) + */ + autorp->annouce_pkt = XCALLOC(MTYPE_PIM_AUTORP_ANNOUNCE, 65536); + } + + autorp->annouce_pkt_sz = 0; + + holdtime = autorp->announce_holdtime; + if (holdtime == DEFAULT_ANNOUNCE_HOLDTIME) + holdtime = autorp->announce_interval * 3; + if (holdtime > UINT16_MAX) + holdtime = UINT16_MAX; + + hdr = (struct autorp_pkt_hdr *)autorp->annouce_pkt; + hdr->version = AUTORP_VERSION; + hdr->type = AUTORP_ANNOUNCEMENT_TYPE; + hdr->holdtime = htons((uint16_t)holdtime); + hdr->reserved = 0; + hdr->rpcnt = + pim_autorp_new_announcement_rps(autorp, + autorp->annouce_pkt + + sizeof(struct autorp_pkt_hdr), + &(autorp->annouce_pkt_sz)); + + /* Still need to add on the size of the header */ + autorp->annouce_pkt_sz += sizeof(struct autorp_pkt_hdr); + + if (autorp->annouce_pkt_sz >= MIN_AUTORP_PKT_SZ) + autorp_announcement_on(autorp); + + return 0; +} + +int pim_autorp_rm_candidate_rp(struct pim_instance *pim, pim_addr rpaddr) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *trp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + trp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (trp) { + pim_autorp_rp_del(&(autorp->candidate_rp_list), trp); + pim_autorp_rp_free(trp); + return pim_autorp_new_announcement(pim); + } + return -1; +} + +int pim_autorp_add_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr, + struct prefix group) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (!rp) { + rp = XCALLOC(MTYPE_PIM_AUTORP_CRP, sizeof(*rp)); + memset(rp, 0, sizeof(struct pim_autorp_rp)); + rp->autorp = autorp; + memcpy(&(rp->addr), &rpaddr, sizeof(pim_addr)); + pim_autorp_rp_add(&(autorp->candidate_rp_list), rp); + } + + apply_mask(&group); + prefix_copy(&(rp->grp), &group); + /* A new group prefix implies that any previous prefix list is now invalid */ + rp->grplist[0] = '\0'; + + return pim_autorp_new_announcement(pim); +} + +int pim_autorp_rm_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr, + struct prefix group) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (rp) { + memset(&(rp->grp), 0, sizeof(rp->grp)); + return pim_autorp_new_announcement(pim); + } + return -1; +} + +int pim_autorp_add_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr, + const char *plist) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (!rp) { + rp = XCALLOC(MTYPE_PIM_AUTORP_CRP, sizeof(*rp)); + memset(rp, 0, sizeof(struct pim_autorp_rp)); + rp->autorp = autorp; + memcpy(&(rp->addr), &rpaddr, sizeof(pim_addr)); + pim_autorp_rp_add(&(autorp->candidate_rp_list), rp); + } + + snprintf(rp->grplist, sizeof(rp->grplist), "%s", plist); + /* A new group prefix list implies that any previous group prefix is now invalid */ + memset(&(rp->grp), 0, sizeof(rp->grp)); + + return pim_autorp_new_announcement(pim); +} + +int pim_autorp_rm_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr, + const char *plist) +{ + struct pim_autorp *autorp = pim->autorp; + struct pim_autorp_rp *rp; + struct pim_autorp_rp find = { .addr = rpaddr }; + rp = pim_autorp_rp_find(&(autorp->candidate_rp_list), + (const struct pim_autorp_rp *)&find); + if (rp) { + rp->grplist[0] = '\0'; + return pim_autorp_new_announcement(pim); + } + return -1; +} + +int pim_autorp_announce_scope(struct pim_instance *pim, uint8_t scope) +{ + struct pim_autorp *autorp = pim->autorp; + scope = (scope == 0 ? DEFAULT_ANNOUNCE_SCOPE : scope); + + if (autorp->announce_scope == scope) { + return 0; + } + + autorp->announce_scope = scope; + return pim_autorp_new_announcement(pim); +} + +int pim_autorp_announce_interval(struct pim_instance *pim, uint16_t interval) +{ + struct pim_autorp *autorp = pim->autorp; + interval = (interval == 0 ? DEFAULT_ANNOUNCE_INTERVAL : interval); + + if (autorp->announce_interval == interval) { + return 0; + } + + autorp->announce_interval = interval; + return pim_autorp_new_announcement(pim); +} + +int pim_autorp_announce_holdtime(struct pim_instance *pim, int32_t holdtime) +{ + struct pim_autorp *autorp = pim->autorp; + + if (autorp->announce_holdtime == holdtime) { + return 0; + } + + autorp->announce_holdtime = holdtime; + return pim_autorp_new_announcement(pim); +} + int pim_autorp_add_ifp(struct interface *ifp) { /* Add a new interface for autorp @@ -525,14 +897,21 @@ int pim_autorp_add_ifp(struct interface *ifp) * This is called even when adding a new pim interface that is not yet * active, so make sure the check, it'll call in again once the interface is up. */ - if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) { - if (PIM_DEBUG_AUTORP) - zlog_debug("%s: Adding interface %s to AutoRP, joining AutoRP groups", - __func__, ifp->name); - if (pim_autorp_join_groups(ifp)) { - zlog_err("Could not join AutoRP groups, errno=%d, %s", - errno, safe_strerror(errno)); - return errno; + struct pim_instance *pim; + struct pim_interface *pim_ifp; + pim_ifp = ifp->info; + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && pim_ifp && + pim_ifp->pim_enable) { + pim = pim_ifp->pim; + if (pim && pim->autorp && pim->autorp->do_discovery) { + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Adding interface %s to AutoRP, joining AutoRP groups", + __func__, ifp->name); + if (pim_autorp_join_groups(ifp)) { + zlog_err("Could not join AutoRP groups, errno=%d, %s", + errno, safe_strerror(errno)); + return errno; + } } } return 0; @@ -544,16 +923,57 @@ int pim_autorp_rm_ifp(struct interface *ifp) * When an interface is no longer enabled for multicast, or at all, then * we should leave the AutoRP groups on this interface. */ - /* TODO Should we check CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)? - * If the interface disappeared, then maybe we don't care about leaving - */ - if (PIM_DEBUG_AUTORP) - zlog_debug("%s: Removing interface %s from AutoRP, leaving AutoRP groups", - __func__, ifp->name); - if (pim_autorp_leave_groups(ifp)) { - zlog_err("Could not leave AutoRP groups, errno=%d, %s", errno, - safe_strerror(errno)); - return errno; + struct pim_instance *pim; + struct pim_interface *pim_ifp; + pim_ifp = ifp->info; + if (CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE) && pim_ifp) { + pim = pim_ifp->pim; + if (pim && pim->autorp) { + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: Removing interface %s from AutoRP, leaving AutoRP groups", + __func__, ifp->name); + if (pim_autorp_leave_groups(ifp)) { + zlog_err("Could not leave AutoRP groups, errno=%d, %s", + errno, safe_strerror(errno)); + return errno; + } + } + } + return 0; +} + +int pim_autorp_start_discovery(struct pim_instance *pim) +{ + struct interface *ifp; + struct pim_autorp *autorp = pim->autorp; + if (!autorp->do_discovery) { + autorp->do_discovery = true; + autorp_read_on(autorp); + + FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) { + pim_autorp_add_ifp(ifp); + } + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP Discovery started", __func__); + } + return 0; +} + +int pim_autorp_stop_discovery(struct pim_instance *pim) +{ + struct interface *ifp; + struct pim_autorp *autorp = pim->autorp; + if (autorp->do_discovery) { + FOR_ALL_INTERFACES (autorp->pim->vrf, ifp) { + pim_autorp_rm_ifp(ifp); + } + + autorp->do_discovery = false; + autorp_read_off(autorp); + + if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP Discovery stopped", __func__); } return 0; } @@ -562,10 +982,22 @@ int pim_autorp_init(struct pim_instance *pim) { struct pim_autorp *autorp; autorp = XCALLOC(MTYPE_PIM_AUTORP, sizeof(*autorp)); - autorp->ev_msg = NULL; - autorp->sock = -1; - autorp->enable = false; autorp->pim = pim; + autorp->sock = -1; + autorp->read_event = NULL; + autorp->announce_timer = NULL; + autorp->do_discovery = false; + pim_autorp_rp_init(&(autorp->discovery_rp_list)); + pim_autorp_rp_init(&(autorp->candidate_rp_list)); + autorp->announce_scope = DEFAULT_ANNOUNCE_SCOPE; + autorp->announce_interval = DEFAULT_ANNOUNCE_INTERVAL; + autorp->announce_holdtime = DEFAULT_ANNOUNCE_HOLDTIME; + + if (pim_autorp_socket_enable(autorp)) { + zlog_err("%s: AutoRP failed to initialize", __func__); + return -1; + } + pim->autorp = autorp; if (PIM_DEBUG_AUTORP) zlog_debug("%s: AutoRP Initialized", __func__); @@ -573,45 +1005,141 @@ int pim_autorp_init(struct pim_instance *pim) return 0; } -int pim_autorp_start(struct pim_instance *pim) -{ - struct pim_autorp *autorp = pim->autorp; - int ret = 0; - if (!autorp->enable) { - pim_autorp_rp_init(&(autorp->rplist)); - autorp->enable = true; - ret = pim_autorp_socket_enable(autorp); - if (ret) - zlog_err("%s: AutoRP failed to start", __func__); - else if (PIM_DEBUG_AUTORP) - zlog_debug("%s: AutoRP Started", __func__); - } - return ret; -} - int pim_autorp_finish(struct pim_instance *pim) { struct pim_autorp *autorp = pim->autorp; int ret = 0; - if (autorp->enable) { - autorp->enable = false; - pim_autorp_free(autorp); - ret = pim_autorp_socket_disable(autorp); - if (ret) - zlog_err("%s: AutoRP failed to finish", __func__); - else if (PIM_DEBUG_AUTORP) - zlog_debug("%s: AutoRP Finished", __func__); - } + autorp_read_off(autorp); + pim_autorp_free(autorp); + ret = pim_autorp_socket_disable(autorp); + if (ret) + zlog_err("%s: AutoRP failed to finish", __func__); + else if (PIM_DEBUG_AUTORP) + zlog_debug("%s: AutoRP Finished", __func__); + XFREE(MTYPE_PIM_AUTORP, pim->autorp); return ret; } int pim_autorp_config_write(struct pim_instance *pim, struct vty *vty) { + struct pim_autorp_rp *rp; struct pim_autorp *autorp = pim->autorp; - if (autorp->enable) { + char interval_str[16] = { 0 }; + char scope_str[16] = { 0 }; + char holdtime_str[32] = { 0 }; + char grp_str[64] = { 0 }; + int writes = 0; + + if (autorp->do_discovery) { vty_out(vty, " autorp discovery\n"); - return 1; + ++writes; } - return 0; + + if (autorp->announce_interval != DEFAULT_ANNOUNCE_INTERVAL) { + snprintf(interval_str, sizeof(interval_str), " interval %u", + autorp->announce_interval); + } + + if (autorp->announce_scope != DEFAULT_ANNOUNCE_SCOPE) { + snprintf(scope_str, sizeof(scope_str), " scope %u", + autorp->announce_scope); + } + + if (autorp->announce_holdtime != DEFAULT_ANNOUNCE_HOLDTIME) { + snprintf(holdtime_str, sizeof(holdtime_str), " holdtime %u", + autorp->announce_holdtime); + } + + if (strlen(interval_str) || strlen(scope_str) || strlen(holdtime_str)) { + vty_out(vty, " autorp announce%s%s%s\n", interval_str, + scope_str, holdtime_str); + ++writes; + } + + frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) { + /* Only print candidate RP's that have all the information needed to be announced */ + if (pim_addr_is_any(rp->addr) || + (is_default_prefix(&(rp->grp)) && strlen(rp->grplist) == 0)) + continue; + + /* Don't make sure the prefix list has multicast groups, user may not have created it yet */ + + if (!is_default_prefix(&(rp->grp))) + snprintfrr(grp_str, sizeof(grp_str), "%pFX", &(rp->grp)); + else + snprintfrr(grp_str, sizeof(grp_str), "group-list %s", + rp->grplist); + + vty_out(vty, " autorp announce %pI4 %s\n", &(rp->addr), grp_str); + ++writes; + } + + return writes; } + +void pim_autorp_show_autorp(struct vty *vty, struct pim_instance *pim, + json_object *json) +{ + struct pim_autorp_rp *rp; + struct pim_autorp *autorp = pim->autorp; + struct ttable *tt = NULL; + char *table = NULL; + char grp_str[64] = { 0 }; + char plist_str[64] = { 0 }; + json_object *annouce_jobj; + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "RP address|group|prefix-list"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + + frr_each_safe (pim_autorp_rp, &(autorp->candidate_rp_list), rp) { + if (!is_default_prefix(&(rp->grp))) + snprintfrr(grp_str, sizeof(grp_str), "%pFX", &(rp->grp)); + else + snprintfrr(plist_str, sizeof(plist_str), "%s", + rp->grplist); + + ttable_add_row(tt, "%pPA|%s|%s", &(rp->addr), grp_str, + plist_str); + } + + if (json) { + json_object_boolean_add(json, "discoveryEnabled", + autorp->do_discovery); + + annouce_jobj = json_object_new_object(); + json_object_int_add(annouce_jobj, "scope", + autorp->announce_scope); + json_object_int_add(annouce_jobj, "interval", + autorp->announce_interval); + json_object_int_add(annouce_jobj, "holdtime", + autorp->announce_holdtime); + json_object_object_add(annouce_jobj, "rpList", + ttable_json_with_json_text( + tt, "sss", + "rpAddress|group|prefixList")); + + json_object_object_add(json, "announce", annouce_jobj); + } else { + vty_out(vty, "AutoRP Discovery is %sabled\n", + (autorp->do_discovery ? "en" : "dis")); + vty_out(vty, "AutoRP Candidate RPs\n"); + vty_out(vty, " interval %us, scope %u, holdtime %us\n", + autorp->announce_interval, autorp->announce_scope, + (autorp->announce_holdtime == DEFAULT_ANNOUNCE_HOLDTIME + ? (autorp->announce_interval * 3) + : autorp->announce_holdtime)); + + vty_out(vty, "\n"); + + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } + + ttable_del(tt); +} \ No newline at end of file diff --git a/pimd/pim_autorp.h b/pimd/pim_autorp.h index e1021460917b..15b3fe4e15b5 100644 --- a/pimd/pim_autorp.h +++ b/pimd/pim_autorp.h @@ -18,9 +18,13 @@ #define PIMV2 2 #define PIMV1_2 3 +#define DEFAULT_ANNOUNCE_INTERVAL 60 +#define DEFAULT_ANNOUNCE_SCOPE 31 +#define DEFAULT_ANNOUNCE_HOLDTIME -1 + PREDECL_SORTLIST_UNIQ(pim_autorp_rp); -struct __attribute__((__packed__)) autorp_pkt_grp { +struct autorp_pkt_grp { #if __BYTE_ORDER == __LITTLE_ENDIAN uint8_t negprefix : 1; uint8_t reserved : 7; @@ -32,9 +36,9 @@ struct __attribute__((__packed__)) autorp_pkt_grp { #endif uint8_t masklen; uint32_t addr; -}; +} __attribute__((__packed__)); -struct __attribute__((__packed__)) autorp_pkt_rp { +struct autorp_pkt_rp { uint32_t addr; #if __BYTE_ORDER == __LITTLE_ENDIAN uint8_t pimver : 2; @@ -46,9 +50,9 @@ struct __attribute__((__packed__)) autorp_pkt_rp { #error "Please fix " #endif uint8_t grpcnt; -}; +} __attribute__((__packed__)); -struct __attribute__((__packed__)) autorp_pkt_hdr { +struct autorp_pkt_hdr { #if __BYTE_ORDER == __LITTLE_ENDIAN uint8_t type : 4; uint8_t version : 4; @@ -61,7 +65,11 @@ struct __attribute__((__packed__)) autorp_pkt_hdr { uint8_t rpcnt; uint16_t holdtime; uint32_t reserved; -}; +} __attribute__((__packed__)); + +#define MIN_AUTORP_PKT_SZ \ + (sizeof(struct autorp_pkt_hdr) + sizeof(struct autorp_pkt_rp) + \ + sizeof(struct autorp_pkt_grp)) struct pim_autorp_rp { struct pim_autorp *autorp; @@ -74,22 +82,77 @@ struct pim_autorp_rp { }; struct pim_autorp { + /* backpointer to pim instance */ struct pim_instance *pim; + + /* UDP socket bound to AutoRP port, used for sending and receiving all AutoRP packets */ int sock; - struct event *ev_msg; - bool enable; - struct pim_autorp_rp_head rplist; + + /* Event for reading AutoRP packets */ + struct event *read_event; + + /* Event for sending announcement packets */ + struct event *announce_timer; + + /* Event for sending discovery packets*/ + /* struct event *discovery_timer; */ + + /* Flag enabling reading discovery packets */ + bool do_discovery; + + /* Flag enabling mapping agent (reading announcements and sending discovery)*/ + /* bool do_mapping; */ + + /* List of RP's in received discovery packets */ + struct pim_autorp_rp_head discovery_rp_list; + + /* List of configured candidate RP's to send in announcement packets */ + struct pim_autorp_rp_head candidate_rp_list; + + /* List of announced RP's to send in discovery packets */ + /* struct pim_autorp_rp_head mapping_rp_list; */ + + /* Packet parameters for sending announcement packets */ + uint8_t announce_scope; + uint16_t announce_interval; + int32_t announce_holdtime; + + /* Pre-built announcement packet, only changes when configured RP's or packet parameters change */ + uint8_t *annouce_pkt; + uint16_t annouce_pkt_sz; + + /* Packet parameters for sending discovery packets */ + /* + int discovery_scope; + int discovery_interval; + int discovery_holdtime; + */ }; #define AUTORP_GRPLEN 6 #define AUTORP_RPLEN 6 #define AUTORP_HDRLEN 8 +int pim_autorp_rm_candidate_rp(struct pim_instance *pim, pim_addr rpaddr); +int pim_autorp_add_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr, + struct prefix group); +int pim_autorp_rm_candidate_rp_group(struct pim_instance *pim, pim_addr rpaddr, + struct prefix group); +int pim_autorp_add_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr, + const char *plist); +int pim_autorp_rm_candidate_rp_plist(struct pim_instance *pim, pim_addr rpaddr, + const char *plist); +int pim_autorp_announce_scope(struct pim_instance *pim, uint8_t scope); +int pim_autorp_announce_interval(struct pim_instance *pim, uint16_t interval); +int pim_autorp_announce_holdtime(struct pim_instance *pim, int32_t holdtime); int pim_autorp_add_ifp(struct interface *ifp); int pim_autorp_rm_ifp(struct interface *ifp); +int pim_autorp_start_discovery(struct pim_instance *pim); +int pim_autorp_stop_discovery(struct pim_instance *pim); int pim_autorp_init(struct pim_instance *pim); -int pim_autorp_start(struct pim_instance *pim); int pim_autorp_finish(struct pim_instance *pim); int pim_autorp_config_write(struct pim_instance *pim, struct vty *vty); +void pim_autorp_show_autorp(struct vty *vty, struct pim_instance *pim, + json_object *json); #endif \ No newline at end of file diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index b4d8db324e90..e24ab927983f 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -2783,6 +2783,75 @@ DEFPY (show_ip_pim_rp_vrf_all, (struct prefix *)group, !!json); } +DEFPY (show_ip_pim_autorp, + show_ip_pim_autorp_cmd, + "show ip pim [vrf NAME] autorp [json$json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM AutoRP information\n" + JSON_STR) +{ + struct vrf *v; + json_object *json_parent = NULL; + + v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME); + if (!v || !v->info) { + if (!json) + vty_out(vty, "%% Unable to find pim instance\n"); + return CMD_WARNING; + } + + if (json) + json_parent = json_object_new_object(); + + pim_autorp_show_autorp(vty, v->info, json_parent); + + if (json) + vty_json(vty, json_parent); + + return CMD_SUCCESS; +} + +DEFPY (show_ip_pim_autorp_vrf_all, + show_ip_pim_autorp_vrf_all_cmd, + "show ip pim vrf all autorp [json$json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "PIM AutoRP information\n" + JSON_STR) +{ + struct vrf *vrf; + json_object *json_parent = NULL; + json_object *json_vrf = NULL; + + if (json) + json_parent = json_object_new_object(); + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + if (vrf->info) { + if (!json) + vty_out(vty, "VRF: %s\n", vrf->name); + else + json_vrf = json_object_new_object(); + + pim_autorp_show_autorp(vty, vrf->info, json_vrf); + + if (json) + json_object_object_add(json_parent, vrf->name, + json_vrf); + } + } + + if (json) + vty_json(vty, json_parent); + + return CMD_SUCCESS; +} + DEFPY (show_ip_pim_rpf, show_ip_pim_rpf_cmd, "show ip pim [vrf NAME] rpf [json$json]", @@ -4379,13 +4448,47 @@ DEFPY_ATTR(no_ip_pim_rp_prefix_list, DEFPY (pim_autorp_discovery, pim_autorp_discovery_cmd, "[no] autorp discovery", - NO_STR + NO_STR "AutoRP\n" - "Enable AutoRP discovery\n") + "Enable AutoRP discovery\n") { if (no) return pim_process_no_autorp_cmd(vty); - return pim_process_autorp_cmd(vty); + else + return pim_process_autorp_cmd(vty); +} + +DEFPY (pim_autorp_announce_rp, + pim_autorp_announce_rp_cmd, + "[no] autorp announce A.B.C.D$rpaddr ![A.B.C.D/M$grp|group-list PREFIX_LIST$plist]", + NO_STR + "AutoRP\n" + "AutoRP Candidate RP announcement\n" + "AutoRP Candidate RP address\n" + "Group prefix\n" + "Prefix list\n" + "List name\n") +{ + return pim_process_autorp_candidate_rp_cmd(vty, no, rpaddr_str, grp, + plist); +} + +DEFPY (pim_autorp_announce_scope_int, + pim_autorp_announce_scope_int_cmd, + "[no] autorp announce ![{scope (1-255) | interval (1-65535) | holdtime (0-65535)}]", + NO_STR + "AutoRP\n" + "AutoRP Candidate RP announcement\n" + "Packet scope (TTL)\n" + "TTL value\n" + "Announcement interval\n" + "Time in seconds\n" + "Announcement holdtime\n" + "Time in seconds\n") +{ + return pim_process_autorp_announce_scope_int_cmd(vty, no, scope_str, + interval_str, + holdtime_str); } DEFPY (pim_ssm_prefix_list, @@ -8542,6 +8645,8 @@ void pim_cmd_init(void) install_element(PIM_NODE, &pim_rp_prefix_list_cmd); install_element(PIM_NODE, &no_pim_rp_prefix_list_cmd); install_element(PIM_NODE, &pim_autorp_discovery_cmd); + install_element(PIM_NODE, &pim_autorp_announce_rp_cmd); + install_element(PIM_NODE, &pim_autorp_announce_scope_int_cmd); install_element(PIM_NODE, &no_pim_ssm_prefix_list_cmd); install_element(PIM_NODE, &no_pim_ssm_prefix_list_name_cmd); install_element(PIM_NODE, &pim_ssm_prefix_list_cmd); @@ -8689,6 +8794,8 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_pim_upstream_rpf_cmd); install_element(VIEW_NODE, &show_ip_pim_rp_cmd); install_element(VIEW_NODE, &show_ip_pim_rp_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_pim_autorp_cmd); + install_element(VIEW_NODE, &show_ip_pim_autorp_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_bsr_cmd); install_element(VIEW_NODE, &show_ip_multicast_cmd); install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd); diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index 6bab162c7c6d..4768f568dfd8 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -599,7 +599,8 @@ int pim_process_autorp_cmd(struct vty *vty) { char xpath[XPATH_MAXLEN]; - snprintf(xpath, sizeof(xpath), "%s", FRR_PIM_AUTORP_XPATH); + snprintf(xpath, sizeof(xpath), "%s/%s", FRR_PIM_AUTORP_XPATH, + "discovery-enabled"); nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, "true"); @@ -610,13 +611,149 @@ int pim_process_no_autorp_cmd(struct vty *vty) { char xpath[XPATH_MAXLEN]; - snprintf(xpath, sizeof(xpath), "%s", FRR_PIM_AUTORP_XPATH); + snprintf(xpath, sizeof(xpath), "%s/%s", FRR_PIM_AUTORP_XPATH, + "discovery-enabled"); nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } +int pim_process_autorp_candidate_rp_cmd(struct vty *vty, bool no, + const char *rpaddr_str, + const struct prefix_ipv4 *grp, + const char *plist) +{ + char xpath[XPATH_MAXLEN]; + char grpstr[64]; + + if (no) { + if (!is_default_prefix((const struct prefix *)grp) || plist) { + /* If any single values are set, only destroy those */ + if (!is_default_prefix((const struct prefix *)grp)) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']/group", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + if (plist) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']/prefix-list", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + } else { + /* No values set, remove the entire RP */ + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } + } else { + if (!is_default_prefix((const struct prefix *)grp) || plist) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (!is_default_prefix((const struct prefix *)grp)) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']/group", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + prefix2str(grp, grpstr, + sizeof(grpstr))); + } + if (plist) { + snprintfrr(xpath, sizeof(xpath), + "%s/candidate-rp-list[rp-address='%s']/prefix-list", + FRR_PIM_AUTORP_XPATH, rpaddr_str); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + plist); + } + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } + + return nb_cli_apply_changes(vty, NULL); +} + +int pim_process_autorp_announce_scope_int_cmd(struct vty *vty, bool no, + const char *scope, + const char *interval, + const char *holdtime) +{ + char xpath[XPATH_MAXLEN]; + + if (no) { + if (scope || interval || holdtime) { + /* If any single values are set, only destroy those */ + if (scope) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-scope"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + if (interval) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-interval"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + if (holdtime) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-holdtime"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, + NULL); + } + } else { + /* No values set, remove all */ + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, "announce-scope"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, "announce-interval"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, "announce-holdtime"); + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + } + } else { + if (scope || interval || holdtime) { + if (scope) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-scope"); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + scope); + } + if (interval) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-interval"); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + interval); + } + if (holdtime) { + snprintfrr(xpath, sizeof(xpath), "%s/%s", + FRR_PIM_AUTORP_XPATH, + "announce-holdtime"); + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, + holdtime); + } + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } + + return nb_cli_apply_changes(vty, NULL); +} + bool pim_sgaddr_match(pim_sgaddr item, pim_sgaddr match) { return (pim_addr_is_any(match.grp) || diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h index b1edf3e00c28..dc511e52bc99 100644 --- a/pimd/pim_cmd_common.h +++ b/pimd/pim_cmd_common.h @@ -35,6 +35,14 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list); int pim_process_autorp_cmd(struct vty *vty); int pim_process_no_autorp_cmd(struct vty *vty); +int pim_process_autorp_candidate_rp_cmd(struct vty *vty, bool no, + const char *rpaddr_str, + const struct prefix_ipv4 *grp, + const char *plist); +int pim_process_autorp_announce_scope_int_cmd(struct vty *vty, bool no, + const char *scope, + const char *interval, + const char *holdtime); int pim_process_ip_pim_cmd(struct vty *vty); int pim_process_no_ip_pim_cmd(struct vty *vty); int pim_process_ip_pim_passive_cmd(struct vty *vty, bool enable); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index ee19c8b5f6fc..60195b84e960 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -1846,7 +1846,8 @@ static int pim_ifp_up(struct interface *ifp) } #if PIM_IPV == 4 - if (pim->autorp && pim->autorp->enable && pim_ifp && pim_ifp->pim_enable) + if (pim->autorp && pim->autorp->do_discovery && pim_ifp && + pim_ifp->pim_enable) pim_autorp_add_ifp(ifp); #endif diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 3afe77eacde7..3b615ef6f505 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -379,15 +379,55 @@ const struct frr_yang_module_info frr_pim_rp_info = { .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy, } }, -#if PIM_IPV == 4 { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/autorp", + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled", .cbs = { - .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_autorp_modify, - .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_autorp_destroy, + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-holdtime", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list", + .cbs = { + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/group", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/prefix-list", + .cbs = { + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy, } }, -#endif { .xpath = NULL, }, diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index a4ce394e5d86..b9658205ba3b 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -158,9 +158,33 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp struct nb_cb_modify_args *args); 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); -int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_autorp_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify( struct nb_cb_modify_args *args); -int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_autorp_destroy( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create( + struct nb_cb_create_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy( + struct nb_cb_destroy_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify( + struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy( struct nb_cb_destroy_args *args); /* frr-gmp prototypes*/ @@ -223,7 +247,7 @@ int routing_control_plane_protocols_name_validate( "mroute[source-addr='%s'][group-addr='%s']" #define FRR_PIM_STATIC_RP_XPATH \ "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']" -#define FRR_PIM_AUTORP_XPATH "./frr-pim-rp:rp/autorp" +#define FRR_PIM_AUTORP_XPATH "./frr-pim-rp:rp/auto-rp" #define FRR_GMP_INTERFACE_XPATH \ "./frr-gmp:gmp/address-family[address-family='%s']" #define FRR_GMP_ENABLE_XPATH \ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index e78c122a2718..d93e6407fc12 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -2677,13 +2677,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp return NB_OK; } -#if PIM_IPV == 4 /* - * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/autorp + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/discovery-enabled */ -int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_autorp_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_modify( struct nb_cb_modify_args *args) { +#if PIM_IPV == 4 struct vrf *vrf; struct pim_instance *pim; bool enabled; @@ -2698,19 +2698,20 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp pim = vrf->info; enabled = yang_dnode_get_bool(args->dnode, NULL); if (enabled) { - if (pim_autorp_start(pim)) + if (pim_autorp_start_discovery(pim)) return NB_ERR; - } else if (pim_autorp_finish(pim)) + } else if (pim_autorp_stop_discovery(pim)) return NB_ERR; return NB_OK; } +#endif return NB_OK; } - -int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_autorp_destroy( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_discovery_enabled_destroy( struct nb_cb_destroy_args *args) { +#if PIM_IPV == 4 struct vrf *vrf; struct pim_instance *pim; bool enabled; @@ -2724,15 +2725,325 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp vrf = nb_running_get_entry(args->dnode, NULL, true); pim = vrf->info; enabled = yang_dnode_get_bool(args->dnode, NULL); - if (enabled && pim_autorp_finish(pim)) + if (enabled && pim_autorp_stop_discovery(pim)) + return NB_ERR; + break; + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-scope + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + uint8_t scope; + + 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; + scope = yang_dnode_get_uint8(args->dnode, NULL); + if (pim_autorp_announce_scope(pim, scope)) + return NB_ERR; + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_scope_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + 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; + if (pim_autorp_announce_scope(pim, 0)) + return NB_ERR; + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-interval + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + uint16_t interval; + + 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; + interval = yang_dnode_get_uint16(args->dnode, NULL); + if (pim_autorp_announce_interval(pim, interval)) return NB_ERR; + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_interval_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + 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; + if (pim_autorp_announce_interval(pim, 0)) + return NB_ERR; + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/announce-holdtime + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + uint16_t holdtime; + + 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; + holdtime = yang_dnode_get_uint16(args->dnode, NULL); + if (pim_autorp_announce_holdtime(pim, holdtime)) + return NB_ERR; } +#endif return NB_OK; } +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_announce_holdtime_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + 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; + if (pim_autorp_announce_holdtime(pim, + -1)) /* 0 is a valid value, so -1 indicates deleting (go back to default) */ + return NB_ERR; + } #endif + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_create( + struct nb_cb_create_args *args) +{ +#if PIM_IPV == 4 + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + pim_addr 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_pimaddr(&rp_addr, args->dnode, "rp-address"); + if (pim_autorp_rm_candidate_rp(pim, rp_addr)) + return NB_ERR_INCONSISTENCY; + break; + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/group + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + pim_addr 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_pimaddr(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_prefix(&group, args->dnode, NULL); + apply_mask(&group); + if (pim_autorp_add_candidate_rp_group(pim, rp_addr, group)) + return NB_ERR; + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_group_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + struct prefix group; + pim_addr 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_pimaddr(&rp_addr, args->dnode, "../rp-address"); + yang_dnode_get_prefix(&group, args->dnode, NULL); + apply_mask(&group); + if (pim_autorp_rm_candidate_rp_group(pim, rp_addr, group)) + return NB_ERR; + } +#endif + + return NB_OK; +} + +/* + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/frr-pim-rp:rp/auto-rp/candidate-rp-list/prefix-list + */ +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_modify( + struct nb_cb_modify_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + pim_addr 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_pimaddr(&rp_addr, args->dnode, "../rp-address"); + if (pim_autorp_add_candidate_rp_plist(pim, rp_addr, plist)) + return NB_ERR; + } +#endif + + return NB_OK; +} +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_auto_rp_candidate_rp_list_prefix_list_destroy( + struct nb_cb_destroy_args *args) +{ +#if PIM_IPV == 4 + struct vrf *vrf; + struct pim_instance *pim; + pim_addr 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_pimaddr(&rp_addr, args->dnode, "../rp-address"); + plist = yang_dnode_get_string(args->dnode, NULL); + if (pim_autorp_rm_candidate_rp_plist(pim, rp_addr, plist)) + return NB_ERR; + break; + } +#endif + + return NB_OK; +} + /* * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family */ diff --git a/yang/frr-pim-rp.yang b/yang/frr-pim-rp.yang index 5ee73c3e2d83..dbd5513ee57b 100644 --- a/yang/frr-pim-rp.yang +++ b/yang/frr-pim-rp.yang @@ -111,6 +111,70 @@ module frr-pim-rp { } // static-rp } // static-rp-container + grouping auto-rp-container { + description + "Grouping of AutoRP container."; + + container auto-rp { + description + "Containing AutoRP attributes."; + + leaf discovery-enabled { + type boolean; + description + "Flag indicating if Auto RP discovery is enabled."; + } + + leaf announce-scope { + type uint8; + description + "The TTL of the C-RP Announcement packet."; + } + + leaf announce-interval { + type uint16; + description + "The time between sending C-RP announcement packets."; + } + + leaf announce-holdtime { + type uint16; + description + "The hold time in seconds advertised in the announcement packet."; + } + + list candidate-rp-list { + key "rp-address"; + description + "A list of Candidate RP addresses."; + + leaf rp-address { + type inet:ip-address; + description + "Specifies a candidate RP address."; + } + + choice group-or-prefix-list { + description "Use group or prefix-list"; + case group { + leaf group { + type frr-route-types:ip-multicast-group-prefix; + description + "Multicast group prefix."; + } + } + case prefix-list { + leaf prefix-list { + type plist-ref; + description + "Group prefix-list filter"; + } + } + } + } // candidate-rp-list + } // auto-rp + } // auto-rp-container + /* * Configuration data nodes */ @@ -124,14 +188,11 @@ module frr-pim-rp { "PIM RP configuration data."; uses static-rp-container; - leaf autorp { - when "../../frr-pim:address-family = 'frr-rt:ipv4'" { + uses auto-rp-container { + when "../frr-pim:address-family = 'frr-rt:ipv4'" { description "Only applicable to IPv4 address family."; } - type boolean; - description - "Flag indicating if Auto RP discovery is enabled."; } } // rp } // augment