Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/infiniband/core/ud_header.c
37212 views
1
/*
2
* Copyright (c) 2004 Topspin Corporation. All rights reserved.
3
* Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
4
*
5
* This software is available to you under a choice of one of two
6
* licenses. You may choose to be licensed under the terms of the GNU
7
* General Public License (GPL) Version 2, available from the file
8
* COPYING in the main directory of this source tree, or the
9
* OpenIB.org BSD license below:
10
*
11
* Redistribution and use in source and binary forms, with or
12
* without modification, are permitted provided that the following
13
* conditions are met:
14
*
15
* - Redistributions of source code must retain the above
16
* copyright notice, this list of conditions and the following
17
* disclaimer.
18
*
19
* - Redistributions in binary form must reproduce the above
20
* copyright notice, this list of conditions and the following
21
* disclaimer in the documentation and/or other materials
22
* provided with the distribution.
23
*
24
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31
* SOFTWARE.
32
*/
33
34
#include <linux/errno.h>
35
#include <linux/string.h>
36
#include <linux/if_ether.h>
37
38
#include <rdma/ib_pack.h>
39
40
#define STRUCT_FIELD(header, field) \
41
.struct_offset_bytes = offsetof(struct ib_unpacked_ ## header, field), \
42
.struct_size_bytes = sizeof ((struct ib_unpacked_ ## header *) 0)->field, \
43
.field_name = #header ":" #field
44
45
static const struct ib_field lrh_table[] = {
46
{ STRUCT_FIELD(lrh, virtual_lane),
47
.offset_words = 0,
48
.offset_bits = 0,
49
.size_bits = 4 },
50
{ STRUCT_FIELD(lrh, link_version),
51
.offset_words = 0,
52
.offset_bits = 4,
53
.size_bits = 4 },
54
{ STRUCT_FIELD(lrh, service_level),
55
.offset_words = 0,
56
.offset_bits = 8,
57
.size_bits = 4 },
58
{ RESERVED,
59
.offset_words = 0,
60
.offset_bits = 12,
61
.size_bits = 2 },
62
{ STRUCT_FIELD(lrh, link_next_header),
63
.offset_words = 0,
64
.offset_bits = 14,
65
.size_bits = 2 },
66
{ STRUCT_FIELD(lrh, destination_lid),
67
.offset_words = 0,
68
.offset_bits = 16,
69
.size_bits = 16 },
70
{ RESERVED,
71
.offset_words = 1,
72
.offset_bits = 0,
73
.size_bits = 5 },
74
{ STRUCT_FIELD(lrh, packet_length),
75
.offset_words = 1,
76
.offset_bits = 5,
77
.size_bits = 11 },
78
{ STRUCT_FIELD(lrh, source_lid),
79
.offset_words = 1,
80
.offset_bits = 16,
81
.size_bits = 16 }
82
};
83
84
static const struct ib_field eth_table[] = {
85
{ STRUCT_FIELD(eth, dmac_h),
86
.offset_words = 0,
87
.offset_bits = 0,
88
.size_bits = 32 },
89
{ STRUCT_FIELD(eth, dmac_l),
90
.offset_words = 1,
91
.offset_bits = 0,
92
.size_bits = 16 },
93
{ STRUCT_FIELD(eth, smac_h),
94
.offset_words = 1,
95
.offset_bits = 16,
96
.size_bits = 16 },
97
{ STRUCT_FIELD(eth, smac_l),
98
.offset_words = 2,
99
.offset_bits = 0,
100
.size_bits = 32 },
101
{ STRUCT_FIELD(eth, type),
102
.offset_words = 3,
103
.offset_bits = 0,
104
.size_bits = 16 }
105
};
106
107
static const struct ib_field vlan_table[] = {
108
{ STRUCT_FIELD(vlan, tag),
109
.offset_words = 0,
110
.offset_bits = 0,
111
.size_bits = 16 },
112
{ STRUCT_FIELD(vlan, type),
113
.offset_words = 0,
114
.offset_bits = 16,
115
.size_bits = 16 }
116
};
117
118
static const struct ib_field grh_table[] = {
119
{ STRUCT_FIELD(grh, ip_version),
120
.offset_words = 0,
121
.offset_bits = 0,
122
.size_bits = 4 },
123
{ STRUCT_FIELD(grh, traffic_class),
124
.offset_words = 0,
125
.offset_bits = 4,
126
.size_bits = 8 },
127
{ STRUCT_FIELD(grh, flow_label),
128
.offset_words = 0,
129
.offset_bits = 12,
130
.size_bits = 20 },
131
{ STRUCT_FIELD(grh, payload_length),
132
.offset_words = 1,
133
.offset_bits = 0,
134
.size_bits = 16 },
135
{ STRUCT_FIELD(grh, next_header),
136
.offset_words = 1,
137
.offset_bits = 16,
138
.size_bits = 8 },
139
{ STRUCT_FIELD(grh, hop_limit),
140
.offset_words = 1,
141
.offset_bits = 24,
142
.size_bits = 8 },
143
{ STRUCT_FIELD(grh, source_gid),
144
.offset_words = 2,
145
.offset_bits = 0,
146
.size_bits = 128 },
147
{ STRUCT_FIELD(grh, destination_gid),
148
.offset_words = 6,
149
.offset_bits = 0,
150
.size_bits = 128 }
151
};
152
153
static const struct ib_field bth_table[] = {
154
{ STRUCT_FIELD(bth, opcode),
155
.offset_words = 0,
156
.offset_bits = 0,
157
.size_bits = 8 },
158
{ STRUCT_FIELD(bth, solicited_event),
159
.offset_words = 0,
160
.offset_bits = 8,
161
.size_bits = 1 },
162
{ STRUCT_FIELD(bth, mig_req),
163
.offset_words = 0,
164
.offset_bits = 9,
165
.size_bits = 1 },
166
{ STRUCT_FIELD(bth, pad_count),
167
.offset_words = 0,
168
.offset_bits = 10,
169
.size_bits = 2 },
170
{ STRUCT_FIELD(bth, transport_header_version),
171
.offset_words = 0,
172
.offset_bits = 12,
173
.size_bits = 4 },
174
{ STRUCT_FIELD(bth, pkey),
175
.offset_words = 0,
176
.offset_bits = 16,
177
.size_bits = 16 },
178
{ RESERVED,
179
.offset_words = 1,
180
.offset_bits = 0,
181
.size_bits = 8 },
182
{ STRUCT_FIELD(bth, destination_qpn),
183
.offset_words = 1,
184
.offset_bits = 8,
185
.size_bits = 24 },
186
{ STRUCT_FIELD(bth, ack_req),
187
.offset_words = 2,
188
.offset_bits = 0,
189
.size_bits = 1 },
190
{ RESERVED,
191
.offset_words = 2,
192
.offset_bits = 1,
193
.size_bits = 7 },
194
{ STRUCT_FIELD(bth, psn),
195
.offset_words = 2,
196
.offset_bits = 8,
197
.size_bits = 24 }
198
};
199
200
static const struct ib_field deth_table[] = {
201
{ STRUCT_FIELD(deth, qkey),
202
.offset_words = 0,
203
.offset_bits = 0,
204
.size_bits = 32 },
205
{ RESERVED,
206
.offset_words = 1,
207
.offset_bits = 0,
208
.size_bits = 8 },
209
{ STRUCT_FIELD(deth, source_qpn),
210
.offset_words = 1,
211
.offset_bits = 8,
212
.size_bits = 24 }
213
};
214
215
/**
216
* ib_ud_header_init - Initialize UD header structure
217
* @payload_bytes:Length of packet payload
218
* @lrh_present: specify if LRH is present
219
* @eth_present: specify if Eth header is present
220
* @vlan_present: packet is tagged vlan
221
* @grh_present:GRH flag (if non-zero, GRH will be included)
222
* @immediate_present: specify if immediate data is present
223
* @header:Structure to initialize
224
*/
225
void ib_ud_header_init(int payload_bytes,
226
int lrh_present,
227
int eth_present,
228
int vlan_present,
229
int grh_present,
230
int immediate_present,
231
struct ib_ud_header *header)
232
{
233
memset(header, 0, sizeof *header);
234
235
if (lrh_present) {
236
u16 packet_length;
237
238
header->lrh.link_version = 0;
239
header->lrh.link_next_header =
240
grh_present ? IB_LNH_IBA_GLOBAL : IB_LNH_IBA_LOCAL;
241
packet_length = (IB_LRH_BYTES +
242
IB_BTH_BYTES +
243
IB_DETH_BYTES +
244
(grh_present ? IB_GRH_BYTES : 0) +
245
payload_bytes +
246
4 + /* ICRC */
247
3) / 4; /* round up */
248
header->lrh.packet_length = cpu_to_be16(packet_length);
249
}
250
251
if (vlan_present)
252
header->eth.type = cpu_to_be16(ETH_P_8021Q);
253
254
if (grh_present) {
255
header->grh.ip_version = 6;
256
header->grh.payload_length =
257
cpu_to_be16((IB_BTH_BYTES +
258
IB_DETH_BYTES +
259
payload_bytes +
260
4 + /* ICRC */
261
3) & ~3); /* round up */
262
header->grh.next_header = 0x1b;
263
}
264
265
if (immediate_present)
266
header->bth.opcode = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE;
267
else
268
header->bth.opcode = IB_OPCODE_UD_SEND_ONLY;
269
header->bth.pad_count = (4 - payload_bytes) & 3;
270
header->bth.transport_header_version = 0;
271
272
header->lrh_present = lrh_present;
273
header->eth_present = eth_present;
274
header->vlan_present = vlan_present;
275
header->grh_present = grh_present;
276
header->immediate_present = immediate_present;
277
}
278
EXPORT_SYMBOL(ib_ud_header_init);
279
280
/**
281
* ib_ud_header_pack - Pack UD header struct into wire format
282
* @header:UD header struct
283
* @buf:Buffer to pack into
284
*
285
* ib_ud_header_pack() packs the UD header structure @header into wire
286
* format in the buffer @buf.
287
*/
288
int ib_ud_header_pack(struct ib_ud_header *header,
289
void *buf)
290
{
291
int len = 0;
292
293
if (header->lrh_present) {
294
ib_pack(lrh_table, ARRAY_SIZE(lrh_table),
295
&header->lrh, buf + len);
296
len += IB_LRH_BYTES;
297
}
298
if (header->eth_present) {
299
ib_pack(eth_table, ARRAY_SIZE(eth_table),
300
&header->eth, buf + len);
301
len += IB_ETH_BYTES;
302
}
303
if (header->vlan_present) {
304
ib_pack(vlan_table, ARRAY_SIZE(vlan_table),
305
&header->vlan, buf + len);
306
len += IB_VLAN_BYTES;
307
}
308
if (header->grh_present) {
309
ib_pack(grh_table, ARRAY_SIZE(grh_table),
310
&header->grh, buf + len);
311
len += IB_GRH_BYTES;
312
}
313
314
ib_pack(bth_table, ARRAY_SIZE(bth_table),
315
&header->bth, buf + len);
316
len += IB_BTH_BYTES;
317
318
ib_pack(deth_table, ARRAY_SIZE(deth_table),
319
&header->deth, buf + len);
320
len += IB_DETH_BYTES;
321
322
if (header->immediate_present) {
323
memcpy(buf + len, &header->immediate_data, sizeof header->immediate_data);
324
len += sizeof header->immediate_data;
325
}
326
327
return len;
328
}
329
EXPORT_SYMBOL(ib_ud_header_pack);
330
331
/**
332
* ib_ud_header_unpack - Unpack UD header struct from wire format
333
* @header:UD header struct
334
* @buf:Buffer to pack into
335
*
336
* ib_ud_header_pack() unpacks the UD header structure @header from wire
337
* format in the buffer @buf.
338
*/
339
int ib_ud_header_unpack(void *buf,
340
struct ib_ud_header *header)
341
{
342
ib_unpack(lrh_table, ARRAY_SIZE(lrh_table),
343
buf, &header->lrh);
344
buf += IB_LRH_BYTES;
345
346
if (header->lrh.link_version != 0) {
347
printk(KERN_WARNING "Invalid LRH.link_version %d\n",
348
header->lrh.link_version);
349
return -EINVAL;
350
}
351
352
switch (header->lrh.link_next_header) {
353
case IB_LNH_IBA_LOCAL:
354
header->grh_present = 0;
355
break;
356
357
case IB_LNH_IBA_GLOBAL:
358
header->grh_present = 1;
359
ib_unpack(grh_table, ARRAY_SIZE(grh_table),
360
buf, &header->grh);
361
buf += IB_GRH_BYTES;
362
363
if (header->grh.ip_version != 6) {
364
printk(KERN_WARNING "Invalid GRH.ip_version %d\n",
365
header->grh.ip_version);
366
return -EINVAL;
367
}
368
if (header->grh.next_header != 0x1b) {
369
printk(KERN_WARNING "Invalid GRH.next_header 0x%02x\n",
370
header->grh.next_header);
371
return -EINVAL;
372
}
373
break;
374
375
default:
376
printk(KERN_WARNING "Invalid LRH.link_next_header %d\n",
377
header->lrh.link_next_header);
378
return -EINVAL;
379
}
380
381
ib_unpack(bth_table, ARRAY_SIZE(bth_table),
382
buf, &header->bth);
383
buf += IB_BTH_BYTES;
384
385
switch (header->bth.opcode) {
386
case IB_OPCODE_UD_SEND_ONLY:
387
header->immediate_present = 0;
388
break;
389
case IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE:
390
header->immediate_present = 1;
391
break;
392
default:
393
printk(KERN_WARNING "Invalid BTH.opcode 0x%02x\n",
394
header->bth.opcode);
395
return -EINVAL;
396
}
397
398
if (header->bth.transport_header_version != 0) {
399
printk(KERN_WARNING "Invalid BTH.transport_header_version %d\n",
400
header->bth.transport_header_version);
401
return -EINVAL;
402
}
403
404
ib_unpack(deth_table, ARRAY_SIZE(deth_table),
405
buf, &header->deth);
406
buf += IB_DETH_BYTES;
407
408
if (header->immediate_present)
409
memcpy(&header->immediate_data, buf, sizeof header->immediate_data);
410
411
return 0;
412
}
413
EXPORT_SYMBOL(ib_ud_header_unpack);
414
415