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