mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 01:14:48 +00:00
pimd: add back blocking RPF for BSM
NHT won't have a result yet when we get the first BSM from a new BSR. Hence, the first packet(s) are lost, since their RPF validation fails. Re-add the blocking RPF check that was there before (though in a much more sensible manner.) Also nuke the now-unused pim_nexthop_match* functions. Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
This commit is contained in:
parent
b09bd804ac
commit
caef8f7961
252
pimd/pim_nht.c
252
pimd/pim_nht.c
@ -282,15 +282,66 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr,
|
||||
{
|
||||
struct pim_nexthop_cache *pnc = NULL;
|
||||
struct pim_nexthop_cache lookup;
|
||||
struct pim_neighbor *nbr = NULL;
|
||||
struct nexthop *nh;
|
||||
struct interface *ifp;
|
||||
|
||||
lookup.rpf.rpf_addr.family = AF_INET;
|
||||
lookup.rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
|
||||
lookup.rpf.rpf_addr.u.prefix4 = bsr_addr;
|
||||
|
||||
pnc = hash_lookup(pim->rpf_hash, &lookup);
|
||||
if (!pnc)
|
||||
if (!pnc || !CHECK_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED)) {
|
||||
/* BSM from a new freshly registered BSR - do a synchronous
|
||||
* zebra query since otherwise we'd drop the first packet,
|
||||
* leading to additional delay in picking up BSM data
|
||||
*/
|
||||
|
||||
/* FIXME: this should really be moved into a generic NHT
|
||||
* function that does "add and get immediate result" or maybe
|
||||
* "check cache or get immediate result." But until that can
|
||||
* be worked in, here's a copy of the code below :(
|
||||
*/
|
||||
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
|
||||
ifindex_t i;
|
||||
struct interface *ifp = NULL;
|
||||
int num_ifindex;
|
||||
|
||||
memset(nexthop_tab, 0, sizeof(nexthop_tab));
|
||||
num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab,
|
||||
MULTIPATH_NUM, bsr_addr,
|
||||
PIM_NEXTHOP_LOOKUP_MAX);
|
||||
|
||||
if (num_ifindex <= 0)
|
||||
return false;
|
||||
|
||||
for (i = 0; i < num_ifindex; i++) {
|
||||
struct pim_zlookup_nexthop *znh = &nexthop_tab[i];
|
||||
|
||||
/* pim_zlookup_nexthop has no ->type */
|
||||
|
||||
/* 1:1 match code below with znh instead of nh */
|
||||
ifp = if_lookup_by_index(znh->ifindex,
|
||||
pim->vrf->vrf_id);
|
||||
|
||||
if (!ifp || !ifp->info)
|
||||
continue;
|
||||
|
||||
if (if_is_loopback(ifp) && if_is_loopback(src_ifp))
|
||||
return true;
|
||||
|
||||
nbr = pim_neighbor_find(ifp,
|
||||
znh->nexthop_addr.u.prefix4);
|
||||
if (!nbr)
|
||||
continue;
|
||||
|
||||
return znh->ifindex == src_ifp->ifindex
|
||||
&& znh->nexthop_addr.u.prefix4.s_addr
|
||||
== src_ip.s_addr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID))
|
||||
return false;
|
||||
|
||||
@ -299,176 +350,45 @@ bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr,
|
||||
* 4-way ECMP and 4 hops you end up with 256 copies of each BSM
|
||||
* message.
|
||||
*
|
||||
* so... only accept the first (IPv4) nexthop as source.
|
||||
* so... only accept the first (IPv4) valid nexthop as source.
|
||||
*/
|
||||
|
||||
for (nh = pnc->nexthop; nh; nh = nh->next) {
|
||||
if (nh->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
|
||||
struct in_addr nhaddr;
|
||||
|
||||
switch (nh->type) {
|
||||
case NEXTHOP_TYPE_IPV4:
|
||||
if (nh->ifindex == IFINDEX_INTERNAL)
|
||||
continue;
|
||||
|
||||
/* fallthru */
|
||||
case NEXTHOP_TYPE_IPV4_IFINDEX:
|
||||
nhaddr = nh->gate.ipv4;
|
||||
break;
|
||||
|
||||
case NEXTHOP_TYPE_IFINDEX:
|
||||
nhaddr = bsr_addr;
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
ifp = if_lookup_by_index(nh->ifindex, pim->vrf->vrf_id);
|
||||
if (!ifp || !ifp->info)
|
||||
continue;
|
||||
|
||||
if (if_is_loopback(ifp) && if_is_loopback(src_ifp))
|
||||
return true;
|
||||
|
||||
/* MRIB (IGP) may be pointing at a router where PIM is down */
|
||||
nbr = pim_neighbor_find(ifp, nhaddr);
|
||||
if (!nbr)
|
||||
continue;
|
||||
|
||||
return nh->ifindex == src_ifp->ifindex
|
||||
&& nh->gate.ipv4.s_addr == src_ip.s_addr;
|
||||
&& nhaddr.s_addr == src_ip.s_addr;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Given a source address and a neighbor address, check if the neighbor is one
|
||||
* of the next hop to reach the source. search from zebra route database
|
||||
*/
|
||||
bool pim_nexthop_match(struct pim_instance *pim, struct in_addr addr,
|
||||
struct in_addr ip_src)
|
||||
{
|
||||
struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM];
|
||||
int i = 0;
|
||||
ifindex_t first_ifindex = 0;
|
||||
struct interface *ifp = NULL;
|
||||
struct pim_neighbor *nbr = NULL;
|
||||
int num_ifindex;
|
||||
|
||||
if (addr.s_addr == INADDR_NONE)
|
||||
return false;
|
||||
|
||||
memset(nexthop_tab, 0,
|
||||
sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM);
|
||||
num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM,
|
||||
addr, PIM_NEXTHOP_LOOKUP_MAX);
|
||||
if (num_ifindex < 1) {
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
|
||||
pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
|
||||
zlog_warn(
|
||||
"%s %s: could not find nexthop ifindex for address %s",
|
||||
__FILE__, __func__, addr_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (i < num_ifindex) {
|
||||
first_ifindex = nexthop_tab[i].ifindex;
|
||||
|
||||
ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
|
||||
if (!ifp) {
|
||||
if (PIM_DEBUG_ZEBRA) {
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
|
||||
pim_inet4_dump("<addr?>", addr, addr_str,
|
||||
sizeof(addr_str));
|
||||
zlog_debug(
|
||||
"%s %s: could not find interface for ifindex %d (address %s)",
|
||||
__FILE__, __func__, first_ifindex,
|
||||
addr_str);
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ifp->info) {
|
||||
if (PIM_DEBUG_ZEBRA) {
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
|
||||
pim_inet4_dump("<addr?>", addr, addr_str,
|
||||
sizeof(addr_str));
|
||||
zlog_debug(
|
||||
"%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)",
|
||||
__func__, ifp->name, first_ifindex,
|
||||
addr_str);
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pim_if_connected_to_source(ifp, addr)) {
|
||||
nbr = pim_neighbor_find(
|
||||
ifp, nexthop_tab[i].nexthop_addr.u.prefix4);
|
||||
if (PIM_DEBUG_PIM_TRACE_DETAIL)
|
||||
zlog_debug("ifp name: %s, pim nbr: %p",
|
||||
ifp->name, nbr);
|
||||
if (!nbr && !if_is_loopback(ifp)) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (nexthop_tab[i].nexthop_addr.u.prefix4.s_addr
|
||||
== ip_src.s_addr)
|
||||
return true;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Given a source address and a neighbor address, check if the neighbor is one
|
||||
* of the next hop to reach the source. search from pim next hop cache
|
||||
*/
|
||||
bool pim_nexthop_match_nht_cache(struct pim_instance *pim, struct in_addr addr,
|
||||
struct in_addr ip_src)
|
||||
{
|
||||
struct pim_rpf rpf;
|
||||
ifindex_t first_ifindex;
|
||||
struct interface *ifp = NULL;
|
||||
uint8_t nh_iter = 0;
|
||||
struct pim_neighbor *nbr = NULL;
|
||||
struct nexthop *nh_node = NULL;
|
||||
struct pim_nexthop_cache *pnc = NULL;
|
||||
|
||||
memset(&rpf, 0, sizeof(struct pim_rpf));
|
||||
rpf.rpf_addr.family = AF_INET;
|
||||
rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN;
|
||||
rpf.rpf_addr.u.prefix4 = addr;
|
||||
|
||||
pnc = pim_nexthop_cache_find(pim, &rpf);
|
||||
if (!pnc || !pnc->nexthop_num)
|
||||
return false;
|
||||
|
||||
for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
|
||||
first_ifindex = nh_node->ifindex;
|
||||
ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
|
||||
if (!ifp) {
|
||||
if (PIM_DEBUG_PIM_NHT) {
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
|
||||
pim_inet4_dump("<addr?>", addr, addr_str,
|
||||
sizeof(addr_str));
|
||||
zlog_debug(
|
||||
"%s %s: could not find interface for ifindex %d (address %s(%s))",
|
||||
__FILE__, __func__, first_ifindex,
|
||||
addr_str, pim->vrf->name);
|
||||
}
|
||||
nh_iter++;
|
||||
continue;
|
||||
}
|
||||
if (!ifp->info) {
|
||||
if (PIM_DEBUG_PIM_NHT) {
|
||||
char addr_str[INET_ADDRSTRLEN];
|
||||
|
||||
pim_inet4_dump("<addr?>", addr, addr_str,
|
||||
sizeof(addr_str));
|
||||
zlog_debug(
|
||||
"%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)",
|
||||
__func__, ifp->name, pim->vrf->name,
|
||||
first_ifindex, addr_str);
|
||||
}
|
||||
nh_iter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!pim_if_connected_to_source(ifp, addr)) {
|
||||
nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4);
|
||||
if (!nbr && !if_is_loopback(ifp)) {
|
||||
if (PIM_DEBUG_PIM_NHT)
|
||||
zlog_debug(
|
||||
"%s: pim nbr not found on input interface %s(%s)",
|
||||
__func__, ifp->name,
|
||||
pim->vrf->name);
|
||||
nh_iter++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (nh_node->gate.ipv4.s_addr == ip_src.s_addr)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -70,10 +70,6 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient,
|
||||
int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim,
|
||||
struct prefix *src, struct prefix *grp);
|
||||
void pim_rp_nexthop_del(struct rp_info *rp_info);
|
||||
bool pim_nexthop_match(struct pim_instance *pim, struct in_addr addr,
|
||||
struct in_addr ip_src);
|
||||
bool pim_nexthop_match_nht_cache(struct pim_instance *pim, struct in_addr addr,
|
||||
struct in_addr ip_src);
|
||||
|
||||
/* for RPF check on BSM message receipt */
|
||||
void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr bsr_addr);
|
||||
|
Loading…
Reference in New Issue
Block a user