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