#endif
+static struct dst_entry *rxe_find_route(struct rxe_dev *rxe,
+ struct rxe_qp *qp,
+ struct rxe_av *av)
+{
+ struct dst_entry *dst = NULL;
+
+ if (qp_type(qp) == IB_QPT_RC)
+ dst = sk_dst_get(qp->sk->sk);
+
+ if (!dst || !(dst->obsolete && dst->ops->check(dst, 0))) {
+ if (dst)
+ dst_release(dst);
+
+ if (av->network_type == RDMA_NETWORK_IPV4) {
+ struct in_addr *saddr;
+ struct in_addr *daddr;
+
+ saddr = &av->sgid_addr._sockaddr_in.sin_addr;
+ daddr = &av->dgid_addr._sockaddr_in.sin_addr;
+ dst = rxe_find_route4(rxe->ndev, saddr, daddr);
+ } else if (av->network_type == RDMA_NETWORK_IPV6) {
+ struct in6_addr *saddr6;
+ struct in6_addr *daddr6;
+
+ saddr6 = &av->sgid_addr._sockaddr_in6.sin6_addr;
+ daddr6 = &av->dgid_addr._sockaddr_in6.sin6_addr;
+ dst = rxe_find_route6(rxe->ndev, saddr6, daddr6);
+ }
+ }
+
+ return dst;
+}
+
static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
struct udphdr *udph;
skb_scrub_packet(skb, xnet);
skb_clear_hash(skb);
- skb_dst_set(skb, dst);
+ skb_dst_set(skb, dst_clone(dst));
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
skb_push(skb, sizeof(struct iphdr));
static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
struct sk_buff *skb, struct rxe_av *av)
{
+ struct rxe_qp *qp = pkt->qp;
struct dst_entry *dst;
bool xnet = false;
__be16 df = htons(IP_DF);
struct in_addr *saddr = &av->sgid_addr._sockaddr_in.sin_addr;
struct in_addr *daddr = &av->dgid_addr._sockaddr_in.sin_addr;
- dst = rxe_find_route4(rxe->ndev, saddr, daddr);
+ dst = rxe_find_route(rxe, qp, av);
if (!dst) {
pr_err("Host not reachable\n");
return -EHOSTUNREACH;
prepare_ipv4_hdr(dst, skb, saddr->s_addr, daddr->s_addr, IPPROTO_UDP,
av->grh.traffic_class, av->grh.hop_limit, df, xnet);
+
+ if (qp_type(qp) == IB_QPT_RC)
+ sk_dst_set(qp->sk->sk, dst);
+ else
+ dst_release(dst);
+
return 0;
}
static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt,
struct sk_buff *skb, struct rxe_av *av)
{
- struct dst_entry *dst;
+ struct rxe_qp *qp = pkt->qp;
+ struct dst_entry *dst = NULL;
struct in6_addr *saddr = &av->sgid_addr._sockaddr_in6.sin6_addr;
struct in6_addr *daddr = &av->dgid_addr._sockaddr_in6.sin6_addr;
- dst = rxe_find_route6(rxe->ndev, saddr, daddr);
+ dst = rxe_find_route(rxe, qp, av);
if (!dst) {
pr_err("Host not reachable\n");
return -EHOSTUNREACH;
prepare_ipv6_hdr(dst, skb, saddr, daddr, IPPROTO_UDP,
av->grh.traffic_class,
av->grh.hop_limit);
+
+ if (qp_type(qp) == IB_QPT_RC)
+ sk_dst_set(qp->sk->sk, dst);
+ else
+ dst_release(dst);
+
return 0;
}