Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
0002 /*
0003  * Copyright (c) 2020 Mellanox Technologies. All rights reserved.
0004  */
0005 
0006 #include <rdma/ib_verbs.h>
0007 #include <rdma/ib_cache.h>
0008 #include <rdma/lag.h>
0009 
0010 static struct sk_buff *rdma_build_skb(struct ib_device *device,
0011                       struct net_device *netdev,
0012                       struct rdma_ah_attr *ah_attr,
0013                       gfp_t flags)
0014 {
0015     struct ipv6hdr *ip6h;
0016     struct sk_buff *skb;
0017     struct ethhdr *eth;
0018     struct iphdr *iph;
0019     struct udphdr *uh;
0020     u8 smac[ETH_ALEN];
0021     bool is_ipv4;
0022     int hdr_len;
0023 
0024     is_ipv4 = ipv6_addr_v4mapped((struct in6_addr *)ah_attr->grh.dgid.raw);
0025     hdr_len = ETH_HLEN + sizeof(struct udphdr) + LL_RESERVED_SPACE(netdev);
0026     hdr_len += is_ipv4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr);
0027 
0028     skb = alloc_skb(hdr_len, flags);
0029     if (!skb)
0030         return NULL;
0031 
0032     skb->dev = netdev;
0033     skb_reserve(skb, hdr_len);
0034     skb_push(skb, sizeof(struct udphdr));
0035     skb_reset_transport_header(skb);
0036     uh = udp_hdr(skb);
0037     uh->source =
0038         htons(rdma_flow_label_to_udp_sport(ah_attr->grh.flow_label));
0039     uh->dest = htons(ROCE_V2_UDP_DPORT);
0040     uh->len = htons(sizeof(struct udphdr));
0041 
0042     if (is_ipv4) {
0043         skb_push(skb, sizeof(struct iphdr));
0044         skb_reset_network_header(skb);
0045         iph = ip_hdr(skb);
0046         iph->frag_off = 0;
0047         iph->version = 4;
0048         iph->protocol = IPPROTO_UDP;
0049         iph->ihl = 0x5;
0050         iph->tot_len = htons(sizeof(struct udphdr) + sizeof(struct
0051                                     iphdr));
0052         memcpy(&iph->saddr, ah_attr->grh.sgid_attr->gid.raw + 12,
0053                sizeof(struct in_addr));
0054         memcpy(&iph->daddr, ah_attr->grh.dgid.raw + 12,
0055                sizeof(struct in_addr));
0056     } else {
0057         skb_push(skb, sizeof(struct ipv6hdr));
0058         skb_reset_network_header(skb);
0059         ip6h = ipv6_hdr(skb);
0060         ip6h->version = 6;
0061         ip6h->nexthdr = IPPROTO_UDP;
0062         memcpy(&ip6h->flow_lbl, &ah_attr->grh.flow_label,
0063                sizeof(*ip6h->flow_lbl));
0064         memcpy(&ip6h->saddr, ah_attr->grh.sgid_attr->gid.raw,
0065                sizeof(struct in6_addr));
0066         memcpy(&ip6h->daddr, ah_attr->grh.dgid.raw,
0067                sizeof(struct in6_addr));
0068     }
0069 
0070     skb_push(skb, sizeof(struct ethhdr));
0071     skb_reset_mac_header(skb);
0072     eth = eth_hdr(skb);
0073     skb->protocol = eth->h_proto = htons(is_ipv4 ? ETH_P_IP : ETH_P_IPV6);
0074     rdma_read_gid_l2_fields(ah_attr->grh.sgid_attr, NULL, smac);
0075     memcpy(eth->h_source, smac, ETH_ALEN);
0076     memcpy(eth->h_dest, ah_attr->roce.dmac, ETH_ALEN);
0077 
0078     return skb;
0079 }
0080 
0081 static struct net_device *rdma_get_xmit_slave_udp(struct ib_device *device,
0082                           struct net_device *master,
0083                           struct rdma_ah_attr *ah_attr,
0084                           gfp_t flags)
0085 {
0086     struct net_device *slave;
0087     struct sk_buff *skb;
0088 
0089     skb = rdma_build_skb(device, master, ah_attr, flags);
0090     if (!skb)
0091         return ERR_PTR(-ENOMEM);
0092 
0093     rcu_read_lock();
0094     slave = netdev_get_xmit_slave(master, skb,
0095                       !!(device->lag_flags &
0096                      RDMA_LAG_FLAGS_HASH_ALL_SLAVES));
0097     if (slave)
0098         dev_hold(slave);
0099     rcu_read_unlock();
0100     kfree_skb(skb);
0101     return slave;
0102 }
0103 
0104 void rdma_lag_put_ah_roce_slave(struct net_device *xmit_slave)
0105 {
0106     if (xmit_slave)
0107         dev_put(xmit_slave);
0108 }
0109 
0110 struct net_device *rdma_lag_get_ah_roce_slave(struct ib_device *device,
0111                           struct rdma_ah_attr *ah_attr,
0112                           gfp_t flags)
0113 {
0114     struct net_device *slave = NULL;
0115     struct net_device *master;
0116 
0117     if (!(ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE &&
0118           ah_attr->grh.sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP &&
0119           ah_attr->grh.flow_label))
0120         return NULL;
0121 
0122     rcu_read_lock();
0123     master = rdma_read_gid_attr_ndev_rcu(ah_attr->grh.sgid_attr);
0124     if (IS_ERR(master)) {
0125         rcu_read_unlock();
0126         return master;
0127     }
0128     dev_hold(master);
0129     rcu_read_unlock();
0130 
0131     if (!netif_is_bond_master(master))
0132         goto put;
0133 
0134     slave = rdma_get_xmit_slave_udp(device, master, ah_attr, flags);
0135 put:
0136     dev_put(master);
0137     return slave;
0138 }