1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
2 | /* |
3 | * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. |
4 | * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. |
5 | */ |
6 | |
7 | #include "rxe.h" |
8 | #include "rxe_loc.h" |
9 | |
10 | void rxe_init_av(struct rdma_ah_attr *attr, struct rxe_av *av) |
11 | { |
12 | rxe_av_from_attr(port_num: rdma_ah_get_port_num(attr), av, attr); |
13 | rxe_av_fill_ip_info(av, attr); |
14 | memcpy(av->dmac, attr->roce.dmac, ETH_ALEN); |
15 | } |
16 | |
17 | static int chk_attr(void *obj, struct rdma_ah_attr *attr, bool obj_is_ah) |
18 | { |
19 | const struct ib_global_route *grh = rdma_ah_read_grh(attr); |
20 | struct rxe_port *port; |
21 | struct rxe_dev *rxe; |
22 | struct rxe_qp *qp; |
23 | struct rxe_ah *ah; |
24 | int type; |
25 | |
26 | if (obj_is_ah) { |
27 | ah = obj; |
28 | rxe = to_rdev(dev: ah->ibah.device); |
29 | } else { |
30 | qp = obj; |
31 | rxe = to_rdev(dev: qp->ibqp.device); |
32 | } |
33 | |
34 | port = &rxe->port; |
35 | |
36 | if (rdma_ah_get_ah_flags(attr) & IB_AH_GRH) { |
37 | if (grh->sgid_index > port->attr.gid_tbl_len) { |
38 | if (obj_is_ah) |
39 | rxe_dbg_ah(ah, "invalid sgid index = %d\n" , |
40 | grh->sgid_index); |
41 | else |
42 | rxe_dbg_qp(qp, "invalid sgid index = %d\n" , |
43 | grh->sgid_index); |
44 | return -EINVAL; |
45 | } |
46 | |
47 | type = rdma_gid_attr_network_type(attr: grh->sgid_attr); |
48 | if (type < RDMA_NETWORK_IPV4 || |
49 | type > RDMA_NETWORK_IPV6) { |
50 | if (obj_is_ah) |
51 | rxe_dbg_ah(ah, "invalid network type for rdma_rxe = %d\n" , |
52 | type); |
53 | else |
54 | rxe_dbg_qp(qp, "invalid network type for rdma_rxe = %d\n" , |
55 | type); |
56 | return -EINVAL; |
57 | } |
58 | } |
59 | |
60 | return 0; |
61 | } |
62 | |
63 | int rxe_av_chk_attr(struct rxe_qp *qp, struct rdma_ah_attr *attr) |
64 | { |
65 | return chk_attr(obj: qp, attr, obj_is_ah: false); |
66 | } |
67 | |
68 | int rxe_ah_chk_attr(struct rxe_ah *ah, struct rdma_ah_attr *attr) |
69 | { |
70 | return chk_attr(obj: ah, attr, obj_is_ah: true); |
71 | } |
72 | |
73 | void rxe_av_from_attr(u8 port_num, struct rxe_av *av, |
74 | struct rdma_ah_attr *attr) |
75 | { |
76 | const struct ib_global_route *grh = rdma_ah_read_grh(attr); |
77 | |
78 | memset(av, 0, sizeof(*av)); |
79 | memcpy(av->grh.dgid.raw, grh->dgid.raw, sizeof(grh->dgid.raw)); |
80 | av->grh.flow_label = grh->flow_label; |
81 | av->grh.sgid_index = grh->sgid_index; |
82 | av->grh.hop_limit = grh->hop_limit; |
83 | av->grh.traffic_class = grh->traffic_class; |
84 | av->port_num = port_num; |
85 | } |
86 | |
87 | void rxe_av_to_attr(struct rxe_av *av, struct rdma_ah_attr *attr) |
88 | { |
89 | struct ib_global_route *grh = rdma_ah_retrieve_grh(attr); |
90 | |
91 | attr->type = RDMA_AH_ATTR_TYPE_ROCE; |
92 | |
93 | memcpy(grh->dgid.raw, av->grh.dgid.raw, sizeof(av->grh.dgid.raw)); |
94 | grh->flow_label = av->grh.flow_label; |
95 | grh->sgid_index = av->grh.sgid_index; |
96 | grh->hop_limit = av->grh.hop_limit; |
97 | grh->traffic_class = av->grh.traffic_class; |
98 | |
99 | rdma_ah_set_ah_flags(attr, flag: IB_AH_GRH); |
100 | rdma_ah_set_port_num(attr, port_num: av->port_num); |
101 | } |
102 | |
103 | void rxe_av_fill_ip_info(struct rxe_av *av, struct rdma_ah_attr *attr) |
104 | { |
105 | const struct ib_gid_attr *sgid_attr = attr->grh.sgid_attr; |
106 | int ibtype; |
107 | int type; |
108 | |
109 | rdma_gid2ip(out: (struct sockaddr *)&av->sgid_addr, gid: &sgid_attr->gid); |
110 | rdma_gid2ip(out: (struct sockaddr *)&av->dgid_addr, |
111 | gid: &rdma_ah_read_grh(attr)->dgid); |
112 | |
113 | ibtype = rdma_gid_attr_network_type(attr: sgid_attr); |
114 | |
115 | switch (ibtype) { |
116 | case RDMA_NETWORK_IPV4: |
117 | type = RXE_NETWORK_TYPE_IPV4; |
118 | break; |
119 | case RDMA_NETWORK_IPV6: |
120 | type = RXE_NETWORK_TYPE_IPV6; |
121 | break; |
122 | default: |
123 | /* not reached - checked in rxe_av_chk_attr */ |
124 | type = 0; |
125 | break; |
126 | } |
127 | |
128 | av->network_type = type; |
129 | } |
130 | |
131 | struct rxe_av *rxe_get_av(struct rxe_pkt_info *pkt, struct rxe_ah **ahp) |
132 | { |
133 | struct rxe_ah *ah; |
134 | u32 ah_num; |
135 | |
136 | if (ahp) |
137 | *ahp = NULL; |
138 | |
139 | if (!pkt || !pkt->qp) |
140 | return NULL; |
141 | |
142 | if (qp_type(qp: pkt->qp) == IB_QPT_RC || qp_type(qp: pkt->qp) == IB_QPT_UC) |
143 | return &pkt->qp->pri_av; |
144 | |
145 | if (!pkt->wqe) |
146 | return NULL; |
147 | |
148 | ah_num = pkt->wqe->wr.wr.ud.ah_num; |
149 | if (ah_num) { |
150 | /* only new user provider or kernel client */ |
151 | ah = rxe_pool_get_index(pool: &pkt->rxe->ah_pool, index: ah_num); |
152 | if (!ah) { |
153 | rxe_dbg_qp(pkt->qp, "Unable to find AH matching ah_num\n" ); |
154 | return NULL; |
155 | } |
156 | |
157 | if (rxe_ah_pd(ah) != pkt->qp->pd) { |
158 | rxe_dbg_qp(pkt->qp, "PDs don't match for AH and QP\n" ); |
159 | rxe_put(ah); |
160 | return NULL; |
161 | } |
162 | |
163 | if (ahp) |
164 | *ahp = ah; |
165 | else |
166 | rxe_put(ah); |
167 | |
168 | return &ah->av; |
169 | } |
170 | |
171 | /* only old user provider for UD sends*/ |
172 | return &pkt->wqe->wr.wr.ud.av; |
173 | } |
174 | |