Currently a packet is marked for loopback only if the source and destination addresses match, This is not enough when multiple gids are present in rxe device's gid table and the traffic is from one gid to another, this patch fixes this by marking the packet for loopback if the destination address found in the rxe's netdevice address list. Fixes: 8700e3e7c485 ("Soft RoCE driver") Signed-off-by: Marcel Apfelbaum <marcel.apfelbaum@xxxxxxxxx> Signed-off-by: Kamal Heib <kamalheib1@xxxxxxxxx> --- drivers/infiniband/sw/rxe/rxe_net.c | 45 +++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 8fd03ae20efc..6ee984b7793b 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -368,6 +368,25 @@ static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb, ip6h->payload_len = htons(skb->len - sizeof(*ip6h)); } +static inline bool same_rxe4(struct net_device *ndev, struct in_addr *daddr) +{ + struct in_device *in_dev; + bool same_rxe = false; + + in_dev = in_dev_get(ndev); + if (!in_dev) + return false; + + for_ifa(in_dev) + if (!memcmp(&ifa->ifa_address, daddr, sizeof(*daddr))) { + same_rxe = true; + break; + } + endfor_ifa(in_dev); + in_dev_put(in_dev); + return same_rxe; +} + static int prepare4(struct rxe_pkt_info *pkt, struct sk_buff *skb, struct rxe_av *av) { @@ -384,7 +403,7 @@ static int prepare4(struct rxe_pkt_info *pkt, struct sk_buff *skb, return -EHOSTUNREACH; } - if (!memcmp(saddr, daddr, sizeof(*daddr))) + if (same_rxe4(skb->dev, daddr)) pkt->mask |= RXE_LOOPBACK_MASK; prepare_udp_hdr(skb, cpu_to_be16(qp->src_port), @@ -397,6 +416,28 @@ static int prepare4(struct rxe_pkt_info *pkt, struct sk_buff *skb, return 0; } +static inline bool same_rxe6(struct net_device *ndev, struct in6_addr *daddr) +{ + struct inet6_dev *in6_dev; + struct inet6_ifaddr *ifp; + bool same_rxe = false; + + in6_dev = in6_dev_get(ndev); + if (!in6_dev) + return false; + + read_lock_bh(&in6_dev->lock); + list_for_each_entry(ifp, &in6_dev->addr_list, if_list) { + if (!memcmp(&ifp->addr, daddr, sizeof(*daddr))) { + same_rxe = true; + break; + } + } + read_unlock_bh(&in6_dev->lock); + in6_dev_put(in6_dev); + return same_rxe; +} + static int prepare6(struct rxe_pkt_info *pkt, struct sk_buff *skb, struct rxe_av *av) { @@ -411,7 +452,7 @@ static int prepare6(struct rxe_pkt_info *pkt, struct sk_buff *skb, return -EHOSTUNREACH; } - if (!memcmp(saddr, daddr, sizeof(*daddr))) + if (same_rxe6(skb->dev, daddr)) pkt->mask |= RXE_LOOPBACK_MASK; prepare_udp_hdr(skb, cpu_to_be16(qp->src_port), -- 2.20.1