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