1 /*
2 * Copyright (c) 2014, Cisco Systems, Inc. All rights reserved.
3 *
4 * LICENSE_BEGIN
5 *
6 * This software is available to you under a choice of one of two
7 * licenses. You may choose to be licensed under the terms of the GNU
8 * General Public License (GPL) Version 2, available from the file
9 * COPYING in the main directory of this source tree, or the
10 * BSD license below:
11 *
12 * Redistribution and use in source and binary forms, with or
13 * without modification, are permitted provided that the following
14 * conditions are met:
15 *
16 * - Redistributions of source code must retain the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer.
19 *
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials
23 * provided with the distribution.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 *
38 * LICENSE_END
39 *
40 *
41 */
42
43 #include <pthread.h>
44
45 #include "usd.h"
46 #include "usd_post.h"
47
48 static int
usd_post_send_one_ud_udp(struct usd_qp * uqp,struct usd_dest * dest,const void * buf,size_t len,uint32_t flags,void * context)49 usd_post_send_one_ud_udp(
50 struct usd_qp *uqp,
51 struct usd_dest *dest,
52 const void *buf,
53 size_t len,
54 uint32_t flags,
55 void *context)
56 {
57 struct usd_qp_impl *qp;
58 struct usd_udp_hdr *hdr;
59 struct usd_wq *wq;
60 uint32_t last_post;
61 uint8_t *copybuf;
62 struct usd_wq_post_info *info;
63
64 qp = to_qpi(uqp);
65 wq = &qp->uq_wq;
66 copybuf = wq->uwq_copybuf + wq->uwq_post_index * USD_SEND_MAX_COPY;
67
68 hdr = (struct usd_udp_hdr *)copybuf;
69 memcpy(hdr, &dest->ds_dest.ds_udp.u_hdr, sizeof(*hdr));
70
71 /* adjust lengths and insert source port */
72 hdr->uh_ip.tot_len = htons(len + sizeof(struct usd_udp_hdr) -
73 sizeof(struct ether_header));
74 hdr->uh_udp.len = htons((sizeof(struct usd_udp_hdr) -
75 sizeof(struct ether_header) -
76 sizeof(struct iphdr)) + len);
77 hdr->uh_udp.source =
78 qp->uq_attrs.uqa_local_addr.ul_addr.ul_udp.u_addr.sin_port;
79
80 last_post = _usd_post_send_two(wq, hdr, sizeof(*hdr), buf, len,
81 USD_SF_ISSET(flags, SIGNAL));
82
83 info = &wq->uwq_post_info[last_post];
84 info->wp_context = context;
85 info->wp_len = len;
86
87 return 0;
88 }
89
90 static int
usd_post_send_one_vlan_ud_udp(struct usd_qp * uqp,struct usd_dest * dest,const void * buf,size_t len,uint16_t vlan,uint32_t flags,void * context)91 usd_post_send_one_vlan_ud_udp(
92 struct usd_qp *uqp,
93 struct usd_dest *dest,
94 const void *buf,
95 size_t len,
96 uint16_t vlan,
97 uint32_t flags,
98 void *context)
99 {
100 struct usd_qp_impl *qp;
101 struct usd_udp_hdr *hdr;
102 struct usd_wq *wq;
103 uint32_t last_post;
104 uint8_t *copybuf;
105 struct usd_wq_post_info *info;
106
107 qp = to_qpi(uqp);
108 wq = &qp->uq_wq;
109 copybuf = wq->uwq_copybuf + wq->uwq_post_index * USD_SEND_MAX_COPY;
110
111 hdr = (struct usd_udp_hdr *)copybuf;
112 memcpy(hdr, &dest->ds_dest.ds_udp.u_hdr, sizeof(*hdr));
113
114 /* adjust lengths and insert source port */
115 hdr->uh_ip.tot_len = htons(len + sizeof(struct usd_udp_hdr) -
116 sizeof(struct ether_header));
117 hdr->uh_udp.len = htons((sizeof(struct usd_udp_hdr) -
118 sizeof(struct ether_header) -
119 sizeof(struct iphdr)) + len);
120 hdr->uh_udp.source =
121 qp->uq_attrs.uqa_local_addr.ul_addr.ul_udp.u_addr.sin_port;
122
123 last_post = _usd_post_send_two_vlan(wq, hdr, sizeof(*hdr), buf, len,
124 USD_SF_ISSET(flags, SIGNAL), vlan);
125
126 info = &wq->uwq_post_info[last_post];
127 info->wp_context = context;
128 info->wp_len = len;
129
130 return 0;
131 }
132
133 static int
usd_post_send_one_copy_ud_udp(struct usd_qp * uqp,struct usd_dest * dest,const void * buf,size_t len,uint32_t flags,void * context)134 usd_post_send_one_copy_ud_udp(
135 struct usd_qp *uqp,
136 struct usd_dest *dest,
137 const void *buf,
138 size_t len,
139 uint32_t flags,
140 void *context)
141 {
142 struct usd_qp_impl *qp;
143 struct usd_udp_hdr *hdr;
144 struct usd_wq *wq;
145 uint8_t *copybuf;
146 uint32_t last_post;
147 struct usd_wq_post_info *info;
148
149 qp = to_qpi(uqp);
150 wq = &qp->uq_wq;
151 copybuf = wq->uwq_copybuf + wq->uwq_post_index * USD_SEND_MAX_COPY;
152
153 hdr = (struct usd_udp_hdr *) copybuf;
154 memcpy(hdr, &dest->ds_dest.ds_udp.u_hdr, sizeof(*hdr));
155 memcpy(hdr + 1, buf, len);
156
157 /* adjust lengths and insert source port */
158 hdr->uh_ip.tot_len = htons(len + sizeof(struct usd_udp_hdr) -
159 sizeof(struct ether_header));
160 hdr->uh_udp.len = htons((sizeof(struct usd_udp_hdr) -
161 sizeof(struct ether_header) -
162 sizeof(struct iphdr)) + len);
163 hdr->uh_udp.source =
164 qp->uq_attrs.uqa_local_addr.ul_addr.ul_udp.u_addr.sin_port;
165
166 last_post =
167 _usd_post_send_one(wq, hdr, len + sizeof(struct usd_udp_hdr),
168 USD_SF_ISSET(flags, SIGNAL));
169
170 info = &wq->uwq_post_info[last_post];
171 info->wp_context = context;
172 info->wp_len = len;
173
174 return 0;
175 }
176
177 static int
usd_post_send_one_prefixed_ud_udp(struct usd_qp * uqp,struct usd_dest * dest,const void * buf,size_t len,uint32_t flags,void * context)178 usd_post_send_one_prefixed_ud_udp(
179 struct usd_qp *uqp,
180 struct usd_dest *dest,
181 const void *buf,
182 size_t len,
183 uint32_t flags,
184 void *context)
185 {
186 struct usd_qp_impl *qp;
187 struct usd_udp_hdr *hdr;
188 struct usd_wq *wq;
189 uint32_t last_post;
190 struct usd_wq_post_info *info;
191
192 qp = to_qpi(uqp);
193 wq = &qp->uq_wq;
194
195 hdr = (struct usd_udp_hdr *) buf - 1;
196 memcpy(hdr, &dest->ds_dest.ds_udp.u_hdr, sizeof(*hdr));
197
198 /* adjust lengths and insert source port */
199 hdr->uh_ip.tot_len = htons(len + sizeof(struct usd_udp_hdr) -
200 sizeof(struct ether_header));
201 hdr->uh_udp.len = htons((sizeof(struct usd_udp_hdr) -
202 sizeof(struct ether_header) -
203 sizeof(struct iphdr)) + len);
204 hdr->uh_udp.source =
205 qp->uq_attrs.uqa_local_addr.ul_addr.ul_udp.u_addr.sin_port;
206
207 last_post =
208 _usd_post_send_one(wq, hdr, len + sizeof(struct usd_udp_hdr),
209 USD_SF_ISSET(flags, SIGNAL));
210
211 info = &wq->uwq_post_info[last_post];
212 info->wp_context = context;
213 info->wp_len = len;
214
215 return 0;
216 }
217
218 /*
219 * 2 WQEs - our header plus user header in 1st one, user packet in 2nd
220 */
221 static int
usd_post_send_two_copy_ud_udp(struct usd_qp * uqp,struct usd_dest * dest,const void * uhdr,size_t uhdrlen,const void * pkt,size_t pktlen,uint32_t flags,void * context)222 usd_post_send_two_copy_ud_udp(
223 struct usd_qp *uqp,
224 struct usd_dest *dest,
225 const void *uhdr,
226 size_t uhdrlen,
227 const void *pkt,
228 size_t pktlen,
229 uint32_t flags,
230 void *context)
231 {
232 struct usd_qp_impl *qp;
233 struct usd_udp_hdr *hdr;
234 struct usd_wq *wq;
235 uint8_t *copybuf;
236 size_t tot_ulen;
237 uint32_t last_post;
238 struct usd_wq_post_info *info;
239
240 qp = to_qpi(uqp);
241 wq = &qp->uq_wq;
242 copybuf = wq->uwq_copybuf + wq->uwq_post_index * USD_SEND_MAX_COPY;
243
244 hdr = (struct usd_udp_hdr *) copybuf;
245 memcpy(hdr, &dest->ds_dest.ds_udp.u_hdr, sizeof(*hdr));
246 memcpy(hdr + 1, uhdr, uhdrlen);
247 memcpy((char *) (hdr + 1) + uhdrlen, pkt, pktlen);
248
249 /* adjust lengths and insert source port */
250 tot_ulen = uhdrlen + pktlen;
251 hdr->uh_ip.tot_len = htons(tot_ulen + sizeof(struct usd_udp_hdr) -
252 sizeof(struct ether_header));
253 hdr->uh_udp.len = htons((sizeof(struct usd_udp_hdr) -
254 sizeof(struct ether_header) -
255 sizeof(struct iphdr)) + tot_ulen);
256 hdr->uh_udp.source =
257 qp->uq_attrs.uqa_local_addr.ul_addr.ul_udp.u_addr.sin_port;
258
259 last_post =
260 _usd_post_send_one(wq, hdr, uhdrlen + sizeof(*hdr) + pktlen,
261 USD_SF_ISSET(flags, SIGNAL));
262
263 info = &wq->uwq_post_info[last_post];
264 info->wp_context = context;
265 info->wp_len = uhdrlen + pktlen;
266
267 return 0;
268 }
269
270 static int
usd_post_send_iov_ud_udp(struct usd_qp * uqp,struct usd_dest * dest,const struct iovec * iov,size_t iov_count,uint32_t flags,void * context)271 usd_post_send_iov_ud_udp(struct usd_qp *uqp,
272 struct usd_dest *dest, const struct iovec* iov,
273 size_t iov_count, uint32_t flags, void *context)
274 {
275 struct usd_qp_impl *qp;
276 struct usd_udp_hdr *hdr;
277 struct usd_wq *wq;
278 uint32_t last_post;
279 uint8_t *copybuf;
280 struct usd_wq_post_info *info;
281 struct iovec send_iov[USD_SEND_MAX_SGE + 1];
282 size_t len;
283 unsigned i;
284
285 qp = to_qpi(uqp);
286 wq = &qp->uq_wq;
287 copybuf = wq->uwq_copybuf + wq->uwq_post_index * USD_SEND_MAX_COPY;
288
289 for (i = 0, len = 0; i < iov_count; i++) {
290 len += iov[i].iov_len;
291 }
292
293 hdr = (struct usd_udp_hdr *)copybuf;
294 memcpy(hdr, &dest->ds_dest.ds_udp.u_hdr, sizeof(*hdr));
295
296 /* adjust lengths and insert source port */
297 hdr->uh_ip.tot_len = htons(len + sizeof(struct usd_udp_hdr) -
298 sizeof(struct ether_header));
299 hdr->uh_udp.len = htons((sizeof(struct usd_udp_hdr) -
300 sizeof(struct ether_header) -
301 sizeof(struct iphdr)) + len);
302 hdr->uh_udp.source =
303 qp->uq_attrs.uqa_local_addr.ul_addr.ul_udp.u_addr.sin_port;
304
305 send_iov[0].iov_base = hdr;
306 send_iov[0].iov_len = sizeof(*hdr);
307 memcpy(&send_iov[1], iov, sizeof(struct iovec) * iov_count);
308
309 last_post = _usd_post_send_iov(wq, send_iov, iov_count + 1,
310 USD_SF_ISSET(flags, SIGNAL));
311 info = &wq->uwq_post_info[last_post];
312 info->wp_context = context;
313 info->wp_len = len;
314
315 return 0;
316 }
317
318 struct usd_qp_ops usd_qp_ops_ud_udp = {
319 .qo_post_send_one = usd_post_send_one_ud_udp,
320 .qo_post_send_one_prefixed = usd_post_send_one_prefixed_ud_udp,
321 .qo_post_send_one_copy = usd_post_send_one_copy_ud_udp,
322 .qo_post_send_two_copy = usd_post_send_two_copy_ud_udp,
323 .qo_post_send_iov = usd_post_send_iov_ud_udp,
324 .qo_post_send_one_vlan = usd_post_send_one_vlan_ud_udp,
325 };
326