diff options
Diffstat (limited to 'drivers/infiniband/sw/rxe/rxe_net.c')
-rw-r--r-- | drivers/infiniband/sw/rxe/rxe_net.c | 83 |
1 files changed, 51 insertions, 32 deletions
diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index d8610960..c3a140e 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -84,34 +84,6 @@ struct rxe_dev *get_rxe_by_name(const char *name) struct rxe_recv_sockets recv_sockets; -static __be64 rxe_mac_to_eui64(struct net_device *ndev) -{ - unsigned char *mac_addr = ndev->dev_addr; - __be64 eui64; - unsigned char *dst = (unsigned char *)&eui64; - - dst[0] = mac_addr[0] ^ 2; - dst[1] = mac_addr[1]; - dst[2] = mac_addr[2]; - dst[3] = 0xff; - dst[4] = 0xfe; - dst[5] = mac_addr[3]; - dst[6] = mac_addr[4]; - dst[7] = mac_addr[5]; - - return eui64; -} - -__be64 rxe_node_guid(struct rxe_dev *rxe) -{ - return rxe_mac_to_eui64(rxe->ndev); -} - -__be64 rxe_port_guid(struct rxe_dev *rxe) -{ - return rxe_mac_to_eui64(rxe->ndev); -} - struct device *rxe_dma_device(struct rxe_dev *rxe) { struct net_device *ndev; @@ -210,6 +182,39 @@ static struct dst_entry *rxe_find_route6(struct net_device *ndev, #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; @@ -301,7 +306,7 @@ static void prepare_ipv4_hdr(struct dst_entry *dst, struct sk_buff *skb, 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)); @@ -349,13 +354,14 @@ static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb, 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; @@ -369,17 +375,24 @@ static int prepare4(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, 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; @@ -394,6 +407,12 @@ static int prepare6(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, 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; } |