Skip to content

Commit c31e403

Browse files
paravmellanoxrleon
authored andcommitted
RDMA/core: Use route entry flag to decide on loopback traffic
addr_resolve() considers a destination to be local if the next-hop device of the resolved route for the destination is the loopback netdevice. This fails when the source and destination IP addresses belong to a netdev enslaved to a VRF netdev. In this case the next-hop device is the VRF itself: $ ip link add name myvrf up type vrf table 100 $ ip link set ens2f0np0 master myvrf up $ ip addr add 192.168.1.1/24 dev ens2f0np0 $ ip route get 192.168.1.1 oif myvrf local 192.168.1.1 dev myvrf table 100 src 192.168.1.1 uid 0 cache <local> This results in packets being generated with an incorrect destination MAC of the VRF netdevice and ib_write_bw failing with timeout. Solve this by determining if a destination is local or not based on the resolved route's type rather than based on its next-hop netdevice loopback flag. This enables to resolve loopback traffic with and without VRF configurations in a uniform way. Signed-off-by: Parav Pandit <parav@nvidia.com> Reviewed-by: Vlad Dumitrescu <vdumitrescu@nvidia.com> Signed-off-by: Edward Srouji <edwards@nvidia.com> Link: https://patch.msgid.link/20250916111103.84069-4-edwards@nvidia.com Signed-off-by: Leon Romanovsky <leon@kernel.org>
1 parent 200651b commit c31e403

1 file changed

Lines changed: 21 additions & 13 deletions

File tree

drivers/infiniband/core/addr.c

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -446,31 +446,40 @@ static int addr6_resolve(struct sockaddr *src_sock,
446446
}
447447
#endif
448448

449+
static bool is_dst_local(const struct dst_entry *dst)
450+
{
451+
if (dst->ops->family == AF_INET)
452+
return !!(dst_rtable(dst)->rt_type & RTN_LOCAL);
453+
else if (dst->ops->family == AF_INET6)
454+
return !!(dst_rt6_info(dst)->rt6i_flags & RTF_LOCAL);
455+
else
456+
return false;
457+
}
458+
449459
static int addr_resolve_neigh(const struct dst_entry *dst,
450460
const struct sockaddr *dst_in,
451461
struct rdma_dev_addr *addr,
452-
unsigned int ndev_flags,
453462
u32 seq)
454463
{
455-
int ret = 0;
456-
457-
if (ndev_flags & IFF_LOOPBACK)
464+
if (is_dst_local(dst)) {
465+
/* When the destination is local entry, source and destination
466+
* are same. Skip the neighbour lookup.
467+
*/
458468
memcpy(addr->dst_dev_addr, addr->src_dev_addr, MAX_ADDR_LEN);
459-
else
460-
ret = fetch_ha(dst, addr, dst_in, seq);
461-
return ret;
469+
return 0;
470+
}
471+
472+
return fetch_ha(dst, addr, dst_in, seq);
462473
}
463474

464475
static int rdma_set_src_addr_rcu(struct rdma_dev_addr *dev_addr,
465-
unsigned int *ndev_flags,
466476
const struct sockaddr *dst_in,
467477
const struct dst_entry *dst)
468478
{
469479
struct net_device *ndev = READ_ONCE(dst->dev);
470480

471-
*ndev_flags = ndev->flags;
472481
/* A physical device must be the RDMA device to use */
473-
if (ndev->flags & IFF_LOOPBACK) {
482+
if (is_dst_local(dst)) {
474483
int ret;
475484
/*
476485
* RDMA (IB/RoCE, iWarp) doesn't run on lo interface or
@@ -538,7 +547,6 @@ static int addr_resolve(struct sockaddr *src_in,
538547
u32 seq)
539548
{
540549
struct dst_entry *dst = NULL;
541-
unsigned int ndev_flags = 0;
542550
struct rtable *rt = NULL;
543551
int ret;
544552

@@ -575,15 +583,15 @@ static int addr_resolve(struct sockaddr *src_in,
575583
rcu_read_unlock();
576584
goto done;
577585
}
578-
ret = rdma_set_src_addr_rcu(addr, &ndev_flags, dst_in, dst);
586+
ret = rdma_set_src_addr_rcu(addr, dst_in, dst);
579587
rcu_read_unlock();
580588

581589
/*
582590
* Resolve neighbor destination address if requested and
583591
* only if src addr translation didn't fail.
584592
*/
585593
if (!ret && resolve_neigh)
586-
ret = addr_resolve_neigh(dst, dst_in, addr, ndev_flags, seq);
594+
ret = addr_resolve_neigh(dst, dst_in, addr, seq);
587595

588596
if (src_in->sa_family == AF_INET)
589597
ip_rt_put(rt);

0 commit comments

Comments
 (0)