TODO drsuapi compressed
[wireshark-sm.git] / epan / dissectors / packet-lnet.c
blob112dbc07959e8ecf0344b1d2533c0350fa68a080
1 /* packet-lnet.c
2 * Routines for lnet dissection
3 * Copyright (c) 2012, 2013, 2017 Intel Corporation.
5 * Wireshark - Network traffic analyzer
6 * By Gerald Combs <gerald@wireshark.org>
7 * Copyright 1998 Gerald Combs
9 * SPDX-License-Identifier: GPL-2.0-or-later
13 * LNet - Lustre Networking
15 * A network abstraction layer for passing data at near wire-speed.
16 * Supports RDMA where available and run across a variety of network hosts.
18 * http://doc.lustre.org/lustre_manual.xhtml#understandinglustrenetworking
21 #include "config.h"
23 #include <epan/packet.h>
24 #include <epan/expert.h>
25 #include <epan/to_str.h>
26 #include <epan/proto_data.h>
29 #include "packet-tcp.h"
30 #include "packet-lnet.h"
31 VALUE_STRING_ARRAY2(portal_index);
33 void proto_reg_handoff_lnet(void);
34 void proto_register_lnet(void);
36 static dissector_handle_t lnet_handle;
38 /* Initialize the protocol and registered fields */
39 static int proto_lnet;
41 static int hf_lnet_ksm_type;
42 static int hf_lnet_ksm_csum;
43 static int hf_lnet_ksm_zc_req_cookie;
44 static int hf_lnet_ksm_zc_ack_cookie;
46 static int hf_lnet_ib_magic;
47 static int hf_lnet_ib_version;
48 static int hf_lnet_ib_type;
49 static int hf_lnet_ib_credits;
50 static int hf_lnet_ib_nob;
51 static int hf_lnet_ib_csum;
52 static int hf_lnet_ib_srcstamp;
53 static int hf_lnet_ib_dststamp;
55 static int hf_lnet_src_nid;
56 static int hf_lnet_dest_nid;
58 static int hf_lnet_nid_addr;
59 static int hf_lnet_nid_lnet_type;
60 static int hf_lnet_nid_interface;
62 static int hf_lnet_dest_pid;
63 static int hf_lnet_src_pid;
65 static int hf_lnet_msg_type;
66 static int hf_lnet_payload_length;
67 static int hf_lnet_payload;
68 static int hf_lnet_msg_filler;
70 static int hf_dst_wmd_interface;
71 static int hf_dst_wmd_object;
73 static int hf_match_bits;
74 static int hf_mlength;
76 static int hf_hdr_data;
77 static int hf_ptl_index;
78 static int hf_offset;
80 static int hf_src_offset;
81 static int hf_sink_length;
83 static int hf_hello_incarnation;
84 static int hf_hello_type;
86 static int hf_lnet_o2ib_connparam;
87 static int hf_lnet_o2ib_connparam_qdepth;
88 static int hf_lnet_o2ib_connparam_max_frags;
89 static int hf_lnet_o2ib_connparam_max_size;
90 static int hf_lnet_o2ib_cookie;
91 static int hf_lnet_o2ib_src_cookie;
92 static int hf_lnet_o2ib_dest_cookie;
93 static int hf_lnet_o2ib_status;
95 static int hf_lnet_rdma_desc;
96 static int hf_lnet_rdma_desc_key;
97 static int hf_lnet_rdma_desc_nfrags;
99 static int hf_lnet_rdma_frag_size;
100 static int hf_lnet_rdma_frag_addr;
102 /* Initialize the subtree pointers */
103 static int ett_lnet;
104 static int ett_lnet_nid;
105 static int ett_lnet_o2ib_connparams;
106 static int ett_lnet_rdma_desc;
107 static int ett_lnet_rdma_frag;
109 static expert_field ei_lnet_buflen;
110 static expert_field ei_lnet_type;
112 #define LNET_TCP_PORT 988 /* Not IANA registered */
114 #define LNET_HEADER_LEN 52
115 #define LNET_PTL_INDEX_OFFSET_PUT (88 + extra_bytes)
117 #define EXTRA_IB_HEADER_SIZE 24
119 static dissector_table_t subdissector_table;
121 /********************************************************************\
123 * LNet Definitions
125 * NID : Network IDentifiyer
126 * IP@PORT#
127 * e.g. 192.168.1.1@tcp0 or 10.10.10.1@o2ib4
129 \********************************************************************/
131 #define lndnames_VALUE_STRING_LIST(XXX) \
132 XXX(QSWLND, 1) \
133 XXX(SOCKLND, 2) \
134 XXX(GMLND, 3) \
135 XXX(PTLLND, 4) \
136 XXX(O2IBLND, 5) \
137 XXX(CIBLND, 6) \
138 XXX(OPENIBLND, 7) \
139 XXX(IIBLND, 8) \
140 XXX(LOLND, 9) \
141 XXX(RALND, 10) \
142 XXX(VIBLND, 11) \
143 XXX(MXLND, 12) \
144 XXX(GNILND, 13) \
145 XXX(GNIIPLND, 14) \
146 XXX(PTL4LND, 15)
148 VALUE_STRING_ENUM2(lndnames);
149 VALUE_STRING_ARRAY2(lndnames);
151 /* These are the NID protocol names */
152 static const value_string lndprotos[] = {
153 { QSWLND, "elan" }, /* removed v2_7_50 */
154 { SOCKLND, "tcp" },
155 { GMLND, "gm" }, /* removed v2_0_0-rc1a-16-gc660aac */
156 { PTLLND, "ptl" }, /* removed v2_7_50 */
157 { O2IBLND, "o2ib" },
158 { CIBLND, "cib" }, /* removed v2_0_0-rc1a-175-gd2b8a0e */
159 { OPENIBLND, "openib" }, /* removed v2_0_0-rc1a-175-gd2b8a0e */
160 { IIBLND, "iib" }, /* removed v2_0_0-rc1a-175-gd2b8a0e */
161 { LOLND, "lo" },
162 { RALND, "ra" }, /* removed v2_7_50_0-34-g8be9e41 */
163 { VIBLND, "vib" }, /* removed v2_0_0-rc1a-175-gd2b8a0e */
164 { MXLND, "mx" }, /* removed v2_7_50_0-34-g8be9e41 */
165 { GNILND, "gni" },
166 { GNIIPLND, "gip" },
167 { PTL4LND, "ptlf" },
168 { 0, NULL}
171 enum MSG_type {
172 LNET_MSG_ACK = 0,
173 LNET_MSG_PUT,
174 LNET_MSG_GET,
175 LNET_MSG_REPLY,
176 LNET_MSG_HELLO,
179 static const value_string lnet_msg_type[] = {
180 { LNET_MSG_ACK , "ACK"},
181 { LNET_MSG_PUT , "PUT"},
182 { LNET_MSG_GET , "GET"},
183 { LNET_MSG_REPLY, "REPLY"},
184 { LNET_MSG_HELLO, "HELLO"},
185 { 0, NULL}
188 /* PROTO MAGIC for LNDs */
189 #define LNET_PROTO_IB_MAGIC 0x0be91b91
190 #define LNET_PROTO_MAGIC 0x45726963 /* ! */
191 #define LNET_PROTO_PING_MAGIC 0x70696E67 /* 'ping' */
192 #define LNET_PROTO_ACCEPTOR_MAGIC 0xacce7100
193 #define LNET_PROTO_GNI_MAGIC 0xb00fbabe /* ask Kim */
194 #define LNET_PROTO_TCP_MAGIC 0xeebc0ded
196 static const value_string lnet_magic[] = {
197 { LNET_PROTO_IB_MAGIC, "IB_MAGIC" },
198 { LNET_PROTO_MAGIC, "LNET_MAGIC" }, /* place holder */
199 { LNET_PROTO_PING_MAGIC, "PING_MAGIC" },
200 { LNET_PROTO_ACCEPTOR_MAGIC, "ACCEPTOR_MAGIC" },
201 { LNET_PROTO_GNI_MAGIC, "GNI_MAGIC" },
202 { LNET_PROTO_TCP_MAGIC, "TCP_MAGIC" },
203 { 0, NULL }
206 /* SOCKLND constants. */
207 #define ksm_type_VALUE_STRING_LIST(XXX) \
208 XXX(KSOCK_MSG_NOOP, 0xc0) \
209 XXX(KSOCK_MSG_LNET, 0xc1)
211 VALUE_STRING_ENUM2(ksm_type);
212 VALUE_STRING_ARRAY2(ksm_type);
214 static const value_string ib_version_t[] = {
215 {0x11, "1"},
216 {0x12, "2"},
217 {0, NULL}
220 #define lnet_ib_type_VALUE_STRING_LIST(XXX) \
221 XXX(IBLND_MSG_CONNREQ, 0xc0) \
222 XXX(IBLND_MSG_CONNACK, 0xc1) \
223 XXX(IBLND_MSG_NOOP, 0xd0) \
224 XXX(IBLND_MSG_IMMEDIATE, 0xd1) \
225 XXX(IBLND_MSG_PUT_REQ, 0xd2) \
226 XXX(IBLND_MSG_PUT_NAK, 0xd3) \
227 XXX(IBLND_MSG_PUT_ACK, 0xd4) \
228 XXX(IBLND_MSG_PUT_DONE, 0xd5) \
229 XXX(IBLND_MSG_GET_REQ, 0xd6) \
230 XXX(IBLND_MSG_GET_DONE, 0xd7)
232 VALUE_STRING_ENUM2(lnet_ib_type);
233 VALUE_STRING_ARRAY2(lnet_ib_type);
235 /********************************************************************\
237 * LNet Conversation
239 \********************************************************************/
241 typedef struct _lnet_conv_info_t {
242 wmem_map_t *pdus;
243 } lnet_conv_info_t;
245 static struct lnet_trans_info *
246 get_lnet_conv(packet_info *pinfo, uint64_t match_bits) {
247 conversation_t *conversation;
249 struct lnet_trans_info *info;
251 lnet_conv_info_t *conv_info;
253 // Ignore ports because this is kernel level and there can only be one Lustre instance per server
254 conversation = find_conversation(pinfo->num, &pinfo->src, &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype),
255 0, 0, 0);
256 if (conversation == NULL)
257 conversation = conversation_new(pinfo->num, &pinfo->src,
258 &pinfo->dst, conversation_pt_to_conversation_type(pinfo->ptype), 0, 0, 0);
260 conv_info = (lnet_conv_info_t *)conversation_get_proto_data(conversation, proto_lnet);
261 if (!conv_info) {
262 conv_info = wmem_new0(wmem_file_scope(), lnet_conv_info_t);
263 conv_info->pdus = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal);
265 conversation_add_proto_data(conversation, proto_lnet, conv_info);
268 info = (struct lnet_trans_info *)wmem_map_lookup(conv_info->pdus, GUINT_TO_POINTER(match_bits));
269 if (info == NULL) {
270 info = wmem_new0(wmem_file_scope(), struct lnet_trans_info);
271 info->match_bits = match_bits;
272 wmem_map_insert(conv_info->pdus, GUINT_TO_POINTER(info->match_bits), info);
275 return info;
278 /********************************************************************\
280 * LND:O2IB Structures
282 \********************************************************************/
284 static int
285 dissect_struct_o2ib_connparam(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
287 proto_tree *tree;
288 proto_item *item;
290 item = proto_tree_add_item(parent_tree, hf_lnet_o2ib_connparam, tvb, offset, 8, ENC_NA);
291 tree = proto_item_add_subtree(item, ett_lnet_o2ib_connparams);
293 proto_tree_add_item(tree, hf_lnet_o2ib_connparam_qdepth, tvb, offset, 2, ENC_LITTLE_ENDIAN);
294 offset+=2;
295 proto_tree_add_item(tree, hf_lnet_o2ib_connparam_max_frags, tvb, offset, 2, ENC_LITTLE_ENDIAN);
296 offset+=2;
297 proto_tree_add_item(tree, hf_lnet_o2ib_connparam_max_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
298 offset+=4;
299 return offset;
302 /* kib_rdma_desc_t */
303 /* { */
304 /* __u32 rd_key; /\* local/remote key *\/ */
305 /* __u32 rd_nfrags; /\* # fragments *\/ */
306 /* kib_rdma_frag_t rd_frags[0]; /\* buffer frags *\/ */
307 /* }
308 * kib_rdma_frag_t */
309 /* { */
310 /* __u32 rf_nob; /\* # bytes this frag *\/ */
311 /* __u64 rf_addr; /\* CAVEAT EMPTOR: misaligned!! *\/ */
312 /* } */
313 static int
314 dissect_struct_rdma_desc(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
316 proto_tree *tree, *ftree;
317 int old_offset;
318 uint32_t frags, i;
320 proto_item *item;
322 old_offset = offset;
324 item = proto_tree_add_item(parent_tree, hf_lnet_rdma_desc, tvb, offset, -1, ENC_NA);
325 tree = proto_item_add_subtree(item, ett_lnet_rdma_desc);
327 /* @@ SAVE KEY and use to intercept infiniband payload */
328 proto_tree_add_item(tree, hf_lnet_rdma_desc_key, tvb, offset, 4, ENC_LITTLE_ENDIAN);
329 offset += 4;
330 proto_tree_add_item_ret_uint(tree, hf_lnet_rdma_desc_nfrags, tvb, offset, 4, ENC_LITTLE_ENDIAN, &frags);
331 offset += 4;
333 for (i=0; i < frags; ++i) {
334 ftree = proto_tree_add_subtree_format(tree, tvb, offset, 12, ett_lnet_rdma_frag, NULL, "RDMA Fragment [%d]", i);
335 proto_tree_add_item(ftree, hf_lnet_rdma_frag_size, tvb, offset, 4, ENC_LITTLE_ENDIAN);
336 offset += 4;
337 proto_tree_add_item(ftree, hf_lnet_rdma_frag_addr, tvb, offset, 8, ENC_LITTLE_ENDIAN);
338 offset += 8;
341 proto_item_set_len(item, offset-old_offset);
342 return offset;
346 /********************************************************************\
348 * NID Dissection & Healper Function
350 \********************************************************************/
352 // EXPORTED
354 lnet_dissect_struct_nid(tvbuff_t * tvb, proto_tree *parent_tree, int offset, int hf_index)
356 proto_tree *tree;
357 proto_item *item;
358 uint32_t ip, interface, proto;
360 item = proto_tree_add_item(parent_tree, hf_index, tvb, offset, 8, ENC_NA);
361 tree = proto_item_add_subtree(item, ett_lnet_nid);
363 ip = tvb_get_ipv4(tvb, offset);
364 proto_tree_add_item(tree, hf_lnet_nid_addr, tvb, offset, 4, ENC_LITTLE_ENDIAN);
365 offset+=4;
366 proto_tree_add_item_ret_uint(tree, hf_lnet_nid_interface, tvb, offset, 2, ENC_LITTLE_ENDIAN, &interface);
367 offset+=2;
368 proto_tree_add_item_ret_uint(tree, hf_lnet_nid_lnet_type, tvb, offset, 2, ENC_LITTLE_ENDIAN, &proto);
369 offset+=2;
371 if (ip != 0) {
372 address addr;
373 set_address(&addr, AT_IPv4, 4, &ip);
374 proto_item_append_text(item, ": %s@%s%d", address_to_name(&addr), val_to_str(proto, lndprotos, "E(%d)"), interface);
377 return offset;
380 /********************************************************************\
382 * Other Dissection
384 \********************************************************************/
386 static int
387 dissect_csum(tvbuff_t * tvb, packet_info *pinfo, proto_tree *tree, int offset, unsigned lnd_type)
389 uint32_t csum;
390 proto_item *ti;
392 csum = tvb_get_letohl(tvb, offset);
393 // @@ convert this to proto_tree_add_checksum()
394 switch (lnd_type) {
395 case SOCKLND:
396 ti = proto_tree_add_item(tree, hf_lnet_ib_csum, tvb, offset, 4, ENC_LITTLE_ENDIAN);
397 break;
399 case O2IBLND:
400 ti = proto_tree_add_item(tree, hf_lnet_ksm_csum, tvb, offset, 4, ENC_LITTLE_ENDIAN);
401 break;
403 default:
404 ti = proto_tree_add_expert_format(tree, pinfo, &ei_lnet_type, tvb, offset, 4,
405 "Checksum for unprocessed type: %s",
406 val_to_str(lnd_type, lndnames, "Unknown(%d)"));
407 break;
410 if (csum == 0)
411 proto_item_append_text(ti, " (DISABLED)");
413 return offset + 4;
416 /********************************************************************\
418 * Message Type Dissection
420 \********************************************************************/
422 static int
423 dissect_lnet_put(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint64_t *match)
425 /* typedef struct lnet_put {
426 lnet_handle_wire_t ack_wmd;
427 __u64 match_bits;
428 __u64 hdr_data;
429 __u32 ptl_index;
430 __u32 offset;
431 } WIRE_ATTR lnet_put_t; */
432 const char *port;
433 uint32_t ptl_index;
435 proto_tree_add_item(tree, hf_dst_wmd_interface, tvb, offset, 8, ENC_LITTLE_ENDIAN);
436 offset += 8;
437 proto_tree_add_item(tree, hf_dst_wmd_object, tvb, offset, 8, ENC_LITTLE_ENDIAN);
438 offset += 8;
440 proto_tree_add_item_ret_uint64(tree, hf_match_bits, tvb, offset, 8, ENC_LITTLE_ENDIAN, match);
441 offset += 8;
442 proto_tree_add_item(tree, hf_hdr_data, tvb, offset, 8, ENC_LITTLE_ENDIAN);
443 offset += 8;
445 /* print ptl_index */
446 proto_tree_add_item_ret_uint(tree, hf_ptl_index, tvb, offset, 4, ENC_LITTLE_ENDIAN, &ptl_index);
447 offset += 4;
449 port = val_to_str(ptl_index, portal_index, "Unknown(%d)");
450 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", port);
451 proto_item_append_text(tree, ", %s" , port);
453 proto_tree_add_item(tree, hf_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
454 offset += 4;
455 return offset;
458 static int
459 dissect_lnet_get(tvbuff_t * tvb, packet_info *pinfo, proto_tree *tree, int offset, uint64_t *match)
461 /* typedef struct lnet_get {
462 lnet_handle_wire_t return_wmd;
463 __u64 match_bits;
464 __u32 ptl_index;
465 __u32 src_offset;
466 __u32 sink_length;
467 } WIRE_ATTR lnet_get_t;
469 const char *port;
470 uint32_t ptl_index;
472 proto_tree_add_item(tree, hf_dst_wmd_interface, tvb, offset, 8, ENC_LITTLE_ENDIAN);
473 offset += 8;
474 proto_tree_add_item(tree, hf_dst_wmd_object, tvb, offset, 8, ENC_LITTLE_ENDIAN);
475 offset += 8;
476 proto_tree_add_item_ret_uint64(tree, hf_match_bits, tvb, offset, 8, ENC_LITTLE_ENDIAN, match);
477 offset += 8;
479 proto_tree_add_item_ret_uint(tree, hf_ptl_index, tvb, offset, 4, ENC_LITTLE_ENDIAN, &ptl_index);
480 offset += 4;
482 port = val_to_str(ptl_index, portal_index, "Unknown (%d)");
483 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", port);
484 proto_item_append_text(tree, ", %s", port);
486 proto_tree_add_item(tree, hf_src_offset, tvb, offset, 4, ENC_LITTLE_ENDIAN);
487 offset += 4;
488 proto_tree_add_item(tree, hf_sink_length, tvb, offset, 4, ENC_LITTLE_ENDIAN);
489 offset += 4;
490 return offset;
493 static int
494 dissect_lnet_reply(tvbuff_t * tvb, proto_tree *tree, int offset)
496 /* typedef struct lnet_reply {
497 lnet_handle_wire_t dst_wmd;
498 } WIRE_ATTR lnet_reply_t; */
500 proto_tree_add_item(tree, hf_dst_wmd_interface, tvb, offset, 8, ENC_LITTLE_ENDIAN);
501 offset+=8;
502 proto_tree_add_item(tree, hf_dst_wmd_object, tvb, offset, 8, ENC_LITTLE_ENDIAN);
503 offset+=8;
505 return offset;
509 static int
510 dissect_lnet_hello(tvbuff_t * tvb, proto_tree *tree, int offset)
512 /* typedef struct lnet_hello {
513 __u64 incarnation;
514 __u32 type;
515 } WIRE_ATTR lnet_hello_t; */
517 proto_tree_add_item(tree, hf_hello_incarnation, tvb, offset, 8, ENC_LITTLE_ENDIAN);
518 offset+=8;
519 proto_tree_add_item(tree, hf_hello_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
520 offset+=4;
521 return offset;
524 static int
525 dissect_lnet_ack(tvbuff_t * tvb, proto_tree *tree, int offset, uint64_t *match)
527 /* typedef struct lnet_ack {
528 lnet_handle_wire_t dst_wmd;
529 __u64 match_bits;
530 __u32 mlength;
531 } WIRE_ATTR lnet_ack_t; */
533 proto_tree_add_item(tree, hf_dst_wmd_interface, tvb, offset, 8, ENC_NA);
534 offset+=8;
535 proto_tree_add_item(tree, hf_dst_wmd_object, tvb, offset, 8, ENC_NA);
536 offset+=8;
537 proto_tree_add_item_ret_uint64(tree, hf_match_bits, tvb, offset, 8, ENC_LITTLE_ENDIAN, match);
538 offset+=8;
539 proto_tree_add_item(tree, hf_mlength, tvb, offset,4, ENC_LITTLE_ENDIAN);
540 offset+=4;
541 return offset;
544 /********************************************************************\
546 * Dissect Header Functions
548 \********************************************************************/
550 static int
551 dissect_ksock_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset)
553 proto_item *ti;
554 uint64_t val;
556 proto_tree_add_item(tree, hf_lnet_ksm_type, tvb, offset, 4, ENC_LITTLE_ENDIAN);
557 offset += 4;
558 offset = dissect_csum(tvb, pinfo, tree, offset, SOCKLND);
559 ti = proto_tree_add_item_ret_uint64(tree, hf_lnet_ksm_zc_req_cookie, tvb, offset, 8, ENC_LITTLE_ENDIAN, &val);
560 if (val == 0)
561 proto_item_append_text(ti, " (NO ACK REQUIRED)");
562 offset += 8;
563 ti = proto_tree_add_item_ret_uint64(tree, hf_lnet_ksm_zc_ack_cookie, tvb, offset, 8, ENC_LITTLE_ENDIAN, &val);
564 if (val == 0)
565 proto_item_append_text(ti, " (NOT ACK)");
566 offset += 8;
567 return offset;
569 static int
570 dissect_ksock_msg_noop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
572 return dissect_ksock_msg(tvb, pinfo, tree, 0);
575 static int
576 dissect_ib_msg(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int offset, uint32_t *msg_type, uint32_t *msg_length)
578 /* typedef struct
580 * __u32 ibm_magic; * I'm an ibnal message *
581 * __u16 ibm_version; * this is my version *
583 * __u8 ibm_type; * msg type *
584 * __u8 ibm_credits; * returned credits *
585 * __u32 ibm_nob; * # bytes in message *
586 * __u32 ibm_cksum; * checksum (0 == no
587 * checksum) *
588 * __u64 ibm_srcnid; * sender's NID *
589 * __u64 ibm_srcstamp; * sender's incarnation *
590 * __u64 ibm_dstnid; * destination's NID *
591 * __u64 ibm_dststamp; * destination's
592 * incarnation *
594 * union {
595 * kib_connparams_t connparams;
596 * kib_immediate_msg_t immediate;
597 * kib_putreq_msg_t putreq;
598 * kib_putack_msg_t putack;
599 * kib_get_msg_t get;
600 * kib_completion_msg_t completion;
601 * } WIRE_ATTR ibm_u;
602 *} WIRE_ATTR kib_msg_t; */
604 proto_tree_add_item(tree, hf_lnet_ib_magic, tvb, offset, 4, ENC_LITTLE_ENDIAN);
605 offset += 4;
606 proto_tree_add_item(tree, hf_lnet_ib_version, tvb, offset, 2, ENC_LITTLE_ENDIAN);
607 offset += 2;
608 proto_tree_add_item_ret_uint(tree, hf_lnet_ib_type, tvb, offset, 1, ENC_LITTLE_ENDIAN, msg_type);
609 offset += 1;
610 proto_tree_add_item(tree, hf_lnet_ib_credits, tvb, offset, 1, ENC_LITTLE_ENDIAN);
611 offset += 1;
612 proto_tree_add_item_ret_uint(tree, hf_lnet_ib_nob, tvb, offset, 4, ENC_LITTLE_ENDIAN, msg_length);
613 offset += 4;
614 offset = dissect_csum(tvb, pinfo, tree, offset, O2IBLND);
616 offset = lnet_dissect_struct_nid(tvb, tree, offset, hf_lnet_src_nid);
618 proto_tree_add_item(tree, hf_lnet_ib_srcstamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
619 offset += 8;
621 offset = lnet_dissect_struct_nid(tvb, tree, offset, hf_lnet_dest_nid);
623 proto_tree_add_item(tree, hf_lnet_ib_dststamp, tvb, offset, 8, ENC_LITTLE_ENDIAN);
624 offset += 8;
626 /* LNet payloads only exist when the LND msg type is IMMEDIATE.
627 Return a zero offset for all other types. */
628 return offset;
631 /********************************************************************\
633 * Main Packet Dissection
635 \********************************************************************/
636 static int
637 dissect_lnet_message(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data)
639 proto_item *ti;
641 proto_tree *lnet_tree;
642 /* Other misc. local variables. */
643 unsigned offset = 0;
644 uint32_t msg_length = 0;
645 uint32_t payload_length = 0;
646 int32_t msg_filler_length = 0;
648 uint64_t match;
649 uint32_t msg_type = 0;
650 uint32_t ib_msg_type = 0;
651 unsigned extra_bytes = GPOINTER_TO_UINT(data);
652 bool ib_msg_payload = false;
654 col_set_str(pinfo->cinfo, COL_PROTOCOL, "LNET");
655 col_clear(pinfo->cinfo, COL_INFO);
657 ti = proto_tree_add_item(tree, proto_lnet, tvb, 0, -1, ENC_NA);
658 lnet_tree = proto_item_add_subtree(ti, ett_lnet);
660 if (extra_bytes) {
661 offset = dissect_ib_msg(tvb, pinfo, lnet_tree, offset, &ib_msg_type, &msg_length);
663 switch (ib_msg_type) {
664 case IBLND_MSG_CONNREQ:
665 case IBLND_MSG_CONNACK:
666 // kib_connparams_t;
667 col_add_fstr(pinfo->cinfo, COL_INFO, "LNET %s",
668 val_to_str(ib_msg_type, lnet_ib_type, "Unknown(%d)"));
669 offset = dissect_struct_o2ib_connparam(tvb, lnet_tree, offset);
670 msg_filler_length = tvb_reported_length_remaining(tvb, offset);
671 ib_msg_payload = true;
672 break;
674 case IBLND_MSG_NOOP:
675 // No further data
676 col_add_fstr(pinfo->cinfo, COL_INFO, "LNET %s",
677 val_to_str(ib_msg_type, lnet_ib_type, "Unknown(%d)"));
678 ib_msg_payload = true;
679 break;
681 case IBLND_MSG_IMMEDIATE:
682 // Normal LNET Message
683 break;
685 case IBLND_MSG_PUT_REQ:
686 // kib_putreq_msg_t
687 // lnet_hdr + cookie
688 break;
690 case IBLND_MSG_PUT_ACK:
691 // kib_putack_msg_t;
692 // src cookie + dest cookie + rdma_desc_t
693 col_add_fstr(pinfo->cinfo, COL_INFO, "LNET %s",
694 val_to_str(ib_msg_type, lnet_ib_type, "Unknown(%d)"));
695 proto_tree_add_item(lnet_tree, hf_lnet_o2ib_src_cookie, tvb, offset, 8, ENC_LITTLE_ENDIAN);
696 offset+=8;
697 proto_tree_add_item(lnet_tree, hf_lnet_o2ib_dest_cookie, tvb, offset, 8, ENC_LITTLE_ENDIAN);
698 offset+=8;
699 offset = dissect_struct_rdma_desc(tvb, lnet_tree, offset);
700 ib_msg_payload = true;
701 break;
703 case IBLND_MSG_GET_REQ:
704 // kib_get_msg_t
705 // lnet_hdr + cookie + rdma_desc_t
706 break;
708 case IBLND_MSG_PUT_NAK:
709 case IBLND_MSG_PUT_DONE:
710 case IBLND_MSG_GET_DONE:
711 // kib_completion_msg_t;
712 col_add_fstr(pinfo->cinfo, COL_INFO, "LNET %s",
713 val_to_str(ib_msg_type, lnet_ib_type, "Unknown(%d)"));
715 proto_tree_add_item(lnet_tree, hf_lnet_o2ib_cookie, tvb, offset, 8, ENC_LITTLE_ENDIAN);
716 offset+=8;
717 proto_tree_add_item(lnet_tree, hf_lnet_o2ib_status, tvb, offset, 4, ENC_LITTLE_ENDIAN);
718 offset+=4;
719 ib_msg_payload = true;
720 break;
723 } else {
724 /* dissect the first 24 bytes (ksock_msg_t in
725 * lnet/socklnd.h
727 offset = dissect_ksock_msg(tvb, pinfo, lnet_tree, offset);
730 if (!ib_msg_payload) {
731 /* LNET HEADER */
732 offset = lnet_dissect_struct_nid(tvb, lnet_tree, offset, hf_lnet_dest_nid);
733 offset = lnet_dissect_struct_nid(tvb, lnet_tree, offset, hf_lnet_src_nid);
735 /* pid */
736 proto_tree_add_item(lnet_tree, hf_lnet_src_pid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
737 offset += 4;
738 proto_tree_add_item(lnet_tree, hf_lnet_dest_pid, tvb, offset, 4, ENC_LITTLE_ENDIAN);
739 offset += 4;
741 /* put some nice info on lnet line */
742 proto_tree_add_item_ret_uint(lnet_tree, hf_lnet_msg_type, tvb, offset, 4, ENC_LITTLE_ENDIAN, &msg_type);
743 proto_item_append_text(ti, " %s", val_to_str(msg_type, lnet_msg_type, "Unknown(%d)"));
744 col_add_fstr(pinfo->cinfo, COL_INFO, "LNET_%s", val_to_str(msg_type, lnet_msg_type, "Unknown(%d)"));
745 offset += 4;
747 /* payload data (to follow) length :*/
748 proto_tree_add_item_ret_uint(lnet_tree, hf_lnet_payload_length, tvb, offset, 4, ENC_LITTLE_ENDIAN, &payload_length);
749 offset += 4;
751 match = 0;
752 switch (msg_type) {
753 case LNET_MSG_ACK:
754 offset = dissect_lnet_ack(tvb, lnet_tree, offset, &match);
755 break;
756 case LNET_MSG_PUT:
757 offset = dissect_lnet_put(tvb, pinfo, lnet_tree, offset, &match);
758 break;
759 case LNET_MSG_GET:
760 offset = dissect_lnet_get(tvb, pinfo, lnet_tree, offset, &match);
761 break;
762 case LNET_MSG_REPLY:
763 offset = dissect_lnet_reply(tvb, lnet_tree, offset);
764 break;
765 case LNET_MSG_HELLO:
766 offset = dissect_lnet_hello(tvb, lnet_tree, offset);
767 break;
768 default:
769 break;
772 switch (ib_msg_type) {
773 case 0: // not actually an ib_msg
774 break;
775 case IBLND_MSG_PUT_REQ:
776 proto_tree_add_item(lnet_tree, hf_lnet_o2ib_cookie, tvb, offset, 8, ENC_LITTLE_ENDIAN);
777 offset += 8;
778 /*@@ SAVE payload_length with O2IB cookie for IBLND_MSG_PUT_ACK */
779 payload_length = 0;
780 break;
781 case IBLND_MSG_GET_REQ:
782 proto_tree_add_item(lnet_tree, hf_lnet_o2ib_cookie, tvb, offset, 8, ENC_LITTLE_ENDIAN);
783 offset += 8;
784 offset = dissect_struct_rdma_desc(tvb, lnet_tree, offset);
785 break;
788 /* padding */
789 msg_filler_length = 72 - offset + 24 + extra_bytes;
791 if (msg_filler_length > 72)
792 goto out;
794 /* +24 : ksock_message take 24bytes, and already in offset */
797 if (msg_filler_length > 0) {
798 proto_tree_add_item(lnet_tree, hf_lnet_msg_filler, tvb, offset, msg_filler_length, ENC_NA);
799 offset += msg_filler_length;
802 if (payload_length > 0) {
803 tvbuff_t *next_tvb;
804 struct lnet_trans_info *conv;
806 next_tvb = tvb_new_subset_length(tvb, offset, payload_length);
807 switch (msg_type) {
808 case LNET_MSG_PUT:
809 conv = get_lnet_conv(pinfo, match);
811 offset += dissector_try_uint_new(subdissector_table, tvb_get_letohl(tvb, LNET_PTL_INDEX_OFFSET_PUT),
812 next_tvb, pinfo, tree, true, conv);
813 break;
814 default:
815 /* display of payload */
816 proto_tree_add_item(lnet_tree, hf_lnet_payload, tvb, offset, payload_length, ENC_NA);
817 offset += payload_length;
818 break;
822 if (tvb_captured_length(tvb) != offset) {
823 expert_add_info_format(pinfo, ti, &ei_lnet_buflen,
824 "Capture:%d offset:%d (length:%d) msg_type:%d ib_type:%02x",
825 tvb_captured_length(tvb), offset, msg_length, msg_type, ib_msg_type);
827 return offset;
830 /********************************************************************\
832 * Length Functions (these are SOCK LND only)
834 \********************************************************************/
835 #if 0
836 static unsigned
837 get_lnet_ib_pdu_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
839 uint32_t plen;
841 /* Ensure this is an LNET IB segment */
842 if (tvb_get_letohl(tvb, 0) != LNET_PROTO_IB_MAGIC)
843 return 0;
845 /* Get the IB message length (see dissect_ib_msg() for .ibm_nob)
847 plen = tvb_get_letohl(tvb, offset + 8);
849 return plen;
851 #endif
853 static unsigned
854 get_lnet_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, int offset, void *data _U_)
856 uint32_t plen;
857 unsigned extra_bytes = GPOINTER_TO_UINT(data);
859 /* Get the payload length:
860 * 24 = ksm header,
861 * 28 = the rest of the headers
863 plen = tvb_get_letohl(tvb, offset + 28 + 24 + extra_bytes);
865 /* That length doesn't include the header; add that in.
866 * +24 == ksock msg header.. :D
868 return plen + 72 + 24 + extra_bytes;
871 static unsigned
872 get_noop_message_len(packet_info *pinfo _U_, tvbuff_t *tvb _U_,
873 int offset _U_, void *data _U_)
875 return 24;
878 /******************************************************************** \
880 * Core Functions
882 \********************************************************************/
884 static int
885 dissect_lnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
887 switch (tvb_get_letohl(tvb, 0)) {
888 case KSOCK_MSG_NOOP:
889 tcp_dissect_pdus(tvb, pinfo, tree, true, 0,
890 get_noop_message_len,
891 dissect_ksock_msg_noop, GUINT_TO_POINTER(0));
892 break;
893 case KSOCK_MSG_LNET:
894 tcp_dissect_pdus(tvb, pinfo, tree, true, LNET_HEADER_LEN,
895 get_lnet_message_len,
896 dissect_lnet_message, GUINT_TO_POINTER(0));
897 break;
899 return tvb_captured_length(tvb);
902 static bool
903 dissect_lnet_ib_heur(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_)
905 /* We can tell if this is an LNet payload by looking at the first
906 * 32-bit word for our magic number. */
907 if (tvb_captured_length(tvb) < 4 || tvb_get_letohl(tvb, 0) != LNET_PROTO_IB_MAGIC)
908 /* Not an LNet payload. */
909 return false;
911 dissect_lnet_message(tvb, pinfo, tree, GUINT_TO_POINTER(EXTRA_IB_HEADER_SIZE));
912 return true;
915 void
916 proto_register_lnet(void)
918 static hf_register_info hf[] = {
919 { &hf_lnet_ksm_type,
920 { "Type of socklnd message", "lnet.ksm_type", FT_UINT32, BASE_HEX, VALS(ksm_type), 0x0, NULL, HFILL }},
921 { &hf_lnet_ksm_csum,
922 { "Checksum", "lnet.ksm_csum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
923 { &hf_lnet_ksm_zc_req_cookie,
924 { "Ack required", "lnet.ksm_zc_req_cookie", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
925 { &hf_lnet_ksm_zc_ack_cookie,
926 { "Ack", "lnet.ksm_zc_ack_cookie", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
928 /* Infiniband Fields */
929 { &hf_lnet_ib_magic,
930 { "Magic of IB message", "lnet.ib.magic", FT_UINT32, BASE_HEX, VALS(lnet_magic), 0x0, NULL, HFILL} },
931 { &hf_lnet_ib_version,
932 { "Version", "lnet.ib.version", FT_UINT16, BASE_HEX, VALS(ib_version_t), 0x0, NULL, HFILL} },
933 { &hf_lnet_ib_type,
934 { "Type of IB message", "lnet.ib.type", FT_UINT8, BASE_HEX, VALS(lnet_ib_type), 0x0, NULL, HFILL} },
935 { &hf_lnet_ib_credits,
936 { "Returned Credits", "lnet.ib.credits", FT_UINT8, BASE_DEC, NULL, 0x0, NULL, HFILL} },
937 { &hf_lnet_ib_nob,
938 { "Number of Bytes", "lnet.ib.nob", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} },
939 { &hf_lnet_ib_csum,
940 { "Checksum", "lnet.ib_csum", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL} },
941 { &hf_lnet_ib_srcstamp,
942 { "Sender Timestamp", "lnet.ib.srcstamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
943 { &hf_lnet_ib_dststamp,
944 { "Destination Timestamp", "lnet.ib.dststamp", FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0, NULL, HFILL }},
946 { &hf_lnet_src_nid,
947 { "Src nid", "lnet.src_nid", FT_NONE, BASE_NONE, NULL, 0x0, "Source NID", HFILL }},
948 { &hf_lnet_dest_nid,
949 { "Dest nid", "lnet.dest_nid", FT_NONE, BASE_NONE, NULL, 0x0, "Destination NID", HFILL }},
951 { &hf_lnet_nid_addr,
952 { "lnd address", "lnet.nid.addr", FT_IPv4, BASE_NONE, NULL, 0x0, NULL, HFILL }},
953 { &hf_lnet_nid_lnet_type,
954 { "lnd network type", "lnet.nid.type", FT_UINT16, BASE_DEC, VALS(lndnames), 0x0, NULL, HFILL }},
955 { &hf_lnet_nid_interface,
956 { "lnd network interface", "lnet.nid.net_interface", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
958 { &hf_lnet_dest_pid,
959 { "Dest pid", "lnet.dest_pid", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, "Destination pid", HFILL }},
960 { &hf_lnet_src_pid,
961 { "Src pid", "lnet.src_pid", FT_UINT32, BASE_DEC_HEX, NULL, 0x0, "Source nid", HFILL }},
963 { &hf_lnet_msg_type,
964 { "Message type", "lnet.msg_type", FT_UINT32, BASE_DEC, VALS(lnet_msg_type), 0x0, NULL, HFILL }},
965 { &hf_lnet_payload_length,
966 { "Payload length", "lnet.payload_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
967 { &hf_lnet_payload,
968 { "Payload", "lnet.payload", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
970 { &hf_dst_wmd_interface,
971 { "DST MD index interface", "lnet.msg_dst_interface_cookie", FT_UINT64, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
972 { &hf_dst_wmd_object,
973 { "DST MD index object", "lnet.msg_dst_object_cookie", FT_UINT64, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL }},
974 { &hf_match_bits,
975 { "Match bits", "lnet.msg_dst_match_bits", FT_UINT64, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL}},
976 { &hf_mlength,
977 { "Message length", "lnet.msg_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
979 /* Put */
980 { &hf_hdr_data,
981 { "hdr data", "lnet.msg_hdr_data", FT_UINT64, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL}},
982 { &hf_ptl_index,
983 { "ptl index", "lnet.ptl_index", FT_UINT32, BASE_DEC, VALS(portal_index), 0x0, NULL, HFILL}},
984 { &hf_offset,
985 { "offset", "lnet.offset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
987 /* Get*/
988 { &hf_src_offset,
989 { "src offset", "lnet.src_offset", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
990 { &hf_sink_length,
991 { "sink length", "lnet.sink_length", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
993 /* Hello */
994 { &hf_hello_incarnation,
995 { "hello incarnation", "lnet.hello_incarnation", FT_UINT64, BASE_HEX_DEC, NULL, 0x0, NULL, HFILL}},
996 { &hf_hello_type,
997 { "hello type", "lnet.hello_type", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL}},
999 { &hf_lnet_msg_filler,
1000 { "msg filler (padding)", "lnet.ptl_filler", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL}},
1002 /* O2IB Specific */
1003 { &hf_lnet_o2ib_connparam,
1004 { "O2IB ConnParam", "lnet.connparam", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1005 { &hf_lnet_o2ib_connparam_qdepth,
1006 { "Queue Depth", "lnet.connparam.qdepth", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1007 { &hf_lnet_o2ib_connparam_max_frags,
1008 { "Max Fragments", "lnet.connparam.max_frags", FT_UINT16, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1009 { &hf_lnet_o2ib_connparam_max_size,
1010 { "Max Msg Size", "lnet.connparam.max_size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1012 { &hf_lnet_o2ib_cookie,
1013 { "O2IB Cookie", "lnet.o2ib.cookie", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1014 { &hf_lnet_o2ib_src_cookie,
1015 { "O2IB Source Cookie", "lnet.o2ib.src_cookie", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1016 { &hf_lnet_o2ib_dest_cookie,
1017 { "O2IB Dest Cookie", "lnet.o2ib.dest_cookie", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1018 { &hf_lnet_o2ib_status,
1019 { "O2IB Status", "lnet.o2ib.status", FT_INT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1021 { &hf_lnet_rdma_desc,
1022 { "RDMA Description", "lnet.rdma", FT_NONE, BASE_NONE, NULL, 0x0, NULL, HFILL }},
1023 { &hf_lnet_rdma_desc_key,
1024 { "RDMA Key", "lnet.rdma.key", FT_UINT32, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1025 { &hf_lnet_rdma_desc_nfrags,
1026 { "RDMA # of Fragments", "lnet.rdma.nfrags", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1028 { &hf_lnet_rdma_frag_size,
1029 { "RDMA Frag Size (bytes)", "lnet.rdma_frag.size", FT_UINT32, BASE_DEC, NULL, 0x0, NULL, HFILL }},
1030 { &hf_lnet_rdma_frag_addr,
1031 { "RDMA Frag Address", "lnet.rdma_frag.addr", FT_UINT64, BASE_HEX, NULL, 0x0, NULL, HFILL }},
1034 static int *ett[] = {
1035 &ett_lnet,
1036 &ett_lnet_nid,
1037 &ett_lnet_o2ib_connparams,
1038 &ett_lnet_rdma_desc,
1039 &ett_lnet_rdma_frag,
1042 expert_module_t *expert_lnet;
1043 static ei_register_info ei[] = {
1044 { &ei_lnet_buflen,
1045 { "lnet.bad_buflen", PI_MALFORMED, PI_ERROR, "Buffer length mis-match", EXPFILL } },
1046 { &ei_lnet_type,
1047 { "lnet.bad_type", PI_PROTOCOL, PI_ERROR, "LNET Type mis-match", EXPFILL } }
1050 proto_lnet = proto_register_protocol("Lustre Network", "LNet", "lnet");
1052 proto_register_field_array(proto_lnet, hf, array_length(hf));
1053 proto_register_subtree_array(ett, array_length(ett));
1054 expert_lnet = expert_register_protocol(proto_lnet);
1055 expert_register_field_array(expert_lnet, ei, array_length(ei));
1057 lnet_handle = register_dissector("lnet", dissect_lnet, proto_lnet);
1059 subdissector_table = register_dissector_table("lnet.ptl_index", "lnet portal index",
1060 proto_lnet,
1061 FT_UINT32 , BASE_DEC);
1064 void
1065 proto_reg_handoff_lnet(void)
1067 heur_dissector_add("infiniband.payload", dissect_lnet_ib_heur, "LNet over IB",
1068 "lnet_ib", proto_lnet, HEURISTIC_ENABLE);
1069 heur_dissector_add("infiniband.mad.cm.private", dissect_lnet_ib_heur, "LNet over IB CM",
1070 "lnet_ib_cm_private", proto_lnet, HEURISTIC_ENABLE);
1071 dissector_add_for_decode_as("infiniband", lnet_handle);
1072 dissector_add_uint_with_preference("tcp.port", LNET_TCP_PORT, lnet_handle);
1076 * Editor modelines - https://www.wireshark.org/tools/modelines.html
1078 * Local variables:
1079 * c-basic-offset: 4
1080 * tab-width: 8
1081 * indent-tabs-mode: nil
1082 * End:
1084 * vi: set shiftwidth=4 tabstop=8 expandtab:
1085 * :indentSize=4:tabSize=8:noTabs=true: