mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
pimd: Implement rpf lookup mode as a list
Add the support to store lookup modes as a sorted list. List is non-unique and sorts mode with both lists < modes with one list < global mode (no lists). This way, when finding the right mode, we will match a lookup using a prefix list before the global mode. Add passing group address into all lookups (using nht cache and/or synchronous lookup). Many areas don't have a group address, use PIMADDR_ANY if no valid group is needed. Signed-off-by: Nathan Bahr <nbahr@atcorp.com>
This commit is contained in:
parent
8b00575fbb
commit
e8d81ab5ce
|
@ -417,7 +417,7 @@ void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
|
||||||
rp = bsr_crp_rps_find(scope->ebsr_rps, &ref);
|
rp = bsr_crp_rps_find(scope->ebsr_rps, &ref);
|
||||||
assertf(rp, "addr=%pPA", &ref.addr);
|
assertf(rp, "addr=%pPA", &ref.addr);
|
||||||
|
|
||||||
ok = pim_nht_pnc_is_valid(pim, pnc);
|
ok = pim_nht_pnc_is_valid(pim, pnc, PIMADDR_ANY);
|
||||||
if (ok == rp->nht_ok)
|
if (ok == rp->nht_ok)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
@ -3296,7 +3296,7 @@ DEFUN (show_ip_rib,
|
||||||
return CMD_WARNING;
|
return CMD_WARNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pim_nht_lookup(vrf->info, &nexthop, addr, 0)) {
|
if (!pim_nht_lookup(vrf->info, &nexthop, addr, PIMADDR_ANY, false)) {
|
||||||
vty_out(vty,
|
vty_out(vty,
|
||||||
"Failure querying RIB nexthop for unicast address %s\n",
|
"Failure querying RIB nexthop for unicast address %s\n",
|
||||||
addr_str);
|
addr_str);
|
||||||
|
|
|
@ -59,7 +59,8 @@ static bool mtrace_fwd_info_weak(struct pim_instance *pim,
|
||||||
|
|
||||||
memset(&nexthop, 0, sizeof(nexthop));
|
memset(&nexthop, 0, sizeof(nexthop));
|
||||||
|
|
||||||
if (!pim_nht_lookup(pim, &nexthop, mtracep->src_addr, 1)) {
|
/* TODO Is there any valid group address to use for lookup? */
|
||||||
|
if (!pim_nht_lookup(pim, &nexthop, mtracep->src_addr, PIMADDR_ANY, true)) {
|
||||||
if (PIM_DEBUG_MTRACE)
|
if (PIM_DEBUG_MTRACE)
|
||||||
zlog_debug("mtrace not found neighbor");
|
zlog_debug("mtrace not found neighbor");
|
||||||
return false;
|
return false;
|
||||||
|
@ -354,7 +355,8 @@ static int mtrace_un_forward_packet(struct pim_instance *pim, struct ip *ip_hdr,
|
||||||
|
|
||||||
if (interface == NULL) {
|
if (interface == NULL) {
|
||||||
memset(&nexthop, 0, sizeof(nexthop));
|
memset(&nexthop, 0, sizeof(nexthop));
|
||||||
if (!pim_nht_lookup(pim, &nexthop, ip_hdr->ip_dst, 0)) {
|
/* TODO Is there any valid group address to use for lookup? */
|
||||||
|
if (!pim_nht_lookup(pim, &nexthop, ip_hdr->ip_dst, PIMADDR_ANY, false)) {
|
||||||
if (PIM_DEBUG_MTRACE)
|
if (PIM_DEBUG_MTRACE)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"Dropping mtrace packet, no route to destination");
|
"Dropping mtrace packet, no route to destination");
|
||||||
|
@ -535,8 +537,11 @@ static int mtrace_send_response(struct pim_instance *pim,
|
||||||
zlog_debug("mtrace response to RP");
|
zlog_debug("mtrace response to RP");
|
||||||
} else {
|
} else {
|
||||||
memset(&nexthop, 0, sizeof(nexthop));
|
memset(&nexthop, 0, sizeof(nexthop));
|
||||||
/* TODO: should use unicast rib lookup */
|
/* TODO: should use unicast rib lookup
|
||||||
if (!pim_nht_lookup(pim, &nexthop, mtracep->rsp_addr, 1)) {
|
* NEB 10/30/24 - Not sure why this needs the unicast rib...right now it will look up per the rpf mode
|
||||||
|
* Are any of the igmp_mtrace addresses a valid group address to use for lookups??
|
||||||
|
*/
|
||||||
|
if (!pim_nht_lookup(pim, &nexthop, mtracep->rsp_addr, PIMADDR_ANY, true)) {
|
||||||
if (PIM_DEBUG_MTRACE)
|
if (PIM_DEBUG_MTRACE)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
"Dropped response qid=%ud, no route to response address",
|
"Dropped response qid=%ud, no route to response address",
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "pim_upstream.h"
|
#include "pim_upstream.h"
|
||||||
#include "pim_mroute.h"
|
#include "pim_mroute.h"
|
||||||
#include "pim_autorp.h"
|
#include "pim_autorp.h"
|
||||||
|
#include "pim_nht.h"
|
||||||
|
|
||||||
enum pim_spt_switchover {
|
enum pim_spt_switchover {
|
||||||
PIM_SPT_IMMEDIATE,
|
PIM_SPT_IMMEDIATE,
|
||||||
|
@ -116,7 +117,7 @@ struct pim_instance {
|
||||||
char *register_plist;
|
char *register_plist;
|
||||||
|
|
||||||
struct hash *nht_hash;
|
struct hash *nht_hash;
|
||||||
enum pim_rpf_lookup_mode rpf_mode;
|
struct pim_lookup_mode_head rpf_mode;
|
||||||
|
|
||||||
void *ssm_info; /* per-vrf SSM configuration */
|
void *ssm_info; /* per-vrf SSM configuration */
|
||||||
|
|
||||||
|
|
|
@ -567,7 +567,8 @@ int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf,
|
||||||
* setting the SPTBIT to true
|
* setting the SPTBIT to true
|
||||||
*/
|
*/
|
||||||
if (!(pim_addr_is_any(up->upstream_register)) &&
|
if (!(pim_addr_is_any(up->upstream_register)) &&
|
||||||
pim_nht_lookup(pim_ifp->pim, &source, up->upstream_register, 0)) {
|
pim_nht_lookup(pim_ifp->pim, &source, up->upstream_register, up->sg.grp,
|
||||||
|
false)) {
|
||||||
pim_register_stop_send(source.interface, &sg,
|
pim_register_stop_send(source.interface, &sg,
|
||||||
pim_ifp->primary_address,
|
pim_ifp->primary_address,
|
||||||
up->upstream_register);
|
up->upstream_register);
|
||||||
|
@ -580,7 +581,8 @@ int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, const char *buf,
|
||||||
__func__);
|
__func__);
|
||||||
} else {
|
} else {
|
||||||
if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
|
if (I_am_RP(pim_ifp->pim, up->sg.grp)) {
|
||||||
if (pim_nht_lookup(pim_ifp->pim, &source, up->upstream_register, 0))
|
if (pim_nht_lookup(pim_ifp->pim, &source, up->upstream_register,
|
||||||
|
up->sg.grp, false))
|
||||||
pim_register_stop_send(
|
pim_register_stop_send(
|
||||||
source.interface, &sg,
|
source.interface, &sg,
|
||||||
pim_ifp->primary_address,
|
pim_ifp->primary_address,
|
||||||
|
|
|
@ -706,7 +706,7 @@ bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if the MSDP peer is the nexthop for the RP */
|
/* check if the MSDP peer is the nexthop for the RP */
|
||||||
if (pim_nht_lookup(mp->pim, &nexthop, rp, 0) &&
|
if (pim_nht_lookup(mp->pim, &nexthop, rp, PIMADDR_ANY, false) &&
|
||||||
nexthop.mrib_nexthop_addr.s_addr == mp->peer.s_addr) {
|
nexthop.mrib_nexthop_addr.s_addr == mp->peer.s_addr) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
413
pimd/pim_nht.c
413
pimd/pim_nht.c
|
@ -34,6 +34,176 @@
|
||||||
#include "pim_register.h"
|
#include "pim_register.h"
|
||||||
#include "pim_vxlan.h"
|
#include "pim_vxlan.h"
|
||||||
|
|
||||||
|
DEFINE_MTYPE_STATIC(PIMD, PIM_LOOKUP_MODE, "PIM RPF lookup mode");
|
||||||
|
DEFINE_MTYPE_STATIC(PIMD, PIM_LOOKUP_MODE_STR, "PIM RPF lookup mode prefix list string");
|
||||||
|
|
||||||
|
static void pim_update_rp_nh(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
|
||||||
|
static int pim_update_upstream_nh(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
|
||||||
|
|
||||||
|
static int pim_lookup_mode_cmp(const struct pim_lookup_mode *l, const struct pim_lookup_mode *r)
|
||||||
|
{
|
||||||
|
/* Let's just sort anything with both lists set above those with only one list set,
|
||||||
|
* which is above the global where neither are set
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Both are set on right, either lower or equal */
|
||||||
|
if (l->grp_plist != NULL && l->src_plist != NULL)
|
||||||
|
return (r->grp_plist == NULL || r->src_plist == NULL) ? -1 : 0;
|
||||||
|
|
||||||
|
/* Only one set on the left */
|
||||||
|
if (!(l->grp_plist == NULL && l->src_plist == NULL)) {
|
||||||
|
/* Lower only if both are not set on right */
|
||||||
|
if (r->grp_plist == NULL && r->src_plist == NULL)
|
||||||
|
return -1;
|
||||||
|
/* Higher only if both are set on right */
|
||||||
|
if (r->grp_plist != NULL && r->src_plist != NULL)
|
||||||
|
return 1;
|
||||||
|
/* Otherwise both sides have at least one set, so equal */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Neither set on left, so equal if neither set on right also */
|
||||||
|
if (r->grp_plist == NULL && r->src_plist == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Otherwise higher */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
DECLARE_SORTLIST_NONUNIQ(pim_lookup_mode, struct pim_lookup_mode, list, pim_lookup_mode_cmp);
|
||||||
|
|
||||||
|
static void pim_lookup_mode_free(struct pim_lookup_mode *m)
|
||||||
|
{
|
||||||
|
if (m->grp_plist)
|
||||||
|
XFREE(MTYPE_PIM_LOOKUP_MODE_STR, m->grp_plist);
|
||||||
|
if (m->src_plist)
|
||||||
|
XFREE(MTYPE_PIM_LOOKUP_MODE_STR, m->src_plist);
|
||||||
|
XFREE(MTYPE_PIM_LOOKUP_MODE, m);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_lookup_mode_list_free(struct pim_lookup_mode_head *head)
|
||||||
|
{
|
||||||
|
struct pim_lookup_mode *m;
|
||||||
|
|
||||||
|
while ((m = pim_lookup_mode_pop(head)))
|
||||||
|
pim_lookup_mode_free(m);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum pim_rpf_lookup_mode pim_get_lookup_mode(struct pim_instance *pim, pim_addr group,
|
||||||
|
pim_addr source)
|
||||||
|
{
|
||||||
|
struct pim_lookup_mode *m;
|
||||||
|
struct prefix_list *plist;
|
||||||
|
struct prefix p;
|
||||||
|
|
||||||
|
frr_each_safe (pim_lookup_mode, &(pim->rpf_mode), m) {
|
||||||
|
if (!pim_addr_is_any(group) && m->grp_plist) {
|
||||||
|
/* Match group against plist, continue if no match */
|
||||||
|
plist = prefix_list_lookup(PIM_AFI, m->grp_plist);
|
||||||
|
if (plist == NULL)
|
||||||
|
continue;
|
||||||
|
pim_addr_to_prefix(&p, group);
|
||||||
|
if (prefix_list_apply(plist, &p) == PREFIX_DENY)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pim_addr_is_any(source) && m->src_plist) {
|
||||||
|
/* Match source against plist, continue if no match */
|
||||||
|
plist = prefix_list_lookup(PIM_AFI, m->src_plist);
|
||||||
|
if (plist == NULL)
|
||||||
|
continue;
|
||||||
|
pim_addr_to_prefix(&p, source);
|
||||||
|
if (prefix_list_apply(plist, &p) == PREFIX_DENY)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If lookup mode has a group list, but no group is provided, don't match it */
|
||||||
|
if (pim_addr_is_any(group) && m->grp_plist)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If lookup mode has a source list, but no source is provided, don't match it */
|
||||||
|
if (pim_addr_is_any(source) && m->src_plist)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* Match found */
|
||||||
|
return m->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This shouldn't happen since we have the global mode, but if it's gone,
|
||||||
|
* just return the default of no config
|
||||||
|
*/
|
||||||
|
if (PIM_DEBUG_PIM_NHT)
|
||||||
|
zlog_debug("%s: No RPF lookup matched for given group %pPA and source %pPA",
|
||||||
|
__func__, &group, &source);
|
||||||
|
|
||||||
|
return MCAST_NO_CONFIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool pim_rpf_mode_changed(enum pim_rpf_lookup_mode old, enum pim_rpf_lookup_mode new)
|
||||||
|
{
|
||||||
|
if (old != new) {
|
||||||
|
/* These two are equivalent, so don't update in that case */
|
||||||
|
if (old == MCAST_NO_CONFIG && new == MCAST_MIX_MRIB_FIRST)
|
||||||
|
return false;
|
||||||
|
if (old == MCAST_MIX_MRIB_FIRST && new == MCAST_NO_CONFIG)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct pnc_mode_update_hash_walk_data {
|
||||||
|
struct pim_instance *pim;
|
||||||
|
struct prefix_list *grp_plist;
|
||||||
|
struct prefix_list *src_plist;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pim_nht_hash_mode_update_helper(struct hash_bucket *bucket, void *arg)
|
||||||
|
{
|
||||||
|
struct pim_nexthop_cache *pnc = bucket->data;
|
||||||
|
struct pnc_mode_update_hash_walk_data *pwd = arg;
|
||||||
|
struct pim_instance *pim = pwd->pim;
|
||||||
|
struct prefix p;
|
||||||
|
|
||||||
|
pim_addr_to_prefix(&p, pnc->addr);
|
||||||
|
|
||||||
|
/* Make sure this pnc entry matches the prefix lists */
|
||||||
|
/* TODO: For now, pnc only has the source address, so we can only check that */
|
||||||
|
if (pwd->src_plist &&
|
||||||
|
(pim_addr_is_any(pnc->addr) || prefix_list_apply(pwd->src_plist, &p) == PREFIX_DENY))
|
||||||
|
return HASHWALK_CONTINUE;
|
||||||
|
|
||||||
|
/* Otherwise the address is any, or matches the prefix list, or no prefix list to match, so do the updates */
|
||||||
|
/* TODO for RP, there are groups....but I don't think we'd want to use those */
|
||||||
|
if (listcount(pnc->rp_list))
|
||||||
|
pim_update_rp_nh(pim, pnc);
|
||||||
|
|
||||||
|
/* TODO for upstream, there is an S,G key...can/should we use that group?? */
|
||||||
|
if (pnc->upstream_hash->count)
|
||||||
|
pim_update_upstream_nh(pim, pnc);
|
||||||
|
|
||||||
|
if (pnc->candrp_count)
|
||||||
|
pim_crp_nht_update(pim, pnc);
|
||||||
|
|
||||||
|
return HASHWALK_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pim_rpf_mode_changed_update(struct pim_instance *pim, const char *group_plist,
|
||||||
|
const char *source_plist)
|
||||||
|
{
|
||||||
|
struct pnc_mode_update_hash_walk_data pwd;
|
||||||
|
|
||||||
|
/* Update the refresh time to force new lookups if needed */
|
||||||
|
pim_rpf_set_refresh_time(pim);
|
||||||
|
|
||||||
|
/* Force update the registered RP and upstreams for all cache entries */
|
||||||
|
pwd.pim = pim;
|
||||||
|
pwd.grp_plist = prefix_list_lookup(PIM_AFI, group_plist);
|
||||||
|
pwd.src_plist = prefix_list_lookup(PIM_AFI, source_plist);
|
||||||
|
|
||||||
|
hash_walk(pim->nht_hash, pim_nht_hash_mode_update_helper, &pwd);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
|
* pim_sendmsg_zebra_rnh -- Format and send a nexthop register/Unregister
|
||||||
* command to Zebra.
|
* command to Zebra.
|
||||||
|
@ -106,9 +276,10 @@ static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim,
|
||||||
return pnc;
|
return pnc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pim_nht_pnc_has_answer(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
|
static bool pim_nht_pnc_has_answer(struct pim_instance *pim, struct pim_nexthop_cache *pnc,
|
||||||
|
pim_addr group)
|
||||||
{
|
{
|
||||||
switch (pim->rpf_mode) {
|
switch (pim_get_lookup_mode(pim, group, pnc->addr)) {
|
||||||
case MCAST_MRIB_ONLY:
|
case MCAST_MRIB_ONLY:
|
||||||
return CHECK_FLAG(pnc->mrib.flags, PIM_NEXTHOP_ANSWER_RECEIVED);
|
return CHECK_FLAG(pnc->mrib.flags, PIM_NEXTHOP_ANSWER_RECEIVED);
|
||||||
|
|
||||||
|
@ -133,25 +304,28 @@ static bool pim_nht_pnc_has_answer(struct pim_instance *pim, struct pim_nexthop_
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct pim_nexthop_cache_rib *pim_pnc_get_rib(struct pim_instance *pim,
|
static struct pim_nexthop_cache_rib *pim_pnc_get_rib(struct pim_instance *pim,
|
||||||
struct pim_nexthop_cache *pnc)
|
struct pim_nexthop_cache *pnc, pim_addr group)
|
||||||
{
|
{
|
||||||
struct pim_nexthop_cache_rib *pnc_rib = NULL;
|
struct pim_nexthop_cache_rib *pnc_rib = NULL;
|
||||||
|
enum pim_rpf_lookup_mode mode;
|
||||||
|
|
||||||
if (pim->rpf_mode == MCAST_MRIB_ONLY)
|
mode = pim_get_lookup_mode(pim, group, pnc->addr);
|
||||||
|
|
||||||
|
if (mode == MCAST_MRIB_ONLY)
|
||||||
pnc_rib = &pnc->mrib;
|
pnc_rib = &pnc->mrib;
|
||||||
else if (pim->rpf_mode == MCAST_URIB_ONLY)
|
else if (mode == MCAST_URIB_ONLY)
|
||||||
pnc_rib = &pnc->urib;
|
pnc_rib = &pnc->urib;
|
||||||
else if (pim->rpf_mode == MCAST_MIX_MRIB_FIRST || pim->rpf_mode == MCAST_NO_CONFIG) {
|
else if (mode == MCAST_MIX_MRIB_FIRST || mode == MCAST_NO_CONFIG) {
|
||||||
if (pnc->mrib.nexthop_num > 0)
|
if (pnc->mrib.nexthop_num > 0)
|
||||||
pnc_rib = &pnc->mrib;
|
pnc_rib = &pnc->mrib;
|
||||||
else
|
else
|
||||||
pnc_rib = &pnc->urib;
|
pnc_rib = &pnc->urib;
|
||||||
} else if (pim->rpf_mode == MCAST_MIX_DISTANCE) {
|
} else if (mode == MCAST_MIX_DISTANCE) {
|
||||||
if (pnc->mrib.distance <= pnc->urib.distance)
|
if (pnc->mrib.distance <= pnc->urib.distance)
|
||||||
pnc_rib = &pnc->mrib;
|
pnc_rib = &pnc->mrib;
|
||||||
else
|
else
|
||||||
pnc_rib = &pnc->urib;
|
pnc_rib = &pnc->urib;
|
||||||
} else if (pim->rpf_mode == MCAST_MIX_PFXLEN) {
|
} else if (mode == MCAST_MIX_PFXLEN) {
|
||||||
if (pnc->mrib.prefix_len >= pnc->urib.prefix_len)
|
if (pnc->mrib.prefix_len >= pnc->urib.prefix_len)
|
||||||
pnc_rib = &pnc->mrib;
|
pnc_rib = &pnc->mrib;
|
||||||
else
|
else
|
||||||
|
@ -161,23 +335,151 @@ static struct pim_nexthop_cache_rib *pim_pnc_get_rib(struct pim_instance *pim,
|
||||||
return pnc_rib;
|
return pnc_rib;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void pim_nht_change_rpf_mode(struct pim_instance *pim, const char *group_plist,
|
void pim_nht_change_rpf_mode(struct pim_instance *pim, const char *group_plist,
|
||||||
const char *source_plist, enum pim_rpf_lookup_mode mode)
|
const char *source_plist, enum pim_rpf_lookup_mode mode)
|
||||||
{
|
{
|
||||||
/* TODO */
|
struct pim_lookup_mode *m;
|
||||||
}
|
bool found = false;
|
||||||
|
bool update = false;
|
||||||
|
const char *glist = NULL;
|
||||||
|
const char *slist = NULL;
|
||||||
|
|
||||||
|
/* Prefix lists may be passed in as empty string, leave them NULL instead */
|
||||||
|
if (group_plist && strlen(group_plist))
|
||||||
|
glist = group_plist;
|
||||||
|
if (source_plist && strlen(source_plist))
|
||||||
|
slist = source_plist;
|
||||||
|
|
||||||
|
frr_each_safe (pim_lookup_mode, &(pim->rpf_mode), m) {
|
||||||
|
if ((m->grp_plist && glist && strmatch(m->grp_plist, glist)) &&
|
||||||
|
(m->src_plist && slist && strmatch(m->src_plist, slist))) {
|
||||||
|
/* Group and source plists are both set and matched */
|
||||||
|
found = true;
|
||||||
|
if (mode == MCAST_NO_CONFIG) {
|
||||||
|
/* MCAST_NO_CONFIG means we should remove this lookup mode
|
||||||
|
* We don't know what other modes might match, or if only the global, so we need to
|
||||||
|
* update all lookups
|
||||||
|
*/
|
||||||
|
pim_lookup_mode_del(&pim->rpf_mode, m);
|
||||||
|
pim_lookup_mode_free(m);
|
||||||
|
glist = NULL;
|
||||||
|
slist = NULL;
|
||||||
|
update = true;
|
||||||
|
} else {
|
||||||
|
/* Just changing mode */
|
||||||
|
update = pim_rpf_mode_changed(m->mode, mode);
|
||||||
|
m->mode = mode; /* Always make sure the mode is set, even if not updating */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update)
|
||||||
|
pim_rpf_mode_changed_update(pim, glist, slist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((m->grp_plist && glist && strmatch(m->grp_plist, glist)) &&
|
||||||
|
(!m->src_plist && !slist)) {
|
||||||
|
/* Only group list set and matched */
|
||||||
|
found = true;
|
||||||
|
if (mode == MCAST_NO_CONFIG) {
|
||||||
|
/* MCAST_NO_CONFIG means we should remove this lookup mode
|
||||||
|
* We don't know what other modes might match, or if only the global, so we need to
|
||||||
|
* update all lookups
|
||||||
|
*/
|
||||||
|
pim_lookup_mode_del(&pim->rpf_mode, m);
|
||||||
|
pim_lookup_mode_free(m);
|
||||||
|
glist = NULL;
|
||||||
|
slist = NULL;
|
||||||
|
update = true;
|
||||||
|
} else {
|
||||||
|
/* Just changing mode */
|
||||||
|
update = pim_rpf_mode_changed(m->mode, mode);
|
||||||
|
m->mode = mode; /* Always make sure the mode is set, even if not updating */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update)
|
||||||
|
pim_rpf_mode_changed_update(pim, glist, slist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!m->grp_plist && !glist) &&
|
||||||
|
(m->src_plist && slist && strmatch(m->src_plist, slist))) {
|
||||||
|
/* Only source list set and matched */
|
||||||
|
found = true;
|
||||||
|
if (mode == MCAST_NO_CONFIG) {
|
||||||
|
/* MCAST_NO_CONFIG means we should remove this lookup mode
|
||||||
|
* We don't know what other modes might match, or if only the global, so we need to
|
||||||
|
* update all lookups
|
||||||
|
*/
|
||||||
|
pim_lookup_mode_del(&pim->rpf_mode, m);
|
||||||
|
pim_lookup_mode_free(m);
|
||||||
|
glist = NULL;
|
||||||
|
slist = NULL;
|
||||||
|
update = true;
|
||||||
|
} else {
|
||||||
|
/* Just changing mode */
|
||||||
|
update = pim_rpf_mode_changed(m->mode, mode);
|
||||||
|
m->mode = mode; /* Always make sure the mode is set, even if not updating */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (update)
|
||||||
|
pim_rpf_mode_changed_update(pim, glist, slist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m->grp_plist && !glist && !m->src_plist && !slist) {
|
||||||
|
/* No prefix lists set, so this is the global mode */
|
||||||
|
/* We never delete this mode, even when set back to MCAST_NO_CONFIG */
|
||||||
|
update = pim_rpf_mode_changed(m->mode, mode);
|
||||||
|
m->mode = mode; /* Always make sure the mode is set, even if not updating */
|
||||||
|
if (update)
|
||||||
|
pim_rpf_mode_changed_update(pim, glist, slist);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
/* Adding a new lookup mode with unique prefix lists, add it */
|
||||||
|
m = XCALLOC(MTYPE_PIM_LOOKUP_MODE, sizeof(struct pim_lookup_mode));
|
||||||
|
m->grp_plist = XSTRDUP(MTYPE_PIM_LOOKUP_MODE_STR, glist);
|
||||||
|
m->src_plist = XSTRDUP(MTYPE_PIM_LOOKUP_MODE_STR, slist);
|
||||||
|
m->mode = mode;
|
||||||
|
pim_lookup_mode_add(&(pim->rpf_mode), m);
|
||||||
|
pim_rpf_mode_changed_update(pim, glist, slist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int pim_lookup_mode_write(struct pim_instance *pim, struct vty *vty)
|
int pim_lookup_mode_write(struct pim_instance *pim, struct vty *vty)
|
||||||
{
|
{
|
||||||
/* TODO */
|
int writes = 0;
|
||||||
return 0;
|
struct pim_lookup_mode *m;
|
||||||
|
|
||||||
|
frr_each_safe (pim_lookup_mode, &(pim->rpf_mode), m) {
|
||||||
|
if (m->mode == MCAST_NO_CONFIG)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
++writes;
|
||||||
|
vty_out(vty, " rpf-lookup-mode %s",
|
||||||
|
m->mode == MCAST_URIB_ONLY ? "urib-only"
|
||||||
|
: m->mode == MCAST_MRIB_ONLY ? "mrib-only"
|
||||||
|
: m->mode == MCAST_MIX_MRIB_FIRST ? "mrib-then-urib"
|
||||||
|
: m->mode == MCAST_MIX_DISTANCE ? "lower-distance"
|
||||||
|
: "longer-prefix");
|
||||||
|
|
||||||
|
if (m->grp_plist)
|
||||||
|
vty_out(vty, " group-list %s", m->grp_plist);
|
||||||
|
|
||||||
|
if (m->src_plist)
|
||||||
|
vty_out(vty, " source-list %s", m->src_plist);
|
||||||
|
|
||||||
|
vty_out(vty, "\n");
|
||||||
|
}
|
||||||
|
return writes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pim_nht_pnc_is_valid(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
|
bool pim_nht_pnc_is_valid(struct pim_instance *pim, struct pim_nexthop_cache *pnc, pim_addr group)
|
||||||
{
|
{
|
||||||
switch (pim->rpf_mode) {
|
switch (pim_get_lookup_mode(pim, group, pnc->addr)) {
|
||||||
case MCAST_MRIB_ONLY:
|
case MCAST_MRIB_ONLY:
|
||||||
return CHECK_FLAG(pnc->mrib.flags, PIM_NEXTHOP_VALID);
|
return CHECK_FLAG(pnc->mrib.flags, PIM_NEXTHOP_VALID);
|
||||||
|
|
||||||
|
@ -289,6 +591,7 @@ bool pim_nht_find_or_track(struct pim_instance *pim, pim_addr addr, struct pim_u
|
||||||
{
|
{
|
||||||
struct pim_nexthop_cache *pnc;
|
struct pim_nexthop_cache *pnc;
|
||||||
struct listnode *ch_node = NULL;
|
struct listnode *ch_node = NULL;
|
||||||
|
pim_addr group = PIMADDR_ANY;
|
||||||
|
|
||||||
/* This will find the entry and add it to tracking if not found */
|
/* This will find the entry and add it to tracking if not found */
|
||||||
pnc = pim_nht_get(pim, addr);
|
pnc = pim_nht_get(pim, addr);
|
||||||
|
@ -303,10 +606,12 @@ bool pim_nht_find_or_track(struct pim_instance *pim, pim_addr addr, struct pim_u
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store the upstream if provided and not currently in the list */
|
/* Store the upstream if provided and not currently in the list */
|
||||||
if (up != NULL)
|
if (up != NULL) {
|
||||||
(void)hash_get(pnc->upstream_hash, up, hash_alloc_intern);
|
(void)hash_get(pnc->upstream_hash, up, hash_alloc_intern);
|
||||||
|
group = up->sg.grp;
|
||||||
|
}
|
||||||
|
|
||||||
if (pim_nht_pnc_is_valid(pim, pnc)) {
|
if (pim_nht_pnc_is_valid(pim, pnc, group)) {
|
||||||
if (out_pnc)
|
if (out_pnc)
|
||||||
memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache));
|
memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache));
|
||||||
return true;
|
return true;
|
||||||
|
@ -329,7 +634,7 @@ bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr)
|
||||||
|
|
||||||
pnc = pim_nht_get(pim, addr);
|
pnc = pim_nht_get(pim, addr);
|
||||||
pnc->candrp_count++;
|
pnc->candrp_count++;
|
||||||
return pim_nht_pnc_is_valid(pim, pnc);
|
return pim_nht_pnc_is_valid(pim, pnc, PIMADDR_ANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
|
static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc)
|
||||||
|
@ -462,7 +767,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
|
||||||
lookup.addr = bsr_addr;
|
lookup.addr = bsr_addr;
|
||||||
|
|
||||||
pnc = hash_lookup(pim->nht_hash, &lookup);
|
pnc = hash_lookup(pim->nht_hash, &lookup);
|
||||||
if (!pnc || !pim_nht_pnc_has_answer(pim, pnc)) {
|
if (!pnc || !pim_nht_pnc_has_answer(pim, pnc, PIMADDR_ANY)) {
|
||||||
/* BSM from a new freshly registered BSR - do a synchronous
|
/* BSM from a new freshly registered BSR - do a synchronous
|
||||||
* zebra query since otherwise we'd drop the first packet,
|
* zebra query since otherwise we'd drop the first packet,
|
||||||
* leading to additional delay in picking up BSM data
|
* leading to additional delay in picking up BSM data
|
||||||
|
@ -479,9 +784,8 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
|
||||||
int num_ifindex;
|
int num_ifindex;
|
||||||
|
|
||||||
memset(nexthop_tab, 0, sizeof(nexthop_tab));
|
memset(nexthop_tab, 0, sizeof(nexthop_tab));
|
||||||
num_ifindex = zclient_lookup_nexthop(
|
num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, bsr_addr,
|
||||||
pim, nexthop_tab, router->multipath, bsr_addr,
|
PIMADDR_ANY, PIM_NEXTHOP_LOOKUP_MAX);
|
||||||
PIM_NEXTHOP_LOOKUP_MAX);
|
|
||||||
|
|
||||||
if (num_ifindex <= 0)
|
if (num_ifindex <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
@ -521,7 +825,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pim_nht_pnc_is_valid(pim, pnc)) {
|
if (pim_nht_pnc_is_valid(pim, pnc, PIMADDR_ANY)) {
|
||||||
/* if we accept BSMs from more than one ECMP nexthop, this will cause
|
/* if we accept BSMs from more than one ECMP nexthop, this will cause
|
||||||
* BSM message "multiplication" for each ECMP hop. i.e. if you have
|
* BSM message "multiplication" for each ECMP hop. i.e. if you have
|
||||||
* 4-way ECMP and 4 hops you end up with 256 copies of each BSM
|
* 4-way ECMP and 4 hops you end up with 256 copies of each BSM
|
||||||
|
@ -529,7 +833,7 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
|
||||||
*
|
*
|
||||||
* so... only accept the first (IPv4) valid nexthop as source.
|
* so... only accept the first (IPv4) valid nexthop as source.
|
||||||
*/
|
*/
|
||||||
struct pim_nexthop_cache_rib *rib = pim_pnc_get_rib(pim, pnc);
|
struct pim_nexthop_cache_rib *rib = pim_pnc_get_rib(pim, pnc, PIMADDR_ANY);
|
||||||
|
|
||||||
for (nh = rib->nexthop; nh; nh = nh->next) {
|
for (nh = rib->nexthop; nh; nh = nh->next) {
|
||||||
pim_addr nhaddr;
|
pim_addr nhaddr;
|
||||||
|
@ -768,14 +1072,17 @@ static bool pim_ecmp_nexthop_search(struct pim_instance *pim, struct pim_nexthop
|
||||||
pim_addr nh_addr;
|
pim_addr nh_addr;
|
||||||
pim_addr grp_addr;
|
pim_addr grp_addr;
|
||||||
struct pim_nexthop_cache_rib *rib;
|
struct pim_nexthop_cache_rib *rib;
|
||||||
|
pim_addr group;
|
||||||
|
|
||||||
|
group = pim_addr_from_prefix(grp);
|
||||||
|
|
||||||
/* Early return if required parameters aren't provided */
|
/* Early return if required parameters aren't provided */
|
||||||
if (!pim || !pnc || !pim_nht_pnc_is_valid(pim, pnc) || !nexthop || !grp)
|
if (!pim || !pnc || !pim_nht_pnc_is_valid(pim, pnc, group) || !nexthop || !grp)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
nh_addr = nexthop->mrib_nexthop_addr;
|
nh_addr = nexthop->mrib_nexthop_addr;
|
||||||
grp_addr = pim_addr_from_prefix(grp);
|
grp_addr = pim_addr_from_prefix(grp);
|
||||||
rib = pim_pnc_get_rib(pim, pnc);
|
rib = pim_pnc_get_rib(pim, pnc, group);
|
||||||
|
|
||||||
/* Current Nexthop is VALID, check to stay on the current path. */
|
/* Current Nexthop is VALID, check to stay on the current path. */
|
||||||
if (nexthop->interface && nexthop->interface->info &&
|
if (nexthop->interface && nexthop->interface->info &&
|
||||||
|
@ -948,6 +1255,9 @@ bool pim_nht_lookup_ecmp(struct pim_instance *pim, struct pim_nexthop *nexthop,
|
||||||
uint32_t hash_val = 0;
|
uint32_t hash_val = 0;
|
||||||
uint32_t mod_val = 0;
|
uint32_t mod_val = 0;
|
||||||
uint32_t num_nbrs = 0;
|
uint32_t num_nbrs = 0;
|
||||||
|
pim_addr group;
|
||||||
|
|
||||||
|
group = pim_addr_from_prefix(grp);
|
||||||
|
|
||||||
if (PIM_DEBUG_PIM_NHT_DETAIL)
|
if (PIM_DEBUG_PIM_NHT_DETAIL)
|
||||||
zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld", __func__, &src,
|
zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld", __func__, &src,
|
||||||
|
@ -955,12 +1265,12 @@ bool pim_nht_lookup_ecmp(struct pim_instance *pim, struct pim_nexthop *nexthop,
|
||||||
|
|
||||||
pnc = pim_nexthop_cache_find(pim, src);
|
pnc = pim_nexthop_cache_find(pim, src);
|
||||||
if (pnc) {
|
if (pnc) {
|
||||||
if (pim_nht_pnc_has_answer(pim, pnc))
|
if (pim_nht_pnc_has_answer(pim, pnc, group))
|
||||||
return pim_ecmp_nexthop_search(pim, pnc, nexthop, src, grp, neighbor_needed);
|
return pim_ecmp_nexthop_search(pim, pnc, nexthop, src, grp, neighbor_needed);
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(nexthop_tab, 0, sizeof(struct pim_zlookup_nexthop) * router->multipath);
|
memset(nexthop_tab, 0, sizeof(struct pim_zlookup_nexthop) * router->multipath);
|
||||||
num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, src,
|
num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, src, group,
|
||||||
PIM_NEXTHOP_LOOKUP_MAX);
|
PIM_NEXTHOP_LOOKUP_MAX);
|
||||||
if (num_ifindex < 1) {
|
if (num_ifindex < 1) {
|
||||||
if (PIM_DEBUG_PIM_NHT)
|
if (PIM_DEBUG_PIM_NHT)
|
||||||
|
@ -1065,7 +1375,7 @@ bool pim_nht_lookup_ecmp(struct pim_instance *pim, struct pim_nexthop *nexthop,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pim_nht_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, pim_addr addr,
|
bool pim_nht_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, pim_addr addr,
|
||||||
int neighbor_needed)
|
pim_addr group, bool neighbor_needed)
|
||||||
{
|
{
|
||||||
struct pim_zlookup_nexthop nexthop_tab[router->multipath];
|
struct pim_zlookup_nexthop nexthop_tab[router->multipath];
|
||||||
struct pim_neighbor *nbr = NULL;
|
struct pim_neighbor *nbr = NULL;
|
||||||
|
@ -1101,7 +1411,7 @@ bool pim_nht_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, pim_a
|
||||||
&addr, nexthop->last_lookup_time, pim->last_route_change_time);
|
&addr, nexthop->last_lookup_time, pim->last_route_change_time);
|
||||||
|
|
||||||
memset(nexthop_tab, 0, sizeof(struct pim_zlookup_nexthop) * router->multipath);
|
memset(nexthop_tab, 0, sizeof(struct pim_zlookup_nexthop) * router->multipath);
|
||||||
num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, addr,
|
num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, router->multipath, addr, group,
|
||||||
PIM_NEXTHOP_LOOKUP_MAX);
|
PIM_NEXTHOP_LOOKUP_MAX);
|
||||||
if (num_ifindex < 1) {
|
if (num_ifindex < 1) {
|
||||||
if (PIM_DEBUG_PIM_NHT)
|
if (PIM_DEBUG_PIM_NHT)
|
||||||
|
@ -1363,36 +1673,6 @@ void pim_nexthop_update(struct vrf *vrf, struct prefix *match, struct zapi_route
|
||||||
pim_crp_nht_update(pim, pnc);
|
pim_crp_nht_update(pim, pnc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pim_nht_hash_mode_update_helper(struct hash_bucket *bucket, void *arg)
|
|
||||||
{
|
|
||||||
struct pim_nexthop_cache *pnc = bucket->data;
|
|
||||||
struct pnc_hash_walk_data *pwd = arg;
|
|
||||||
struct pim_instance *pim = pwd->pim;
|
|
||||||
|
|
||||||
if (listcount(pnc->rp_list))
|
|
||||||
pim_update_rp_nh(pim, pnc);
|
|
||||||
|
|
||||||
if (pnc->upstream_hash->count)
|
|
||||||
pim_update_upstream_nh(pim, pnc);
|
|
||||||
|
|
||||||
if (pnc->candrp_count)
|
|
||||||
pim_crp_nht_update(pim, pnc);
|
|
||||||
|
|
||||||
return HASHWALK_CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pim_nht_mode_changed(struct pim_instance *pim)
|
|
||||||
{
|
|
||||||
struct pnc_hash_walk_data pwd;
|
|
||||||
|
|
||||||
/* Update the refresh time to force new lookups if needed */
|
|
||||||
pim_rpf_set_refresh_time(pim);
|
|
||||||
|
|
||||||
/* Force update the registered RP and upstreams for all cache entries */
|
|
||||||
pwd.pim = pim;
|
|
||||||
hash_walk(pim->nht_hash, pim_nht_hash_mode_update_helper, &pwd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cleanup pim->nht_hash each node data */
|
/* Cleanup pim->nht_hash each node data */
|
||||||
static void pim_nht_hash_clean(void *data)
|
static void pim_nht_hash_clean(void *data)
|
||||||
{
|
{
|
||||||
|
@ -1432,11 +1712,19 @@ static bool pim_nht_equal(const void *arg1, const void *arg2)
|
||||||
void pim_nht_init(struct pim_instance *pim)
|
void pim_nht_init(struct pim_instance *pim)
|
||||||
{
|
{
|
||||||
char hash_name[64];
|
char hash_name[64];
|
||||||
|
struct pim_lookup_mode *global_mode;
|
||||||
|
|
||||||
snprintf(hash_name, sizeof(hash_name), "PIM %s NHT Hash", pim->vrf->name);
|
snprintf(hash_name, sizeof(hash_name), "PIM %s NHT Hash", pim->vrf->name);
|
||||||
pim->nht_hash = hash_create_size(256, pim_nht_hash_key, pim_nht_equal, hash_name);
|
pim->nht_hash = hash_create_size(256, pim_nht_hash_key, pim_nht_equal, hash_name);
|
||||||
|
|
||||||
pim->rpf_mode = MCAST_NO_CONFIG;
|
pim_lookup_mode_init(&(pim->rpf_mode));
|
||||||
|
|
||||||
|
/* Add the default global mode */
|
||||||
|
global_mode = XCALLOC(MTYPE_PIM_LOOKUP_MODE, sizeof(*global_mode));
|
||||||
|
global_mode->grp_plist = NULL;
|
||||||
|
global_mode->src_plist = NULL;
|
||||||
|
global_mode->mode = MCAST_NO_CONFIG;
|
||||||
|
pim_lookup_mode_add(&(pim->rpf_mode), global_mode);
|
||||||
|
|
||||||
if (PIM_DEBUG_ZEBRA)
|
if (PIM_DEBUG_ZEBRA)
|
||||||
zlog_debug("%s: NHT hash init: %s ", __func__, hash_name);
|
zlog_debug("%s: NHT hash init: %s ", __func__, hash_name);
|
||||||
|
@ -1446,4 +1734,7 @@ void pim_nht_terminate(struct pim_instance *pim)
|
||||||
{
|
{
|
||||||
/* Traverse and cleanup nht_hash */
|
/* Traverse and cleanup nht_hash */
|
||||||
hash_clean_and_free(&pim->nht_hash, (void *)pim_nht_hash_clean);
|
hash_clean_and_free(&pim->nht_hash, (void *)pim_nht_hash_clean);
|
||||||
|
|
||||||
|
pim_lookup_mode_list_free(&(pim->rpf_mode));
|
||||||
|
pim_lookup_mode_fini(&(pim->rpf_mode));
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,15 @@
|
||||||
#include "pim_rp.h"
|
#include "pim_rp.h"
|
||||||
#include "pim_rpf.h"
|
#include "pim_rpf.h"
|
||||||
|
|
||||||
|
PREDECL_SORTLIST_NONUNIQ(pim_lookup_mode);
|
||||||
|
|
||||||
|
struct pim_lookup_mode {
|
||||||
|
char *grp_plist;
|
||||||
|
char *src_plist;
|
||||||
|
enum pim_rpf_lookup_mode mode;
|
||||||
|
struct pim_lookup_mode_item list;
|
||||||
|
};
|
||||||
|
|
||||||
/* PIM nexthop cache value structure. */
|
/* PIM nexthop cache value structure. */
|
||||||
struct pim_nexthop_cache_rib {
|
struct pim_nexthop_cache_rib {
|
||||||
/* IGP route's metric. */
|
/* IGP route's metric. */
|
||||||
|
@ -54,6 +63,13 @@ struct pnc_hash_walk_data {
|
||||||
struct interface *ifp;
|
struct interface *ifp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Find the right lookup mode for the given group and/or source
|
||||||
|
* either may be ANY (although source should realistically always be provided)
|
||||||
|
* Find the lookup mode that has matching group and/or source prefix lists, or the global mode.
|
||||||
|
*/
|
||||||
|
enum pim_rpf_lookup_mode pim_get_lookup_mode(struct pim_instance *pim, pim_addr group,
|
||||||
|
pim_addr source);
|
||||||
|
|
||||||
/* Change the RPF lookup config, may trigger updates to RP's and Upstreams registered for matching cache entries */
|
/* Change the RPF lookup config, may trigger updates to RP's and Upstreams registered for matching cache entries */
|
||||||
void pim_nht_change_rpf_mode(struct pim_instance *pim, const char *group_plist,
|
void pim_nht_change_rpf_mode(struct pim_instance *pim, const char *group_plist,
|
||||||
const char *source_plist, enum pim_rpf_lookup_mode mode);
|
const char *source_plist, enum pim_rpf_lookup_mode mode);
|
||||||
|
@ -62,7 +78,7 @@ void pim_nht_change_rpf_mode(struct pim_instance *pim, const char *group_plist,
|
||||||
int pim_lookup_mode_write(struct pim_instance *pim, struct vty *vty);
|
int pim_lookup_mode_write(struct pim_instance *pim, struct vty *vty);
|
||||||
|
|
||||||
/* Verify that we have nexthop information in the cache entry */
|
/* Verify that we have nexthop information in the cache entry */
|
||||||
bool pim_nht_pnc_is_valid(struct pim_instance *pim, struct pim_nexthop_cache *pnc);
|
bool pim_nht_pnc_is_valid(struct pim_instance *pim, struct pim_nexthop_cache *pnc, pim_addr group);
|
||||||
|
|
||||||
/* Get (or add) the NH cache entry for the given address */
|
/* Get (or add) the NH cache entry for the given address */
|
||||||
struct pim_nexthop_cache *pim_nht_get(struct pim_instance *pim, pim_addr addr);
|
struct pim_nexthop_cache *pim_nht_get(struct pim_instance *pim, pim_addr addr);
|
||||||
|
@ -116,7 +132,7 @@ bool pim_nht_lookup_ecmp(struct pim_instance *pim, struct pim_nexthop *nexthop,
|
||||||
* a synchronous lookup. No ECMP decision is made.
|
* a synchronous lookup. No ECMP decision is made.
|
||||||
*/
|
*/
|
||||||
bool pim_nht_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, pim_addr addr,
|
bool pim_nht_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop, pim_addr addr,
|
||||||
int neighbor_needed);
|
pim_addr group, bool neighbor_needed);
|
||||||
|
|
||||||
/* Performs a pim_nht_lookup_ecmp and returns the mroute VIF index of the nexthop interface */
|
/* Performs a pim_nht_lookup_ecmp and returns the mroute VIF index of the nexthop interface */
|
||||||
int pim_nht_lookup_ecmp_if_vif_index(struct pim_instance *pim, pim_addr src, struct prefix *grp);
|
int pim_nht_lookup_ecmp_if_vif_index(struct pim_instance *pim, pim_addr src, struct prefix *grp);
|
||||||
|
@ -124,9 +140,6 @@ int pim_nht_lookup_ecmp_if_vif_index(struct pim_instance *pim, pim_addr src, str
|
||||||
/* Tracked nexthop update from zebra */
|
/* Tracked nexthop update from zebra */
|
||||||
void pim_nexthop_update(struct vrf *vrf, struct prefix *match, struct zapi_route *nhr);
|
void pim_nexthop_update(struct vrf *vrf, struct prefix *match, struct zapi_route *nhr);
|
||||||
|
|
||||||
/* RPF lookup mode changed via configuration */
|
|
||||||
void pim_nht_mode_changed(struct pim_instance *pim);
|
|
||||||
|
|
||||||
/* NHT init and finish funcitons */
|
/* NHT init and finish funcitons */
|
||||||
void pim_nht_init(struct pim_instance *pim);
|
void pim_nht_init(struct pim_instance *pim);
|
||||||
void pim_nht_terminate(struct pim_instance *pim);
|
void pim_nht_terminate(struct pim_instance *pim);
|
||||||
|
|
|
@ -375,12 +375,16 @@ static int zclient_rib_lookup(struct pim_instance *pim, struct pim_zlookup_nexth
|
||||||
|
|
||||||
static int zclient_lookup_nexthop_once(struct pim_instance *pim,
|
static int zclient_lookup_nexthop_once(struct pim_instance *pim,
|
||||||
struct pim_zlookup_nexthop nexthop_tab[], const int tab_size,
|
struct pim_zlookup_nexthop nexthop_tab[], const int tab_size,
|
||||||
pim_addr addr)
|
pim_addr addr, pim_addr group)
|
||||||
{
|
{
|
||||||
if (pim->rpf_mode == MCAST_MRIB_ONLY)
|
enum pim_rpf_lookup_mode mode;
|
||||||
|
|
||||||
|
mode = pim_get_lookup_mode(pim, group, addr);
|
||||||
|
|
||||||
|
if (mode == MCAST_MRIB_ONLY)
|
||||||
return zclient_rib_lookup(pim, nexthop_tab, tab_size, addr, SAFI_MULTICAST);
|
return zclient_rib_lookup(pim, nexthop_tab, tab_size, addr, SAFI_MULTICAST);
|
||||||
|
|
||||||
if (pim->rpf_mode == MCAST_URIB_ONLY)
|
if (mode == MCAST_URIB_ONLY)
|
||||||
return zclient_rib_lookup(pim, nexthop_tab, tab_size, addr, SAFI_UNICAST);
|
return zclient_rib_lookup(pim, nexthop_tab, tab_size, addr, SAFI_UNICAST);
|
||||||
|
|
||||||
/* All other modes require looking up both tables and making a choice */
|
/* All other modes require looking up both tables and making a choice */
|
||||||
|
@ -420,15 +424,14 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim,
|
||||||
/* Both tables have results, so compare them. Distance and prefix length are the same for all
|
/* Both tables have results, so compare them. Distance and prefix length are the same for all
|
||||||
* nexthops, so only compare the first in the list
|
* nexthops, so only compare the first in the list
|
||||||
*/
|
*/
|
||||||
if (pim->rpf_mode == MCAST_MIX_DISTANCE &&
|
if (mode == MCAST_MIX_DISTANCE &&
|
||||||
mrib_tab[0].protocol_distance > urib_tab[0].protocol_distance) {
|
mrib_tab[0].protocol_distance > urib_tab[0].protocol_distance) {
|
||||||
if (PIM_DEBUG_PIM_NHT_DETAIL)
|
if (PIM_DEBUG_PIM_NHT_DETAIL)
|
||||||
zlog_debug("%s: addr=%pPAs(%s), URIB has shortest distance", __func__,
|
zlog_debug("%s: addr=%pPAs(%s), URIB has shortest distance", __func__,
|
||||||
&addr, pim->vrf->name);
|
&addr, pim->vrf->name);
|
||||||
memcpy(nexthop_tab, urib_tab, sizeof(struct pim_zlookup_nexthop) * tab_size);
|
memcpy(nexthop_tab, urib_tab, sizeof(struct pim_zlookup_nexthop) * tab_size);
|
||||||
return urib_num;
|
return urib_num;
|
||||||
} else if (pim->rpf_mode == MCAST_MIX_PFXLEN &&
|
} else if (mode == MCAST_MIX_PFXLEN && mrib_tab[0].prefix_len < urib_tab[0].prefix_len) {
|
||||||
mrib_tab[0].prefix_len < urib_tab[0].prefix_len) {
|
|
||||||
if (PIM_DEBUG_PIM_NHT_DETAIL)
|
if (PIM_DEBUG_PIM_NHT_DETAIL)
|
||||||
zlog_debug("%s: addr=%pPAs(%s), URIB has lengthest prefix length", __func__,
|
zlog_debug("%s: addr=%pPAs(%s), URIB has lengthest prefix length", __func__,
|
||||||
&addr, pim->vrf->name);
|
&addr, pim->vrf->name);
|
||||||
|
@ -459,15 +462,13 @@ void zclient_lookup_read_pipe(struct event *thread)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
zclient_lookup_nexthop_once(pim, nexthop_tab, 10, l);
|
zclient_lookup_nexthop_once(pim, nexthop_tab, 10, l, PIMADDR_ANY);
|
||||||
event_add_timer(router->master, zclient_lookup_read_pipe, zlookup, 60,
|
event_add_timer(router->master, zclient_lookup_read_pipe, zlookup, 60,
|
||||||
&zlookup_read);
|
&zlookup_read);
|
||||||
}
|
}
|
||||||
|
|
||||||
int zclient_lookup_nexthop(struct pim_instance *pim,
|
int zclient_lookup_nexthop(struct pim_instance *pim, struct pim_zlookup_nexthop nexthop_tab[],
|
||||||
struct pim_zlookup_nexthop nexthop_tab[],
|
const int tab_size, pim_addr addr, pim_addr group, int max_lookup)
|
||||||
const int tab_size, pim_addr addr,
|
|
||||||
int max_lookup)
|
|
||||||
{
|
{
|
||||||
int lookup;
|
int lookup;
|
||||||
uint32_t route_metric = 0xFFFFFFFF;
|
uint32_t route_metric = 0xFFFFFFFF;
|
||||||
|
@ -480,8 +481,7 @@ int zclient_lookup_nexthop(struct pim_instance *pim,
|
||||||
int first_ifindex;
|
int first_ifindex;
|
||||||
pim_addr nexthop_addr;
|
pim_addr nexthop_addr;
|
||||||
|
|
||||||
num_ifindex = zclient_lookup_nexthop_once(pim, nexthop_tab,
|
num_ifindex = zclient_lookup_nexthop_once(pim, nexthop_tab, tab_size, addr, group);
|
||||||
tab_size, addr);
|
|
||||||
if (num_ifindex < 1) {
|
if (num_ifindex < 1) {
|
||||||
if (PIM_DEBUG_PIM_NHT_DETAIL)
|
if (PIM_DEBUG_PIM_NHT_DETAIL)
|
||||||
zlog_debug(
|
zlog_debug(
|
||||||
|
|
|
@ -27,10 +27,8 @@ struct pim_zlookup_nexthop {
|
||||||
void zclient_lookup_new(void);
|
void zclient_lookup_new(void);
|
||||||
void zclient_lookup_free(void);
|
void zclient_lookup_free(void);
|
||||||
|
|
||||||
int zclient_lookup_nexthop(struct pim_instance *pim,
|
int zclient_lookup_nexthop(struct pim_instance *pim, struct pim_zlookup_nexthop nexthop_tab[],
|
||||||
struct pim_zlookup_nexthop nexthop_tab[],
|
const int tab_size, pim_addr addr, pim_addr group, int max_lookup);
|
||||||
const int tab_size, pim_addr addr,
|
|
||||||
int max_lookup);
|
|
||||||
|
|
||||||
void pim_zlookup_show_ip_multicast(struct vty *vty);
|
void pim_zlookup_show_ip_multicast(struct vty *vty);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue