1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* 3 * Copyright (c) 2020 Mellanox Technologies. All rights reserved. 4 */ 5 6 #include <rdma/ib_verbs.h> 7 #include <rdma/ib_cache.h> 8 #include <rdma/lag.h> 9 10 static struct sk_buff *rdma_build_skb(struct net_device *netdev, 11 struct rdma_ah_attr *ah_attr, 12 gfp_t flags) 13 { 14 struct ipv6hdr *ip6h; 15 struct sk_buff *skb; 16 struct ethhdr *eth; 17 struct iphdr *iph; 18 struct udphdr *uh; 19 u8 smac[ETH_ALEN]; 20 bool is_ipv4; 21 int hdr_len; 22 int ret; 23 24 ret = rdma_read_gid_l2_fields(ah_attr->grh.sgid_attr, NULL, smac); 25 if (ret) 26 return ERR_PTR(ret); 27 28 is_ipv4 = ipv6_addr_v4mapped((struct in6_addr *)ah_attr->grh.dgid.raw); 29 hdr_len = ETH_HLEN + sizeof(struct udphdr) + LL_RESERVED_SPACE(netdev); 30 hdr_len += is_ipv4 ? sizeof(struct iphdr) : sizeof(struct ipv6hdr); 31 32 skb = alloc_skb(hdr_len, flags); 33 if (!skb) 34 return ERR_PTR(-ENOMEM); 35 36 skb->dev = netdev; 37 skb_reserve(skb, hdr_len); 38 skb_push(skb, sizeof(struct udphdr)); 39 skb_reset_transport_header(skb); 40 uh = udp_hdr(skb); 41 uh->source = 42 htons(rdma_flow_label_to_udp_sport(ah_attr->grh.flow_label)); 43 uh->dest = htons(ROCE_V2_UDP_DPORT); 44 udp_set_len_short(uh, sizeof(struct udphdr)); 45 46 if (is_ipv4) { 47 skb_push(skb, sizeof(struct iphdr)); 48 skb_reset_network_header(skb); 49 iph = ip_hdr(skb); 50 iph->frag_off = 0; 51 iph->version = 4; 52 iph->protocol = IPPROTO_UDP; 53 iph->ihl = 0x5; 54 iph->tot_len = htons(sizeof(struct udphdr) + sizeof(struct 55 iphdr)); 56 memcpy(&iph->saddr, ah_attr->grh.sgid_attr->gid.raw + 12, 57 sizeof(struct in_addr)); 58 memcpy(&iph->daddr, ah_attr->grh.dgid.raw + 12, 59 sizeof(struct in_addr)); 60 } else { 61 skb_push(skb, sizeof(struct ipv6hdr)); 62 skb_reset_network_header(skb); 63 ip6h = ipv6_hdr(skb); 64 ip6h->version = 6; 65 ip6h->nexthdr = IPPROTO_UDP; 66 memcpy(&ip6h->flow_lbl, &ah_attr->grh.flow_label, 67 sizeof(ip6h->flow_lbl)); 68 memcpy(&ip6h->saddr, ah_attr->grh.sgid_attr->gid.raw, 69 sizeof(struct in6_addr)); 70 memcpy(&ip6h->daddr, ah_attr->grh.dgid.raw, 71 sizeof(struct in6_addr)); 72 } 73 74 skb_push(skb, sizeof(struct ethhdr)); 75 skb_reset_mac_header(skb); 76 eth = eth_hdr(skb); 77 skb->protocol = eth->h_proto = htons(is_ipv4 ? ETH_P_IP : ETH_P_IPV6); 78 memcpy(eth->h_source, smac, ETH_ALEN); 79 memcpy(eth->h_dest, ah_attr->roce.dmac, ETH_ALEN); 80 81 return skb; 82 } 83 84 static struct net_device *rdma_get_xmit_slave_udp(struct ib_device *device, 85 struct net_device *master, 86 struct rdma_ah_attr *ah_attr, 87 gfp_t flags) 88 { 89 struct net_device *slave; 90 struct sk_buff *skb; 91 92 skb = rdma_build_skb(master, ah_attr, flags); 93 if (IS_ERR(skb)) 94 return ERR_CAST(skb); 95 96 rcu_read_lock(); 97 slave = netdev_get_xmit_slave(master, skb, 98 !!(device->lag_flags & 99 RDMA_LAG_FLAGS_HASH_ALL_SLAVES)); 100 dev_hold(slave); 101 rcu_read_unlock(); 102 kfree_skb(skb); 103 return slave; 104 } 105 106 void rdma_lag_put_ah_roce_slave(struct net_device *xmit_slave) 107 { 108 dev_put(xmit_slave); 109 } 110 111 struct net_device *rdma_lag_get_ah_roce_slave(struct ib_device *device, 112 struct rdma_ah_attr *ah_attr, 113 gfp_t flags) 114 { 115 struct net_device *slave = NULL; 116 struct net_device *master; 117 118 if (!(ah_attr->type == RDMA_AH_ATTR_TYPE_ROCE && 119 ah_attr->grh.sgid_attr->gid_type == IB_GID_TYPE_ROCE_UDP_ENCAP && 120 ah_attr->grh.flow_label)) 121 return NULL; 122 123 rcu_read_lock(); 124 master = rdma_read_gid_attr_ndev_rcu(ah_attr->grh.sgid_attr); 125 if (IS_ERR(master)) { 126 rcu_read_unlock(); 127 return master; 128 } 129 dev_hold(master); 130 rcu_read_unlock(); 131 132 if (!netif_is_bond_master(master)) 133 goto put; 134 135 slave = rdma_get_xmit_slave_udp(device, master, ah_attr, flags); 136 put: 137 dev_put(master); 138 return slave; 139 } 140