1 /* 2 * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3 * 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: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 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. 22 * 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 30 * SOFTWARE. 31 * 32 */ 33 34 #if HAVE_CONFIG_H 35 # include <config.h> 36 #endif /* HAVE_CONFIG_H */ 37 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <getopt.h> 42 #include <netinet/in.h> 43 44 #include <infiniband/umad.h> 45 #include <infiniband/mad.h> 46 47 #include "ibdiag_common.h" 48 49 #define IB_MLX_VENDOR_CLASS 10 50 51 /* Vendor specific Attribute IDs */ 52 #define IB_MLX_IS3_GENERAL_INFO 0x17 53 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]; 59 60 #define ATTRID_PM_ROUTE 0xff30 61 #define ATTRID_PM_FILTER 0xff31 62 #define ATTRID_PM_PORTS 0xff32 63 #define ATTRID_LOSSY_CFG 0xff80 64 65 enum mirror_type { 66 MT_DISABLED = 0, 67 MT_MIRROR_NATIVE = 2, 68 MT_DROP = 5, 69 MT_MIRROR_ENCAP = 6, 70 MT_MIRROR_DROP = 7 71 }; 72 73 enum mirror_port { 74 MP_DISABLED = 0, 75 MP_MIRROR_FILTER = 1, 76 MP_MIRROR_ALWAYS = 2, 77 MP_MIRROR_FILTER_NOT = 3, 78 MT_MIRROR_AS_RX = 1 79 }; 80 81 #define PM_ENCAP_ETHERTYPE 0x1123 82 83 struct ibmad_port *srcport; 84 85 typedef struct { 86 uint16_t hw_revision; 87 uint16_t device_id; 88 uint8_t reserved[24]; 89 uint32_t uptime; 90 } is3_hw_info_t; 91 92 typedef struct { 93 uint8_t resv1; 94 uint8_t major; 95 uint8_t minor; 96 uint8_t sub_minor; 97 uint32_t build_id; 98 uint8_t month; 99 uint8_t day; 100 uint16_t year; 101 uint16_t resv2; 102 uint16_t hour; 103 uint8_t psid[16]; 104 uint32_t ini_file_version; 105 } is3_fw_info_t; 106 107 typedef struct { 108 uint8_t resv1; 109 uint8_t major; 110 uint8_t minor; 111 uint8_t sub_minor; 112 uint8_t resv2[28]; 113 } is3_sw_info_t; 114 115 typedef struct { 116 uint8_t reserved[8]; 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; 121 122 typedef struct { 123 uint16_t ignore_buffer_mask; 124 uint16_t ignore_credit_mask; 125 } lossy_config_t; 126 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; 129 130 static int parse_ports(char *ports_str, char *ports_array) 131 { 132 int num, i; 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; 139 140 token = strtok(NULL, ","); 141 } 142 free(str); 143 return 0; 144 } 145 146 void port_mirror_route(ib_portid_t * portid, int query, int clear) 147 { 148 int mirror_type; 149 150 memset(&buf, 0, sizeof(buf)); 151 152 if (clear) { 153 if (!smp_set_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport)) 154 IBEXIT("Clear port mirror route set failed"); 155 return; 156 } 157 158 if (query) { 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); 166 goto Exit; 167 } 168 169 /* Port Mirror Route */ 170 mad_set_field(buf, 0, IB_PMR_ENCAP_RAW_ETH_TYPE_F, PM_ENCAP_ETHERTYPE); 171 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); 177 } 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); 186 } 187 188 if (!smp_set_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport)) 189 IBEXIT("port mirror route set failed"); 190 191 Exit: 192 mad_dump_portmirror_route(str, sizeof str, buf, sizeof buf); 193 printf("Port Mirror Route\n%s", str); 194 } 195 196 void port_mirror_ports(ib_portid_t * portid, int query, int clear) 197 { 198 int p, rqf, tqf, rqv, tqv; 199 200 memset(&buf, 0, sizeof(buf)); 201 202 if (clear) { 203 if (!smp_set_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport)) 204 IBEXIT("Clear port mirror ports set failed"); 205 return; 206 } 207 208 if (query) { 209 if (!smp_query_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport)) 210 IBEXIT("Read port mirror ports get failed"); 211 goto Exit; 212 } 213 214 /* Port Mirror Ports */ 215 rqf = IB_PMP_RQ_1_F; 216 tqf = IB_PMP_TQ_1_F; 217 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); 223 rqf += 2; 224 tqf += 2; 225 } 226 227 if (!smp_set_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport)) 228 IBEXIT("port mirror ports set failed"); 229 230 Exit: 231 mad_dump_portmirror_ports(str, sizeof str, buf, sizeof buf); 232 printf("Port Mirror Ports\n%s", str); 233 } 234 235 int get_out_port(ib_portid_t* portid) 236 { 237 int block; 238 int offset; 239 240 if (mirror_dlid) { 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; 248 return buf[offset]; 249 } 250 else 251 return mirror_dport; 252 } 253 254 int get_peer(ib_portid_t* portid, int outport, int* peerlid, int* peerport) 255 { 256 ib_portid_t selfportid = { 0 }; 257 ib_portid_t peerportid = { 0 }; 258 int selfport = 0; 259 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"); 270 271 mad_decode_field(buf, IB_PORT_LID_F, peerlid); 272 mad_decode_field(buf, IB_PORT_LOCAL_PORT_F, peerport); 273 274 return 0; 275 } 276 277 int get_mirror_vl(ib_portid_t* portid, int outport) 278 { 279 ib_slvl_table_t * p_slvl_tbl; 280 int portnum; 281 int vl; 282 283 /* hack; assume all sl2vl mappings are the same for any in port and outport */ 284 portnum = (1 << 8) | outport; 285 286 /* get sl2vl mapping */ 287 if (!smp_query_via(buf, portid, IB_ATTR_SLVL_TABLE, portnum, 0, srcport)) 288 IBEXIT("slvl query failed"); 289 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); 293 return vl; 294 } 295 296 int lossy_config(ib_portid_t* portid, int query, int clear) 297 { 298 int outport; 299 int peerport; 300 int attr_mod; 301 uint8_t mirror_vl; 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; 307 308 outport = get_out_port(portid); 309 if (outport == 0) 310 IBEXIT("get_out_port failed, mirror_dlid and mirror_dport are 0"); 311 312 get_peer(portid, outport, &peerportid.lid, &peerport); 313 314 printf("local lid %d / port %d\n", portid->lid, outport); 315 printf("peer lid %d / port %d\n", peerportid.lid, peerport); 316 317 mirror_vl = get_mirror_vl(portid, outport); 318 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)); 324 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)); 330 331 if (query) { 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)); 338 return 0; 339 } 340 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)); 346 if (clear) { 347 p_portid = portid; 348 attr_mod = outport; 349 } else { 350 /* set buffer overrun on peer port */ 351 p_portid = &peerportid; 352 attr_mod = peerport; 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)); 356 } 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); 359 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)); 363 if (clear) { 364 p_portid = &peerportid; 365 attr_mod = peerport; 366 } else { 367 /* set ignore credit on local port */ 368 p_portid = portid; 369 attr_mod = outport; 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)); 373 } 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); 376 377 return 0; 378 } 379 380 int mirror_config(ib_portid_t* portid, int query, int clear) 381 { 382 port_mirror_route(portid, query, clear); 383 /* port_mirror_filter(portid, query, clear); */ 384 port_mirror_ports(portid, query, clear); 385 386 return 0; 387 } 388 389 static int process_opt(void *context, int ch, char *optarg) 390 { 391 switch (ch) { 392 case 'p': 393 mirror_dport = strtoul(optarg, NULL, 0); 394 break; 395 case 'S': 396 packet_size = strtoul(optarg, NULL, 0); 397 break; 398 case 'l': 399 mirror_sl = strtoul(optarg, NULL, 0); 400 break; 401 case 'L': 402 mirror_dlid = strtoul(optarg, NULL, 0); 403 break; 404 case 'R': 405 set_mrx = 1; 406 if (-1 == parse_ports(optarg, mrx_ports)) 407 return -1; 408 break; 409 case 'T': 410 set_mtx = 1; 411 if (-1 == parse_ports(optarg, mtx_ports)) 412 return -1; 413 break; 414 case 'D': 415 mirror_clear = 1; 416 break; 417 case 'Q': 418 mirror_query = 1; 419 break; 420 case 'y': 421 lossy_set = 1; 422 break; 423 default: 424 return -1; 425 } 426 return 0; 427 } 428 429 int main(int argc, char **argv) 430 { 431 int mgmt_classes[4] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, 432 IB_MLX_VENDOR_CLASS 433 }; 434 ib_portid_t portid = { 0 }; 435 int port = 0; 436 ib_vendor_call_t call; 437 is3_general_info_t *gi; 438 uint32_t fw_ver; 439 char op_str[32]; 440 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"}, 451 {0} 452 }; 453 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", 459 NULL 460 }; 461 462 ibdiag_process_opts(argc, argv, NULL, "GDLs", opts, process_opt, 463 usage_args, usage_examples); 464 465 argc -= optind; 466 argv += optind; 467 468 if (argc == 0) 469 ibdiag_show_usage(); 470 471 srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4); 472 if (!srcport) 473 IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 474 475 if (argc) { 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]); 479 } 480 481 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)); 493 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); 499 500 if (ibdebug) { 501 printf( "switch_lid = %d\n" 502 "mirror_clear = %d\n" 503 "mirror_dlid = %d\n" 504 "mirror_sl = %d\n" 505 "mirror_port = %d\n", 506 portid.lid, mirror_clear, mirror_dlid, 507 mirror_sl, mirror_dport); 508 509 for (port = 1; port < MAX_SWITCH_PORTS; port++) { 510 if (mtx_ports[port]) 511 printf("TX: %d\n",port); 512 else if(mrx_ports[port]) 513 printf("RX: %d\n",port); 514 } 515 } 516 517 if (mirror_clear) 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"); 525 else 526 strcpy(op_str, "Set"); 527 528 printf("\n%s Mirror Configuration\n", op_str); 529 mirror_config(&portid, mirror_query, mirror_clear); 530 531 if (lossy_set) { 532 printf("%s Lossy Configuration\n", op_str); 533 lossy_config(&portid, mirror_query, mirror_clear); 534 } 535 536 mad_rpc_close_port(srcport); 537 exit(0); 538 } 539