2 * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved.
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36 #endif /* HAVE_CONFIG_H */
42 #include <netinet/in.h>
44 #include <infiniband/umad.h>
45 #include <infiniband/mad.h>
47 #include "ibdiag_common.h"
49 #define IB_MLX_VENDOR_CLASS 10
51 /* Vendor specific Attribute IDs */
52 #define IB_MLX_IS3_GENERAL_INFO 0x17
54 #define MAX_SWITCH_PORTS (36+1)
55 static char mtx_ports[MAX_SWITCH_PORTS] = {0};
56 static char mrx_ports[MAX_SWITCH_PORTS] = {0};
57 static char str[4096];
58 static uint8_t buf[256];
60 #define ATTRID_PM_ROUTE 0xff30
61 #define ATTRID_PM_FILTER 0xff31
62 #define ATTRID_PM_PORTS 0xff32
63 #define ATTRID_LOSSY_CFG 0xff80
77 MP_MIRROR_FILTER_NOT = 3,
81 #define PM_ENCAP_ETHERTYPE 0x1123
83 struct ibmad_port *srcport;
104 uint32_t ini_file_version;
117 is3_hw_info_t hw_info;
118 is3_fw_info_t fw_info;
119 is3_sw_info_t sw_info;
120 } is3_general_info_t;
123 uint16_t ignore_buffer_mask;
124 uint16_t ignore_credit_mask;
127 static int mirror_query, mirror_dport, mirror_dlid, mirror_clear, mirror_sl, lossy_set;
128 static int set_mtx, set_mrx, packet_size = 0xfff;
130 static int parse_ports(char *ports_str, char *ports_array)
133 char *str = strdup(ports_str);
134 char *token = strtok(str, ",");
135 for (i = 0; i < MAX_SWITCH_PORTS && token; i++) {
136 num = strtoul(token, NULL, 0);
137 if (num > 0 && num < MAX_SWITCH_PORTS)
138 ports_array[num] = 1;
140 token = strtok(NULL, ",");
146 void port_mirror_route(ib_portid_t * portid, int query, int clear)
150 memset(&buf, 0, sizeof(buf));
153 if (!smp_set_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport))
154 IBEXIT("Clear port mirror route set failed");
159 if (!smp_query_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport))
160 IBEXIT("Read port mirror route get failed");
161 mad_decode_field(buf, IB_PMR_MT_F, &mirror_type);
162 if (mirror_type == MT_MIRROR_ENCAP && mirror_dlid == 0)
163 mad_decode_field(buf, IB_PMR_LRH_DLID_F, &mirror_dlid);
164 if (mirror_type == MT_MIRROR_NATIVE && mirror_dport == 0)
165 mad_decode_field(buf, IB_PMR_NM_PORT_F, &mirror_dport);
169 /* Port Mirror Route */
170 mad_set_field(buf, 0, IB_PMR_ENCAP_RAW_ETH_TYPE_F, PM_ENCAP_ETHERTYPE);
172 if (mirror_dlid == 0) {
173 /* Can not truncate mirrored packets in local mode */
174 mad_set_field(buf, 0, IB_PMR_MAX_MIRROR_LEN_F, 0xfff);
175 mad_set_field(buf, 0, IB_PMR_MT_F, MT_MIRROR_NATIVE);
176 mad_set_field(buf, 0, IB_PMR_NM_PORT_F, mirror_dport);
178 else { /* remote mirror */
179 /* convert size to dwords */
180 packet_size = packet_size / 4 + 1;
181 mad_set_field(buf, 0, IB_PMR_MAX_MIRROR_LEN_F, packet_size);
182 mad_set_field(buf, 0, IB_PMR_MT_F, MT_MIRROR_ENCAP);
183 mad_set_field(buf, 0, IB_PMR_LRH_SL_F, mirror_sl);
184 mad_set_field(buf, 0, IB_PMR_LRH_DLID_F, mirror_dlid);
185 mad_set_field(buf, 0, IB_PMR_LRH_SLID_F, portid->lid);
188 if (!smp_set_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport))
189 IBEXIT("port mirror route set failed");
192 mad_dump_portmirror_route(str, sizeof str, buf, sizeof buf);
193 printf("Port Mirror Route\n%s", str);
196 void port_mirror_ports(ib_portid_t * portid, int query, int clear)
198 int p, rqf, tqf, rqv, tqv;
200 memset(&buf, 0, sizeof(buf));
203 if (!smp_set_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport))
204 IBEXIT("Clear port mirror ports set failed");
209 if (!smp_query_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport))
210 IBEXIT("Read port mirror ports get failed");
214 /* Port Mirror Ports */
218 for (p = 1; p < MAX_SWITCH_PORTS; p++) {
219 rqv = mrx_ports[p] ? MP_MIRROR_ALWAYS : MP_DISABLED;
220 tqv = mtx_ports[p] ? MP_MIRROR_ALWAYS : MT_MIRROR_AS_RX;
221 mad_set_field(buf, 0, rqf, rqv);
222 mad_set_field(buf, 0, tqf, tqv);
227 if (!smp_set_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport))
228 IBEXIT("port mirror ports set failed");
231 mad_dump_portmirror_ports(str, sizeof str, buf, sizeof buf);
232 printf("Port Mirror Ports\n%s", str);
235 int get_out_port(ib_portid_t* portid)
241 block = mirror_dlid / IB_SMP_DATA_SIZE;
242 offset = mirror_dlid - block * IB_SMP_DATA_SIZE;
243 /* get out port from lft */
244 if (!smp_query_via(buf, portid, IB_ATTR_LINEARFORWTBL, block, 0, srcport))
245 IBEXIT("linear forwarding table get failed");
246 block = mirror_dlid / IB_SMP_DATA_SIZE;
247 offset = mirror_dlid - block * IB_SMP_DATA_SIZE;
254 int get_peer(ib_portid_t* portid, int outport, int* peerlid, int* peerport)
256 ib_portid_t selfportid = { 0 };
257 ib_portid_t peerportid = { 0 };
260 /* set peerportid for peer port */
261 memcpy(&peerportid, portid, sizeof(peerportid));
262 peerportid.drpath.cnt = 1;
263 peerportid.drpath.p[1] = outport;
264 if (ib_resolve_self_via(&selfportid, &selfport, 0, srcport) < 0)
265 IBEXIT("failed to resolve self portid");
266 peerportid.drpath.drslid = (uint16_t) selfportid.lid;
267 peerportid.drpath.drdlid = 0xffff;
268 if (!smp_query_via(buf, &peerportid, IB_ATTR_PORT_INFO, 0, 0, srcport))
269 IBEXIT("get peer portinfo failed - unable to configure lossy\n");
271 mad_decode_field(buf, IB_PORT_LID_F, peerlid);
272 mad_decode_field(buf, IB_PORT_LOCAL_PORT_F, peerport);
277 int get_mirror_vl(ib_portid_t* portid, int outport)
279 ib_slvl_table_t * p_slvl_tbl;
283 /* hack; assume all sl2vl mappings are the same for any in port and outport */
284 portnum = (1 << 8) | outport;
286 /* get sl2vl mapping */
287 if (!smp_query_via(buf, portid, IB_ATTR_SLVL_TABLE, portnum, 0, srcport))
288 IBEXIT("slvl query failed");
290 p_slvl_tbl = (ib_slvl_table_t *) buf;
291 vl = ib_slvl_table_get(p_slvl_tbl, mirror_sl);
292 printf("mirror_sl %d, mirror_vl %d\n", mirror_sl, vl);
296 int lossy_config(ib_portid_t* portid, int query, int clear)
302 ib_portid_t peerportid = { 0 };
303 ib_portid_t * p_portid;
304 lossy_config_t local_lossy_cfg;
305 lossy_config_t peer_lossy_cfg;
306 lossy_config_t lossy_cfg;
308 outport = get_out_port(portid);
310 IBEXIT("get_out_port failed, mirror_dlid and mirror_dport are 0");
312 get_peer(portid, outport, &peerportid.lid, &peerport);
314 printf("local lid %d / port %d\n", portid->lid, outport);
315 printf("peer lid %d / port %d\n", peerportid.lid, peerport);
317 mirror_vl = get_mirror_vl(portid, outport);
319 /* read local lossy configuration */
320 if (!smp_query_via(buf, portid, ATTRID_LOSSY_CFG, outport, 0, srcport))
321 IBEXIT("get lossy config from lid %d port %d failed - not supported\n",
322 portid->lid, outport);
323 memcpy(&local_lossy_cfg, buf, sizeof(local_lossy_cfg));
325 /* read peer lossy configuration */
326 if (!smp_query_via(buf, &peerportid, ATTRID_LOSSY_CFG, peerport, 0, srcport))
327 IBEXIT("get lossy config from lid %d port %d failed - not supported\n",
328 peerportid.lid, peerport);
329 memcpy(&peer_lossy_cfg, buf, sizeof(peer_lossy_cfg));
332 printf("local port lid %d port %d ignore_buffer 0x%04x, ignore_credit 0x%04x\n",
333 portid->lid, outport,
334 ntohs(local_lossy_cfg.ignore_buffer_mask), ntohs(local_lossy_cfg.ignore_credit_mask));
335 printf("peer port lid %d port %d ignore_buffer 0x%04x, ignore_credit 0x%04x\n",
336 peerportid.lid, peerport,
337 ntohs(peer_lossy_cfg.ignore_buffer_mask), ntohs(peer_lossy_cfg.ignore_credit_mask));
341 /* VLs 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 */
342 /* ignore Buf Overrun ignore Credits */
343 /* when mirror activated set ignore buffer overrun on peer port */
344 /* when mirror is de-activated clear ignore credits on local port */
345 memset(&buf, 0, sizeof(buf));
350 /* set buffer overrun on peer port */
351 p_portid = &peerportid;
353 lossy_cfg.ignore_buffer_mask = htons(1<<mirror_vl);
354 lossy_cfg.ignore_credit_mask = 0;
355 memcpy(&buf, &lossy_cfg, sizeof(lossy_cfg));
357 if (!smp_set_via(buf, p_portid, ATTRID_LOSSY_CFG, attr_mod, 0, srcport))
358 IBEXIT("%s lossy config on lid %d failed\n", clear?"clear":"set", p_portid->lid);
360 /* when mirror activated set ignore credit on local port */
361 /* when mirror de-activated clear buffer overrun on peer */
362 memset(&buf, 0, sizeof(buf));
364 p_portid = &peerportid;
367 /* set ignore credit on local port */
370 lossy_cfg.ignore_credit_mask = htons(1<<mirror_vl);
371 lossy_cfg.ignore_buffer_mask = 0;
372 memcpy(&buf, &lossy_cfg, sizeof(lossy_cfg));
374 if (!smp_set_via(buf, p_portid, ATTRID_LOSSY_CFG, attr_mod, 0, srcport))
375 IBEXIT("%s lossy config on lid %d failed\n", clear?"clear":"set", p_portid->lid);
380 int mirror_config(ib_portid_t* portid, int query, int clear)
382 port_mirror_route(portid, query, clear);
383 /* port_mirror_filter(portid, query, clear); */
384 port_mirror_ports(portid, query, clear);
389 static int process_opt(void *context, int ch, char *optarg)
393 mirror_dport = strtoul(optarg, NULL, 0);
396 packet_size = strtoul(optarg, NULL, 0);
399 mirror_sl = strtoul(optarg, NULL, 0);
402 mirror_dlid = strtoul(optarg, NULL, 0);
406 if (-1 == parse_ports(optarg, mrx_ports))
411 if (-1 == parse_ports(optarg, mtx_ports))
429 int main(int argc, char **argv)
431 int mgmt_classes[4] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS,
434 ib_portid_t portid = { 0 };
436 ib_vendor_call_t call;
437 is3_general_info_t *gi;
441 const struct ibdiag_opt opts[] = {
442 {"dport", 'p', 1, "<port>", "set mirror destination port"},
443 {"dlid", 'L', 1, "<dlid>", "set mirror destination LID"},
444 {"sl", 'l', 1, "<sl>", "set mirror SL"},
445 {"size", 'S', 1, "<size>", "set packet size"},
446 {"rxports", 'R', 1, NULL, "mirror receive port list"},
447 {"txports", 'T', 1, NULL, "mirror transmit port list"},
448 {"clear", 'D', 0, NULL, "clear ports mirroring"},
449 {"query", 'Q', 0, NULL, "read mirror configuration"},
450 {"lossy", 'y', 0, NULL, "set lossy configuration on out port"},
454 char usage_args[] = "<lid>";
455 const char *usage_examples[] = {
456 "-R 1,2,3 -T 2,5 -l1 -L25 -S100 <lid>\t# configure mirror ports",
457 "-D <lid> \t# clear mirror configuration",
458 "-Q <lid>\t# read mirror configuration",
462 ibdiag_process_opts(argc, argv, NULL, "GDLs", opts, process_opt,
463 usage_args, usage_examples);
471 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4);
473 IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port);
476 if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type,
477 ibd_sm_id, srcport) < 0)
478 IBEXIT("can't resolve destination port %s", argv[0]);
482 memset(&buf, 0, sizeof(buf));
483 memset(&call, 0, sizeof(call));
484 call.mgmt_class = IB_MLX_VENDOR_CLASS;
485 call.method = IB_MAD_METHOD_GET;
486 call.timeout = ibd_timeout;
487 call.attrid = IB_MLX_IS3_GENERAL_INFO;
488 if (!ib_vendor_call_via(&buf, &portid, &call, srcport))
489 IBEXIT("failed to read vendor info");
490 gi = (is3_general_info_t *) & buf;
491 if (ntohs(gi->hw_info.device_id) != 0x1b3)
492 IBEXIT("device id 0x%x does not support mirroring", ntohs(gi->hw_info.device_id));
494 fw_ver = gi->fw_info.major * 100000 + gi->fw_info.minor * 1000 + gi->fw_info.sub_minor;
495 printf("FW version %08d\n", fw_ver);
496 if (lossy_set && fw_ver < 704000)
497 IBEXIT("FW version %d.%d.%d does not support lossy config",
498 gi->fw_info.major, gi->fw_info.minor, gi->fw_info.sub_minor);
501 printf( "switch_lid = %d\n"
502 "mirror_clear = %d\n"
505 "mirror_port = %d\n",
506 portid.lid, mirror_clear, mirror_dlid,
507 mirror_sl, mirror_dport);
509 for (port = 1; port < MAX_SWITCH_PORTS; port++) {
511 printf("TX: %d\n",port);
512 else if(mrx_ports[port])
513 printf("RX: %d\n",port);
518 strcpy(op_str, "Clear");
519 else if (mirror_query)
520 strcpy(op_str, "Read");
521 else if (!mirror_dport && !mirror_dlid)
522 IBEXIT("Mirror remote LID and local port are zero");
523 else if (!set_mtx && !set_mrx)
524 IBEXIT("Mirror Rx and Tx ports not selected");
526 strcpy(op_str, "Set");
528 printf("\n%s Mirror Configuration\n", op_str);
529 mirror_config(&portid, mirror_query, mirror_clear);
532 printf("%s Lossy Configuration\n", op_str);
533 lossy_config(&portid, mirror_query, mirror_clear);
536 mad_rpc_close_port(srcport);