Whamcloud - gitweb
9fc4307b245e31fb33195761a6820c07c1dffd69
[fs/lustre-release.git] / lustre / contrib / wireshark / packet-lnet.c
1 /* packet-lnet.c 
2  * Lnet packet dissection 
3  * Author: Laurent George <george@ocre.cea.fr>
4  * based on packet-agentx.c and packet-afs.c
5  * 20080903
6  *
7  * Wireshark - Network traffic analyzer
8  * By Gerald Combs <gerald@wireshark.org>
9  * Copyright 1999 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * Copyright (c) 2012, 2013, Intel Corporation.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <ctype.h>
35 #include <time.h>
36 #include <string.h>
37 #include <glib.h>
38
39 #include <epan/packet.h>
40 #include <epan/conversation.h>
41 #include <epan/prefs.h>
42 #include <epan/emem.h>
43
44 #include <epan/dissectors/packet-tcp.h>
45 #include <epan/dissectors/packet-infiniband.h>
46
47 /* This value inidcates whether we are processing an Infiniband packet, or
48    TCP.  It gets set to the extra bytes the IB header requires if IB,
49    or zero if TCP. */
50 static guint ib_lnd_extra_bytes;
51
52 /* How much data has at least to be available to be able to determine the
53  * length of the lnet message.
54  * Note: This is only used for TCP-based LNet packets.  Not used for Infiniband.
55  */
56 #define LNET_HEADER_LEN 52
57 #define LNET_NID_DEST_OFFSET (24 + ib_lnd_extra_bytes)
58 #define LNET_NID_SRC_OFFSET (32 + ib_lnd_extra_bytes)
59 #define LNET_MSG_TYPE_OFFSET (48 + ib_lnd_extra_bytes)
60 #define LNET_PTL_INDEX_OFFSET_PUT (88 + ib_lnd_extra_bytes)
61
62 #define EXTRA_IB_HEADER_SIZE 24
63
64 /* TCP ports used for LNet. */
65 static guint global_lnet_tcp_port = 988;
66 static guint lnet_tcp_port = 988;
67
68 void proto_reg_handoff_lnet(void);
69
70 /* Define the lnet proto */
71 static int proto_lnet = -1;
72
73 static int hf_lnet_src_nid = -1 ;
74 static int hf_lnet_src_nid_addr = -1 ;
75 static int hf_lnet_src_nid_lnet_type = -1;
76 static int hf_lnet_src_nid_interface = -1  ;
77
78 static int hf_lnet_ksm_type = -1;
79 static int hf_lnet_ksm_csum = -1;
80 static int hf_lnet_ksm_zc_req_cookie = -1;
81 static int hf_lnet_ksm_zc_ack_cookie = -1;
82
83 static int hf_lnet_ib_magic = -1;
84 static int hf_lnet_ib_version = -1;
85 static int hf_lnet_ib_type = -1;
86 static int hf_lnet_ib_credits = -1;
87 static int hf_lnet_ib_nob = -1;
88 static int hf_lnet_ib_csum = -1;
89 static int hf_lnet_ib_srcstamp = -1;
90 static int hf_lnet_ib_dststamp = -1;
91
92 static int hf_lnet_dest_nid = -1 ;
93 static int hf_lnet_dest_nid_addr = -1 ;
94 static int hf_lnet_dest_nid_lnet_type = -1 ; 
95 static int hf_lnet_dest_nid_interface = -1 ;
96
97 static int hf_lnet_dest_pid = -1 ; 
98 static int hf_lnet_src_pid = -1 ;
99
100 static int hf_lnet_msg_type = -1 ;
101 static int hf_lnet_payload_length = -1;
102 static int hf_lnet_payload = -1 ;
103 static int hf_lnet_msg_header = -1 ; 
104 static int hf_lnet_msg_filler = -1 ;
105
106 static int hf_dst_wmd = -1 ;   
107 static int hf_dst_wmd_interface = -1 ;   
108 static int hf_dst_wmd_object = -1 ;   
109
110 static int hf_match_bits = -1 ; 
111 static int hf_mlength = -1 ; 
112
113 static int hf_hdr_data = -1 ;
114 static int hf_ptl_index = -1 ;
115 static int hf_offset = -1 ;
116 static gint ett_lnet = -1;
117
118 static int hf_src_offset = -1;
119 static int hf_sink_length = -1;
120
121 static int hf_hello_incarnation = -1 ;
122 static int hf_hello_type = -1 ; 
123
124 static gint ett_lnet_dest_nid= -1;
125 static gint ett_lnet_src_nid= -1;
126
127 tvbuff_t *next_tvb;
128
129 /* Breakdown of a NID. */
130 typedef struct t_nid {
131         guint32 addr;
132         guint16 interface;
133         guint16 proto;
134 } t_nid ;
135
136 /*static heur_dissector_list_t heur_subdissector_list; */
137 static dissector_table_t subdissector_table;
138
139 static const value_string lndnames[] = {
140         { 1, "QSWLND   "},
141         { 2, "SOCKLND  "},
142         { 3, "GMLND    "},
143         { 4, "PTLLND   "},
144         { 5, "O2IBLND  "},
145         { 6, "CIBLND   "},
146         { 7, "OPENIBLND"}, 
147         { 8, "IIBLND   "},
148         { 9, "LOLND    "},
149         { 10,"RALND    "},
150         { 11,"VIBLND   "},
151         { 12,"MXLND    "} 
152 };
153
154 enum MSG_type{
155         LNET_MSG_ACK = 0,
156         LNET_MSG_PUT,
157         LNET_MSG_GET,
158         LNET_MSG_REPLY,
159         LNET_MSG_HELLO,
160 } ;
161
162 static const value_string lnet_msg_type_t[] = {
163         { LNET_MSG_ACK  , "ACK"},  
164         { LNET_MSG_PUT  , "PUT"},  
165         { LNET_MSG_GET  , "GET"},  
166         { LNET_MSG_REPLY, "REPLY"},  
167         { LNET_MSG_HELLO, "HELLO"} 
168 };
169
170 /* Port Index numbers.  Defined in lustre/include/lustre/lustre_idl.h */
171 static const value_string portal_indices[] = {
172         { 0 , "LNET_RESERVED_PORTAL"},
173         { 1 , "CONNMGR_REQUEST_PORTAL"},
174         { 2 , "CONNMGR_REPLY_PORTAL"},
175         { 3 , "OSC_REQUEST_PORTAL(obsolete)"},
176         { 4 , "OSC_REPLY_PORTAL"},
177         { 5 , "OSC_BULK_PORTAL(obsolete)"},
178         { 6 , "OST_IO_PORTAL"},
179         { 7 , "OST_CREATE_PORTAL"},
180         { 8 , "OST_BULK_PORTAL"},
181         { 9 , "MDC_REQUEST_PORTAL(obsolete)"},
182         { 10 , "MDC_REPLY_PORTAL"},
183         { 11 , "MDC_BULK_PORTAL(obsolete)"},
184         { 12 , "MDS_REQUEST_PORTAL"},
185         { 13 , "MDS_REPLY_PORTAL(obsolete)"},
186         { 14 , "MDS_BULK_PORTAL"},
187         { 15 , "LDLM_CB_REQUEST_PORTAL"},
188         { 16 , "LDLM_CB_REPLY_PORTAL"},
189         { 17 , "LDLM_CANCEL_REQUEST_PORTAL"},
190         { 18 , "LDLM_CANCEL_REPLY_PORTAL"},
191         { 19 , "PTLBD_REQUEST_PORTAL(obsolete)"},
192         { 20 , "PTLBD_REPLY_PORTAL(obsolete)"},
193         { 21 , "PTLBD_BULK_PORTAL(obsolete)"},
194         { 22 , "MDS_SETATTR_PORTAL"},
195         { 23 , "MDS_READPAGE_PORTAL"},
196         { 24 , "MDS_MDS_PORTAL"},
197         { 25 , "MGC_REPLY_PORTAL"},
198         { 26 , "MGS_REQUEST_PORTAL"},
199         { 27 , "MGS_REPLY_PORTAL"},
200         { 28 , "OST_REQUEST_PORTAL"},
201         { 29 , "FLD_REQUEST_PORTAL"},
202         { 30 , "SEQ_METADATA_PORTAL"},
203         { 31 , "SEQ_DATA_PORTAL"},
204         { 32 , "SEQ_CONTROLLER_PORTAL"},
205         { 33 , "MGS_BULK_PORTAL"},
206         { 50 , "SRPC_REQUEST_PORTAL"},
207         { 51 , "SRPC_FRAMEWORK_REQUEST_PORTAL"},
208         { 52 , "SRPC_RDMA_PORTAL"}
209 };
210
211 /* SOCKLND constants. */
212 #define KSOCK_MSG_NOOP          0xc0            /* ksm_u empty */ 
213 #define KSOCK_MSG_LNET          0xc1            /* lnet msg */
214
215 static const value_string ksm_type_t[] = {
216         {0xc0, "KSOCK_MSG_NOOP"},/* ksm_u empty */ 
217         {0xc1, "KSOCK_MSG_LNET"} /* lnet msg */
218 };
219
220 /* O2IBLND constants. */
221 #define LNET_PROTO_IB_MAGIC     0x0be91b91
222
223 static const value_string ib_version_t[] = {
224         {0x11, "1"},
225         {0x12, "2"}
226 };
227
228 #define IBLND_MSG_CONNREQ       0xc0    /* connection request */
229 #define IBLND_MSG_CONNACK       0xc1    /* connection acknowledge */
230 #define IBLND_MSG_NOOP          0xd0    /* nothing (just credits) */
231 #define IBLND_MSG_IMMEDIATE     0xd1    /* immediate */
232 #define IBLND_MSG_PUT_REQ       0xd2    /* putreq (src->sink) */
233 #define IBLND_MSG_PUT_NAK       0xd3    /* completion (sink->src) */
234 #define IBLND_MSG_PUT_ACK       0xd4    /* putack (sink->src) */
235 #define IBLND_MSG_PUT_DONE      0xd5    /* completion (src->sink) */
236 #define IBLND_MSG_GET_REQ       0xd6    /* getreq (sink->src) */
237 #define IBLND_MSG_GET_DONE      0xd7    /* completion (src->sink: all OK) */
238
239 static const value_string ib_type_t[] = {
240         {0xc0, "IBLND_MSG_CONNREQ"},
241         {0xc1, "IBLND_MSG_CONNACK"},
242         {0xd0, "IBLND_MSG_NOOP"},
243         {0xd1, "IBLND_MSG_IMMEDIATE"},
244         {0xd2, "IBLND_MSG_PUT_REQ"},
245         {0xd3, "IBLND_MSG_PUT_NAK"},
246         {0xd4, "IBLND_MSG_PUT_ACK"},
247         {0xd5, "IBLND_MSG_PUT_DONE"},
248         {0xd6, "IBLND_MSG_GET_REQ"},
249         {0xd7, "IBLND_MSG_GET_DONE"}
250 };
251
252 static gboolean little_endian = TRUE;
253
254 #ifndef ENABLE_STATIC
255 const gchar version[] = VERSION;
256
257 /* Start the functions we need for the plugin stuff */
258
259 void
260 plugin_register(void)
261 {
262         extern void proto_register_lnet(void);
263
264         proto_register_lnet();
265 }
266
267 void
268 plugin_reg_handoff(void)
269 {
270         extern void proto_reg_handoff_lnet(void);
271
272         proto_reg_handoff_lnet();
273 }
274 #endif
275
276 static t_nid
277 get_nid(tvbuff_t *tvb, gint offset)
278 {
279         t_nid nid ;
280
281         nid.addr = g_htonl(tvb_get_ipv4(tvb, offset));
282         nid.interface = tvb_get_letohs(tvb, offset + 4);
283         nid.proto = tvb_get_letohs(tvb, offset + 6);
284         return nid ;
285 }
286
287 static int dissect_csum(tvbuff_t * tvb, proto_tree *tree, int offset)
288 {
289         guint32 csum;
290         csum = tvb_get_letohl(tvb, offset);
291         if (!csum)
292                 proto_tree_add_text(tree, tvb, offset, 4, "Checksum Disabled");
293         else {
294                 if (ib_lnd_extra_bytes)
295                         proto_tree_add_item(tree, hf_lnet_ib_csum, tvb, offset,
296                                             4, little_endian);
297                 else
298                         proto_tree_add_item(tree, hf_lnet_ksm_csum, tvb, offset,
299                                             4, little_endian);
300         }
301
302         return offset + 4;
303 }
304
305
306 static int dissect_req_cookie(tvbuff_t * tvb, proto_tree *tree, int offset)
307 {
308         guint32 req;
309         req= tvb_get_letoh64(tvb, offset);
310         if (!req)
311                 proto_tree_add_text(tree, tvb, offset, 8, "Ack not required");
312         else
313                 proto_tree_add_item(tree, hf_lnet_ksm_zc_req_cookie, tvb, offset, 8, little_endian);
314         return offset + 8;
315 }
316
317 static int dissect_ack_cookie(tvbuff_t * tvb, proto_tree *tree, int offset)
318 {
319         guint32 ack;
320         ack= tvb_get_letoh64(tvb, offset);
321         if (!ack)
322                 proto_tree_add_text(tree, tvb, offset, 8, "Not ack");
323         else
324                 proto_tree_add_item(tree, hf_lnet_ksm_zc_ack_cookie, tvb, offset, 8, little_endian);
325         return offset + 8;
326 }
327
328 static void 
329 dissect_ksock_msg_noop( tvbuff_t * tvb, packet_info *pinfo, proto_tree *tree)
330 {
331         guint32 offset;
332         offset=0;
333         proto_tree_add_item(tree, hf_lnet_ksm_type, tvb, offset, 4, TRUE);offset+=4;
334         offset=dissect_csum(tvb,tree,offset);
335         offset=dissect_req_cookie(tvb, tree, offset);
336         offset=dissect_ack_cookie(tvb,tree,offset);
337 }
338
339
340 static int dissect_ksock_msg(tvbuff_t * tvb, proto_tree *tree, int offset)
341 {
342         proto_tree_add_item(tree, hf_lnet_ksm_type, tvb, offset, 4, TRUE);offset+=4;
343         offset=dissect_csum(tvb,tree,offset);
344         offset=dissect_req_cookie(tvb, tree, offset);
345         offset=dissect_ack_cookie(tvb,tree,offset);
346         return offset;
347 }
348
349 static int
350 dissect_ib_msg(tvbuff_t *tvb, proto_tree *tree, int offset)
351 {
352         /* typedef struct
353          * {
354          *      __u32             ibm_magic;            * I'm an ibnal message *
355          *      __u16             ibm_version;          * this is my version *
356
357          *      __u8              ibm_type;             * msg type *
358          *      __u8              ibm_credits;          * returned credits *
359          *      __u32             ibm_nob;              * # bytes in message *
360          *      __u32             ibm_cksum;            * checksum (0 == no
361          *                                                checksum) *
362          *      __u64             ibm_srcnid;           * sender's NID *
363          *      __u64             ibm_srcstamp;         * sender's incarnation *
364          *      __u64             ibm_dstnid;           * destination's NID *
365          *      __u64             ibm_dststamp;         * destination's
366          *                                                incarnation *
367
368          *      union {
369          *              kib_connparams_t      connparams;
370          *              kib_immediate_msg_t   immediate;
371          *              kib_putreq_msg_t      putreq;
372          *              kib_putack_msg_t      putack;
373          *              kib_get_msg_t         get;
374          *              kib_completion_msg_t  completion;
375          *      } WIRE_ATTR ibm_u;
376          *} WIRE_ATTR kib_msg_t;   */
377
378         t_nid src_nid;
379         t_nid dst_nid;
380         guint8 msg_type;
381
382         proto_tree_add_item(tree, hf_lnet_ib_magic, tvb, offset, 4,
383                             little_endian);
384         offset += 4;
385         proto_tree_add_item(tree, hf_lnet_ib_version, tvb, offset, 2,
386                             little_endian);
387         offset += 2;
388         msg_type = tvb_get_guint8(tvb, offset);
389         proto_tree_add_item(tree, hf_lnet_ib_type, tvb, offset, 1,
390                             little_endian);
391         offset += 1;
392         proto_tree_add_item(tree, hf_lnet_ib_credits, tvb, offset, 1,
393                             little_endian);
394         offset += 1;
395         proto_tree_add_item(tree, hf_lnet_ib_nob, tvb, offset, 4,
396                             little_endian);
397         offset += 4;
398         offset = dissect_csum(tvb, tree, offset);
399
400         src_nid = get_nid(tvb, offset);
401         proto_tree_add_text(tree, tvb, offset, 8, "src_nid = %s@tcp%d",
402                             ip_to_str((guint8 *) &src_nid.addr),
403                             src_nid.interface);
404         offset += 8;
405         proto_tree_add_item(tree, hf_lnet_ib_srcstamp, tvb, offset, 8,
406                             little_endian);
407         offset += 8;
408
409         dst_nid = get_nid(tvb, offset);
410         proto_tree_add_text(tree, tvb, offset, 8, "dst_nid = %s@tcp%d",
411                             ip_to_str((guint8 *) &dst_nid.addr),
412                             dst_nid.interface);
413         offset += 8;
414         proto_tree_add_item(tree, hf_lnet_ib_dststamp, tvb,offset, 8,
415                             little_endian);
416         offset += 8;
417
418         /* LNet payloads only exist when the LND msg type is IMMEDIATE.
419            Return a zero offset for all other types. */
420         return (msg_type == IBLND_MSG_IMMEDIATE) ? offset : 0;
421 }
422
423 static int dissect_dest_nid(tvbuff_t * tvb, proto_tree *tree, int offset)
424 {
425         proto_tree_add_item(tree, hf_lnet_dest_nid_addr, tvb, offset, 4, TRUE);offset+=4;
426         proto_tree_add_item(tree, hf_lnet_dest_nid_interface, tvb, offset, 2, TRUE);offset+=2;
427         proto_tree_add_item(tree, hf_lnet_dest_nid_lnet_type, tvb, offset, 2, TRUE);offset+=2;
428         return offset;
429 }
430
431
432 static int dissect_src_nid(tvbuff_t * tvb, proto_tree *tree, int offset)
433 {
434         proto_tree_add_item(tree, hf_lnet_src_nid_addr, tvb, offset, 4, TRUE);offset+=4;
435         proto_tree_add_item(tree, hf_lnet_src_nid_interface, tvb, offset, 2, TRUE);offset+=2;
436         proto_tree_add_item(tree, hf_lnet_src_nid_lnet_type, tvb, offset, 2, TRUE);offset+=2;
437         return offset;
438 }
439
440 static int dissect_lnet_put(tvbuff_t * tvb, proto_tree *tree, int offset, packet_info *pinfo _U_)
441 {
442         /* typedef struct lnet_put {
443                  lnet_handle_wire_t  ack_wmd;
444                  __u64               match_bits;
445                  __u64               hdr_data;
446                  __u32               ptl_index;
447                  __u32               offset;
448                  } WIRE_ATTR lnet_put_t; */
449
450         proto_tree_add_item(tree,hf_dst_wmd_interface,tvb,offset,8,little_endian); offset+=8;
451         proto_tree_add_item(tree,hf_dst_wmd_object,tvb,offset,8,little_endian);offset+=8;
452
453         proto_tree_add_item(tree,hf_match_bits,tvb,offset,8,little_endian);offset+=8;
454         proto_tree_add_item(tree,hf_hdr_data,tvb,offset,8,little_endian);offset+=8;
455         if (check_col(pinfo->cinfo, COL_INFO)) 
456                 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ",
457                 val_to_str(tvb_get_letohl(tvb, offset), portal_indices,
458                            "Unknown")); /* add some nice value  */
459         proto_item_append_text(tree, ", %s" , val_to_str(tvb_get_letohl(tvb,
460                                                                         offset),
461                                                          portal_indices,
462                                                          "Unknown"));
463                                                          /* print ptl_index */
464         proto_tree_add_item(tree,hf_ptl_index,tvb,offset,4,little_endian);offset+=4;
465         proto_tree_add_item(tree,hf_offset,tvb,offset,4,little_endian);offset+=4;
466         return offset ; 
467 }
468
469 static int dissect_lnet_get(tvbuff_t * tvb, proto_tree *tree, int offset, packet_info *pinfo _U_)
470 {
471         /* typedef struct lnet_get {
472                  lnet_handle_wire_t  return_wmd;
473                  __u64               match_bits;
474                  __u32               ptl_index;
475                  __u32               src_offset;
476                  __u32               sink_length;
477                  } WIRE_ATTR lnet_get_t; */
478
479         proto_tree_add_item(tree,hf_dst_wmd_interface,tvb,offset,8,little_endian);offset+=8;
480         proto_tree_add_item(tree,hf_dst_wmd_object,tvb,offset,8,little_endian);offset+=8;
481         /*if (check_col(pinfo->cinfo, COL_INFO))*/
482         /*        col_prepend_fence_fstr(pinfo->cinfo, COL_INFO, " %" G_GINT64_MODIFIER "u ", tvb_get_letoh64(tvb,offset) );*/
483
484         proto_tree_add_item(tree,hf_match_bits,tvb,offset,8,little_endian);offset+=8;
485         if (check_col(pinfo->cinfo, COL_INFO)) 
486                 col_append_sep_str(pinfo->cinfo, COL_INFO, ", ", val_to_str(tvb_get_letohl(tvb,offset), portal_indices, "Unknown"));
487         proto_item_append_text(tree, ", %s" , val_to_str(tvb_get_letohl(tvb,offset), portal_indices, "Unknown"));
488         proto_tree_add_item(tree,hf_ptl_index,tvb,offset,4,little_endian);offset+=4;
489         proto_tree_add_item(tree,hf_src_offset,tvb,offset,4,little_endian);offset+=4;
490         proto_tree_add_item(tree,hf_sink_length,tvb,offset,4,little_endian);offset+=4;
491         return offset; 
492 }
493
494 static int dissect_lnet_reply(tvbuff_t * tvb, proto_tree *tree, int offset)
495 {
496         /* typedef struct lnet_reply {
497                  lnet_handle_wire_t  dst_wmd;
498                  } WIRE_ATTR lnet_reply_t; */
499
500         proto_tree_add_item(tree,hf_dst_wmd_interface,tvb,offset,8,little_endian);offset+=8; 
501         proto_tree_add_item(tree,hf_dst_wmd_object,tvb,offset,8,little_endian);offset+=8;
502
503         return offset;
504 }
505
506
507 static int dissect_lnet_hello(tvbuff_t * tvb, proto_tree *tree, int offset)
508 {
509         /* typedef struct lnet_hello {
510                  __u64              incarnation;
511                  __u32              type;
512                  } WIRE_ATTR lnet_hello_t; */
513
514         proto_tree_add_item(tree,hf_hello_incarnation,tvb,offset,8,little_endian); offset+=8;
515         proto_tree_add_item(tree,hf_hello_type,tvb,offset,4,little_endian); offset+=4;
516         return offset; 
517 }
518
519 static int dissect_lnet_ack(tvbuff_t * tvb, proto_tree *tree, int offset, packet_info *pinfo _U_)
520 {
521         /* typedef struct lnet_ack {
522                  lnet_handle_wire_t  dst_wmd;
523                  __u64               match_bits;
524                  __u32               mlength;
525                  } WIRE_ATTR lnet_ack_t; */
526
527         proto_tree_add_item(tree,hf_dst_wmd_interface,tvb,offset,8,TRUE); offset+=8;
528         proto_tree_add_item(tree,hf_dst_wmd_object,tvb,offset,8,TRUE);offset+=8;
529         proto_tree_add_item(tree,hf_match_bits,tvb,offset,8, little_endian);offset+=8;
530         proto_tree_add_item(tree,hf_mlength, tvb,offset,4, little_endian); offset+=4;
531         return offset ; 
532
533
534 static void dissect_lnet_message(tvbuff_t * tvb, packet_info *pinfo, proto_tree *tree); 
535
536 /* The next two length getting routines are only used for KSOCK LNK messages. */
537 static guint 
538 get_lnet_message_len(packet_info  __attribute__((__unused__))*pinfo, tvbuff_t *tvb, int offset) 
539
540         guint32 plen;
541
542         /* Get the payload length */
543         plen = tvb_get_letohl(tvb, offset + 28 + 24 + ib_lnd_extra_bytes);
544                                                   /* 24 = ksm header,
545                                                      28 = the rest of the
546                                                           headers */
547
548         /* That length doesn't include the header; add that in. */
549         return plen + 72 + 24 + ib_lnd_extra_bytes; /*  +24 == ksock msg
550                                                         header.. :D */
551
552 }
553
554 static guint
555 get_noop_message_len(packet_info  __attribute__((__unused__))*pinfo, tvbuff_t *tvb, int offset)
556 {
557         return 24;
558 }
559
560 static void 
561 dissect_lnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)  
562 {
563         /* TODO : correct this, now we do a difference between packet with
564            NOOP and others ..  but I don't find how to use pdu_dissect with
565            a variable length<=LNET_HEADER_LEN */
566         ib_lnd_extra_bytes = 0;
567         switch(tvb_get_letohl(tvb,0)){
568                 case KSOCK_MSG_NOOP:
569                         tcp_dissect_pdus(tvb,pinfo,tree,TRUE,0, get_noop_message_len,dissect_ksock_msg_noop);
570                         break;
571                 case KSOCK_MSG_LNET:
572                         tcp_dissect_pdus(tvb,pinfo,tree,TRUE,LNET_HEADER_LEN, get_lnet_message_len,dissect_lnet_message);
573                         break;
574         }
575
576 }
577
578 static int
579 dissect_ib_lnet(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void*data)
580 {
581         /* We can tell if this is an LNet payload by looking at the first
582          * 32-bit word for our magic number. */
583         if (tvb_get_letohl(tvb, 0) != LNET_PROTO_IB_MAGIC) {
584                 /* Not an LNet payload. */
585                 return 0;
586         }
587
588         ib_lnd_extra_bytes = EXTRA_IB_HEADER_SIZE;
589         tcp_dissect_pdus(tvb, pinfo, tree, TRUE, LNET_HEADER_LEN,
590                          get_lnet_message_len, dissect_lnet_message);
591         return tvb_length(tvb);
592 }
593
594 /*----------------------------------------------------------- */
595 /* For the conversation */
596
597 typedef struct {
598         guint64 match_bits;
599 } my_entry_t;
600
601
602 typedef struct lnet_request_key {
603         guint64 match_bits ;
604         guint32 conversation;
605 } lnet_request_key_t;
606
607 typedef struct lnet_request_val {
608         guint64 match_bits;
609         guint32 packet_num_parent;
610 } lnet_request_val_t;
611
612
613 static GHashTable *lnet_request_hash;
614
615 /*
616  * Hash Functions
617  */
618 static gint
619 lnet_equal(gconstpointer v, gconstpointer w)
620 {
621         const struct lnet_request_key *v1 = (const struct lnet_request_key *)v;
622         const struct lnet_request_key *v2 = (const struct lnet_request_key *)w;
623
624         if (v1 -> conversation == v2 -> conversation &&
625                         v1 -> match_bits == v2 -> match_bits)
626         {
627
628                 return 1;
629         }
630
631         return 0;
632 }
633
634 static guint
635 lnet_hash (gconstpointer v)
636 {
637         const struct lnet_request_key *key = (const struct lnet_request_key *)v;
638         return key -> conversation + key -> match_bits;
639 }
640
641
642 static void
643 lnet_init_protocol(void)
644 {
645         if (lnet_request_hash)
646                 g_hash_table_destroy(lnet_request_hash);
647
648         lnet_request_hash = g_hash_table_new(lnet_hash, lnet_equal);
649 }
650
651
652 static lnet_request_val_t*
653 get_lnet_conv(packet_info * pinfo , GHashTable * lnet_hash_table,  guint64 match_bits )
654 {
655         conversation_t *  conversation ; 
656         lnet_request_key_t request_key, *new_request_key;
657         lnet_request_val_t *request_val=NULL ;
658
659         conversation = find_conversation(pinfo->fd->num, &pinfo->src, &pinfo->dst, pinfo->ptype, pinfo->srcport, pinfo->destport, 0);
660
661
662         if (NULL == conversation)
663                 /* It's not part of any conversation - create a new one. */
664                 conversation = conversation_new(pinfo->fd->num,  &pinfo->src, &pinfo->dst, proto_lnet,
665                                 pinfo->srcport, pinfo->destport, 0);
666
667         request_key.conversation = conversation->index;
668         request_key.match_bits = match_bits;
669
670         request_val = (struct lnet_request_val * ) g_hash_table_lookup(lnet_hash_table, &request_key);
671         if(!request_val){
672                 new_request_key = se_alloc(sizeof(struct lnet_request_key));
673                 *new_request_key = request_key;
674                 request_val = se_alloc(sizeof(struct lnet_request_val));
675                 request_val -> match_bits = match_bits;
676                 request_val -> packet_num_parent = pinfo->fd->num ;
677                 /*request_val -> filename = "test" ; */
678                 g_hash_table_insert(lnet_hash_table, new_request_key, request_val);
679
680         }
681
682         return request_val ;
683
684 }
685
686
687
688 /*----------------------------------------------------------- */
689 static void
690 dissect_lnet_message(tvbuff_t * tvb, packet_info *pinfo, proto_tree *tree)
691 {
692
693         guint64 match;
694         guint32 msg_type;
695 /*
696         lnet_request_val_t* conversation_val ;
697
698 */
699         if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
700                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "Lnet");
701         }
702
703         if (check_col(pinfo->cinfo, COL_INFO)) {
704                 /* t_nid dest_nid ; */
705                 /*t_nid src_nid ; */
706                 /*guint32 msg_type;*/
707                 /*[> col_clear(pinfo->cinfo, COL_INFO); <]*/
708                 /*dest_nid = get_nid(tvb, LNET_NID_DEST_OFFSET);*/
709                 /*src_nid = get_nid(tvb, LNET_NID_SRC_OFFSET);*/
710
711                 /*[> col_add_fstr(pinfo->cinfo, COL_INFO, "%s@tcp%d > %s@tcp%d",
712                         ip_to_str((guint8 *) &src_nid.addr), src_nid.interface,
713                         ip_to_str((guint8 *) & dest_nid.addr), dest_nid.interface); */
714
715                 msg_type = tvb_get_letohl(tvb, LNET_MSG_TYPE_OFFSET );
716                 /* We delete the entire line and add LNET  + msg_type */
717                 col_add_fstr(pinfo->cinfo, COL_INFO, "LNET_%s", (msg_type < sizeof(lnet_msg_type_t)/sizeof(value_string)) ? lnet_msg_type_t[msg_type].strptr : "Unknown");
718         }
719
720         if (tree) {
721                 t_nid dest_nid ; /* nid value */
722                 t_nid src_nid ; 
723
724
725                 proto_item *ti = NULL; /* principal  node */
726                 proto_tree *lnet_tree = NULL ; /* principal tree */
727                 proto_tree *lnet_nid_src_tree= NULL ; /*subtree for the nids*/
728                 proto_tree *lnet_nid_dest_tree= NULL ; 
729                 proto_item *ti_src_nid ; /* node for the nids */
730                 proto_item *ti_dest_nid ; 
731
732                 gint offset = 0 ; 
733
734                 guint32 msg_type ;
735                 guint32 payload_length; 
736                 guint32 msg_filler_length;
737
738
739                 ti = proto_tree_add_item(tree,proto_lnet,tvb,0,-1,FALSE); /* principal node */ 
740                 /*      ti=proto_tree_add_protocol_format(tree, proto_lnet, tvb, 0, -1, "Lnet"); */
741
742                 lnet_tree = proto_item_add_subtree(ti,ett_lnet); /* add the subtree*/
743
744                 if (ib_lnd_extra_bytes) {
745                         offset = dissect_ib_msg(tvb, lnet_tree, offset);
746                         if (offset == 0) {
747                                 /*  There was no LNet payload, only ob2lnd. */
748                                 return;
749                         }
750                 } else {
751                         /* dissect the first 24 bytes (ksock_msg_t in
752                            lnet/socklnd.h */
753                         offset=dissect_ksock_msg(tvb,lnet_tree,offset);
754                 }
755
756                 /* Dest nid */
757                 dest_nid = get_nid(tvb, offset);
758                 ti_dest_nid = proto_tree_add_text(lnet_tree, tvb, offset, 8, "dest_nid = %s@tcp%d", ip_to_str((guint8 *) &dest_nid.addr), dest_nid.interface);
759                 lnet_nid_dest_tree = proto_item_add_subtree(ti_dest_nid,ett_lnet_dest_nid) ; 
760                 offset=dissect_dest_nid(tvb,lnet_nid_dest_tree,offset); 
761
762                 /* Same for src_nid */
763                 src_nid = get_nid(tvb, offset);
764                 ti_src_nid = proto_tree_add_text(lnet_tree, tvb, offset, 8, "src_nid = %s@tcp%d", ip_to_str((guint8 *) &src_nid.addr), src_nid.interface);
765                 lnet_nid_src_tree = proto_item_add_subtree(ti_src_nid,ett_lnet_src_nid) ; 
766                 offset=dissect_src_nid(tvb,lnet_nid_src_tree,offset);
767
768                 /* pid */
769                 proto_tree_add_item(lnet_tree, hf_lnet_src_pid, tvb, offset, 4, TRUE); offset+=4;
770                 proto_tree_add_item(lnet_tree, hf_lnet_dest_pid, tvb, offset, 4, TRUE); offset+=4;
771
772                 /* message_type (32 bits) */
773                 msg_type = tvb_get_letohl(tvb, offset+0);
774                 /* put some nice info on lnet line */ 
775                 proto_item_append_text(ti," %s", (msg_type < sizeof(lnet_msg_type_t)/sizeof(value_string)) ? lnet_msg_type_t[msg_type].strptr : "Unknow") ;  /* rajout de l'info dans l'arbre */
776                 proto_tree_add_item(lnet_tree, hf_lnet_msg_type, tvb, offset, 4, TRUE); offset+=4;
777
778                 /* payload data (to follow) length :*/
779                 payload_length = tvb_get_letohl(tvb,offset+0);  
780                 proto_tree_add_item(lnet_tree, hf_lnet_payload_length, tvb, offset, 4, TRUE); offset+=4;
781
782                 /* here offset = 24+8+8+4+4+4+4 = 56 */
783                 match = 0 ;
784                 switch(msg_type) {
785                         case LNET_MSG_ACK:
786                                 offset=dissect_lnet_ack(tvb,lnet_tree,offset,pinfo);
787                                 match = tvb_get_letoh64(tvb,72 );
788                                 break;
789                         case LNET_MSG_PUT:
790                                 offset=dissect_lnet_put(tvb,lnet_tree,offset,pinfo);
791                                 match = tvb_get_letoh64(tvb, 72);
792                                 break;
793                         case LNET_MSG_GET:
794                                 offset=dissect_lnet_get(tvb,lnet_tree,offset,pinfo);
795                                 match = tvb_get_letoh64(tvb, 72);
796                                 break;
797                         case LNET_MSG_REPLY:
798                                 offset=dissect_lnet_reply(tvb,lnet_tree,offset);
799                                 break;
800                         case LNET_MSG_HELLO:
801                                 offset=dissect_lnet_hello(tvb,lnet_tree,offset);
802                                 break;
803                         default:
804                                 break;
805                 }
806
807
808                 /* conversation_val = */
809                 get_lnet_conv(pinfo , lnet_request_hash, match );
810                 /*      proto_tree_add_text(tree, tvb, 0 , 0, "match = %"
811                         G_GINT64_MODIFIER "u parent = %d",
812                         conversation_val -> match_bits ,
813                         conversation_val -> packet_num_parent); */
814
815
816                 /* padding */
817                 msg_filler_length = 72 - offset + 24 + ib_lnd_extra_bytes;
818                 if ( msg_filler_length > 72)
819                         return ;
820                 /*  +24 : ksosck_message take 24bytes, and allready in offset  */
821
822                 proto_tree_add_item(lnet_tree, hf_lnet_msg_filler, tvb, offset,
823                                     msg_filler_length, little_endian);
824                 offset+=msg_filler_length;
825
826                 if (payload_length>0)
827                 {
828
829                         /* display of payload */ 
830                         proto_tree_add_item(lnet_tree, hf_lnet_payload, tvb,
831                                             offset, payload_length,
832                                             little_endian);
833
834                         next_tvb = tvb_new_subset (tvb, offset, payload_length, payload_length);
835                         if(msg_type==LNET_MSG_PUT)
836                                 dissector_try_uint(subdissector_table, tvb_get_letohl(tvb,LNET_PTL_INDEX_OFFSET_PUT), next_tvb, pinfo, tree);
837
838                 }
839
840                 offset+=payload_length;
841         } 
842 }
843
844 void
845 proto_register_lnet(void)
846 {
847         static hf_register_info hf[] = {
848                 { &hf_lnet_ksm_type           , 
849                         { "Type of socklnd message"   , "lnet.ksm_type"                , FT_UINT32 , BASE_HEX     , VALS(ksm_type_t)      , 0x0 , ""         , HFILL }} , 
850                 { &hf_lnet_ksm_csum           , 
851                         { "Checksum"                  , "lnet.ksm_csum"                , FT_UINT32 , BASE_DEC     , NULL                  , 0x0 , ""         , HFILL }} , 
852                 { &hf_lnet_ksm_zc_req_cookie  , 
853                         { "Ack required"              , "lnet.ksm_zc_req_cookie"       , FT_UINT64 , BASE_HEX     , NULL                  , 0x0 , ""         , HFILL }} , 
854                 { &hf_lnet_ksm_zc_ack_cookie  , 
855                         { "Ack"                       , "lnet.ksm_zc_ack_cookie"       , FT_UINT64 , BASE_HEX     , NULL                  , 0x0 , ""         , HFILL }} , 
856                 { &hf_lnet_ib_magic,
857                         { "Magic of IB message", "lnet.ib.magic", FT_UINT32,
858                           BASE_HEX, NULL, 0x0, "", HFILL} },
859                 { &hf_lnet_ib_version,
860                         { "Version", "lnet.ib.version", FT_UINT16, BASE_HEX,
861                           VALS(ib_version_t), 0x0, "", HFILL} },
862                 { &hf_lnet_ib_type,
863                         { "Type of IB message", "lnet.ib.type", FT_UINT8,
864                           BASE_HEX, VALS(ib_type_t), 0x0, "", HFILL} },
865                 { &hf_lnet_ib_credits,
866                         { "Returned Credits", "lnet.ib.credits", FT_UINT8,
867                           BASE_DEC, NULL, 0x0, "", HFILL} },
868                 { &hf_lnet_ib_nob,
869                         { "Number of Bytes", "lnet.ib.nob", FT_UINT32,
870                           BASE_DEC, NULL, 0x0, "", HFILL} },
871                 { &hf_lnet_ib_csum,
872                         { "Checksum", "lnet.ib_csum", FT_UINT32, BASE_DEC,
873                           NULL, 0x0, "", HFILL} },
874                 { &hf_lnet_ib_srcstamp,
875                         { "Sender Timestamp", "lnet.ib.srcstamp",
876                           FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
877                           "", HFILL} },
878                 { &hf_lnet_ib_dststamp,
879                         { "Destination Timestamp", "lnet.ib.dststamp",
880                           FT_ABSOLUTE_TIME, ABSOLUTE_TIME_LOCAL, NULL, 0x0,
881                           "", HFILL} },
882
883                 { &hf_lnet_src_nid            , 
884                         { "Src nid"                   , "lnet.src_nid"                 , FT_UINT64 , BASE_HEX     , NULL                  , 0x0 , "src nid"  , HFILL }} , 
885                 { &hf_lnet_src_nid_addr       , 
886                         { "Src nid"                   , "lnet.src_nid_addr"            , FT_IPv4   , BASE_NONE    , NULL                  , 0x0 , ""         , HFILL }} , 
887                 { &hf_lnet_src_nid_lnet_type  , 
888                         { "lnd network type"          , "lnet.src_nid_type"            , FT_UINT16 , BASE_DEC     , VALS(lndnames)       , 0x0 , ""         , HFILL} },
889                 { &hf_lnet_src_nid_interface  , 
890                         { "lnd network interface"     , "lnet.src_nid_net_interface"   , FT_UINT16 , BASE_DEC     , NULL                  , 0x0 , NULL       , HFILL }} , 
891
892                 { &hf_lnet_dest_nid           , 
893                         { "Dest nid"                  , "lnet.dest_nid"                , FT_UINT64 , BASE_HEX     , NULL                  , 0x0 , ""         , HFILL }} , 
894
895                 { &hf_lnet_dest_nid_addr      , 
896                         { "Destination nid"           , "lnet.dest_nid_addr"           , FT_IPv4   , BASE_NONE    , NULL                  , 0x0 , ""         , HFILL }} , 
897                 { &hf_lnet_dest_nid_lnet_type , 
898                         { "lnd network type"          , "lnet.dest_nid_type"           , FT_UINT16 , BASE_DEC     , VALS(lndnames)       , 0x0 , ""         , HFILL} },
899                 { &hf_lnet_dest_nid_interface , 
900                         { "lnd network interface"     , "lnet.dest_nid_net_interface"  , FT_UINT16 , BASE_DEC     , NULL                  , 0x0 , NULL       , HFILL }} , 
901
902                 { &hf_lnet_dest_pid           , 
903                         { "Dest pid"                  , "lnet.dest_pid"                , FT_UINT32 , BASE_DEC_HEX , NULL                  , 0x0 , "dest pid" , HFILL }} , 
904                 { &hf_lnet_src_pid            , 
905                         { "Src pid"                   , "lnet.src_pid"                 , FT_UINT32 , BASE_DEC_HEX , NULL                  , 0x0 , "src nid"  , HFILL }} , 
906
907                 { &hf_lnet_msg_type           , 
908                         { "Message type"              , "lnet.msg_type"                , FT_UINT32 , BASE_DEC     , VALS(lnet_msg_type_t) , 0x0 , "msg type" , HFILL }} , 
909                 { &hf_lnet_payload_length     , 
910                         { "Payload length"            , "lnet.payload_length"          , FT_UINT32 , BASE_DEC     , NULL                  , 0x0 , ""         , HFILL }} , 
911                 { &hf_lnet_payload            , 
912                         { "Payload"                   , "lnet.payload"                 , FT_NONE   , BASE_NONE    , NULL                  , 0x0 , ""         , HFILL }} , 
913
914                 {&hf_dst_wmd                  , 
915                         { "DST MD index "             , "lnet.msg_dst_cookie"          , FT_BYTES  , BASE_NONE    , NULL                  , 0x0 , ""         , HFILL }} , 
916                 { &hf_dst_wmd_interface       , 
917                         { "DST MD index interface"    , "lnet.msg_dst_inteface_cookie" , FT_UINT64 , BASE_HEX_DEC , NULL                  , 0x0 , ""         , HFILL }} , 
918                 { &hf_dst_wmd_object          , 
919                         { "DST MD index object"       , "lnet.msg_dst_object_cookie"   , FT_UINT64 , BASE_HEX_DEC , NULL                  , 0x0 , ""         , HFILL }} , 
920                 { &hf_match_bits              , 
921                         { "Match bits"                , "lnet.msg_dst_match_bits"      , FT_UINT64 , BASE_HEX_DEC , NULL                  , 0x0 , ""         , HFILL}}  , 
922                 { &hf_mlength                 , 
923                         { "Message length"            , "lnet.msg_length"              , FT_UINT32 , BASE_DEC     , NULL                  , 0x0 , ""         , HFILL}}  , 
924
925
926                 /* Put */
927                 { &hf_hdr_data                , 
928                         { "hdr data"                  , "lnet.msg_hdr_data"            , FT_UINT64 , BASE_HEX_DEC , NULL                  , 0x0 , ""         , HFILL}}  , 
929                 { &hf_ptl_index               , 
930                         { "ptl index"                 , "lnet.ptl_index"               , FT_UINT32 , BASE_DEC     , VALS(portal_indices)  , 0x0 , ""         , HFILL}}  , 
931                 { &hf_offset                  , 
932                         { "offset"                    , "lnet.offset"                  , FT_UINT32 , BASE_DEC     , NULL                  , 0x0 , ""         , HFILL}}  , 
933
934                 /* Get*/
935                 { &hf_src_offset              , 
936                         { "src offset"                , "lnet.src_offset"              , FT_UINT32 , BASE_DEC     , NULL                  , 0x0 , ""         , HFILL}}  , 
937                 { &hf_sink_length             , 
938                         { "sink length"               , "lnet.sink_length"             , FT_UINT32 , BASE_DEC     , NULL                  , 0x0 , ""         , HFILL}}  , 
939
940                 /* Hello*/
941                 { &hf_hello_incarnation       , 
942                         { "hello incarnation "        , "lnet.hello_incarnation"       , FT_UINT64 , BASE_HEX_DEC , NULL                  , 0x0 , ""         , HFILL}}  , 
943                 { &hf_hello_type              , 
944                         { "hello type"                , "lnet.hello_type"              , FT_UINT32 , BASE_DEC     , NULL                  , 0x0 , ""         , HFILL}}  , 
945
946                 { &hf_lnet_msg_header         , 
947                         { "ptl header"                , "lnet.ptl_header"              , FT_NONE   , BASE_NONE    , NULL                  , 0x0 , ""         , HFILL}}  , 
948
949                 { &hf_lnet_msg_filler         , 
950                         { "msg filler (padding)"      , "lnet.ptl_filler"              , FT_NONE   , BASE_NONE    , NULL                  , 0x0 , ""         , HFILL}}  , 
951
952                 /* Add more fields here */
953         };
954
955         static gint *ett[] = {
956                 &ett_lnet,
957                 &ett_lnet_dest_nid,
958                 &ett_lnet_src_nid
959         };
960
961
962         module_t *lnet_module;
963
964         proto_lnet = proto_register_protocol("Lnet", /*name*/
965                         "Lnet",  /*short name*/
966                         "lnet"); /*abbrev*/
967
968         proto_register_field_array(proto_lnet, hf, array_length(hf));
969         proto_register_subtree_array(ett, array_length(ett));
970
971         lnet_module = prefs_register_protocol(proto_lnet, proto_reg_handoff_lnet);
972
973         prefs_register_uint_preference(lnet_module, "tcp.lnet_port",
974                         "Lnet listener TCP Port",
975                         "Set the TCP port for Lnet"
976                         "(if other than the default of 988)",
977                         10, &global_lnet_tcp_port);
978
979         subdissector_table = register_dissector_table("lnet.ptl_index", "lnet portal index", FT_UINT32 , BASE_DEC);
980
981         register_init_routine(&lnet_init_protocol);
982
983 }
984
985
986 /* The registration hand-off routine */
987 void
988 proto_reg_handoff_lnet(void)
989 {
990         static int lnet_prefs_initialized = FALSE;
991         static dissector_handle_t lnet_handle;
992
993         if(!lnet_prefs_initialized) {
994                 heur_dissector_add("infiniband.payload", dissect_ib_lnet,
995                                    proto_lnet);
996                 heur_dissector_add("infiniband.mad.cm.private",
997                                    dissect_ib_lnet, proto_lnet);
998                 lnet_handle = create_dissector_handle(dissect_lnet, proto_lnet);
999                 lnet_prefs_initialized = TRUE;
1000         }
1001         else
1002                 dissector_delete_uint("tcp.port", global_lnet_tcp_port, lnet_handle);
1003
1004         lnet_tcp_port = global_lnet_tcp_port;
1005
1006         dissector_add_uint("tcp.port", lnet_tcp_port, lnet_handle);
1007 }