/* * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. * * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #if HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #include #include #include #include #include #include "ibdiag_common.h" #define IB_MLX_VENDOR_CLASS 10 /* Vendor specific Attribute IDs */ #define IB_MLX_IS3_GENERAL_INFO 0x17 #define MAX_SWITCH_PORTS (36+1) static char mtx_ports[MAX_SWITCH_PORTS] = {0}; static char mrx_ports[MAX_SWITCH_PORTS] = {0}; static char str[4096]; static uint8_t buf[256]; #define ATTRID_PM_ROUTE 0xff30 #define ATTRID_PM_FILTER 0xff31 #define ATTRID_PM_PORTS 0xff32 #define ATTRID_LOSSY_CFG 0xff80 enum mirror_type { MT_DISABLED = 0, MT_MIRROR_NATIVE = 2, MT_DROP = 5, MT_MIRROR_ENCAP = 6, MT_MIRROR_DROP = 7 }; enum mirror_port { MP_DISABLED = 0, MP_MIRROR_FILTER = 1, MP_MIRROR_ALWAYS = 2, MP_MIRROR_FILTER_NOT = 3, MT_MIRROR_AS_RX = 1 }; #define PM_ENCAP_ETHERTYPE 0x1123 struct ibmad_port *srcport; typedef struct { uint16_t hw_revision; uint16_t device_id; uint8_t reserved[24]; uint32_t uptime; } is3_hw_info_t; typedef struct { uint8_t resv1; uint8_t major; uint8_t minor; uint8_t sub_minor; uint32_t build_id; uint8_t month; uint8_t day; uint16_t year; uint16_t resv2; uint16_t hour; uint8_t psid[16]; uint32_t ini_file_version; } is3_fw_info_t; typedef struct { uint8_t resv1; uint8_t major; uint8_t minor; uint8_t sub_minor; uint8_t resv2[28]; } is3_sw_info_t; typedef struct { uint8_t reserved[8]; is3_hw_info_t hw_info; is3_fw_info_t fw_info; is3_sw_info_t sw_info; } is3_general_info_t; typedef struct { uint16_t ignore_buffer_mask; uint16_t ignore_credit_mask; } lossy_config_t; static int mirror_query, mirror_dport, mirror_dlid, mirror_clear, mirror_sl, lossy_set; static int set_mtx, set_mrx, packet_size = 0xfff; static int parse_ports(char *ports_str, char *ports_array) { int num, i; char *str = strdup(ports_str); char *token = strtok(str, ","); for (i = 0; i < MAX_SWITCH_PORTS && token; i++) { num = strtoul(token, NULL, 0); if (num > 0 && num < MAX_SWITCH_PORTS) ports_array[num] = 1; token = strtok(NULL, ","); } free(str); return 0; } void port_mirror_route(ib_portid_t * portid, int query, int clear) { int mirror_type; memset(&buf, 0, sizeof(buf)); if (clear) { if (!smp_set_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport)) IBEXIT("Clear port mirror route set failed"); return; } if (query) { if (!smp_query_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport)) IBEXIT("Read port mirror route get failed"); mad_decode_field(buf, IB_PMR_MT_F, &mirror_type); if (mirror_type == MT_MIRROR_ENCAP && mirror_dlid == 0) mad_decode_field(buf, IB_PMR_LRH_DLID_F, &mirror_dlid); if (mirror_type == MT_MIRROR_NATIVE && mirror_dport == 0) mad_decode_field(buf, IB_PMR_NM_PORT_F, &mirror_dport); goto Exit; } /* Port Mirror Route */ mad_set_field(buf, 0, IB_PMR_ENCAP_RAW_ETH_TYPE_F, PM_ENCAP_ETHERTYPE); if (mirror_dlid == 0) { /* Can not truncate mirrored packets in local mode */ mad_set_field(buf, 0, IB_PMR_MAX_MIRROR_LEN_F, 0xfff); mad_set_field(buf, 0, IB_PMR_MT_F, MT_MIRROR_NATIVE); mad_set_field(buf, 0, IB_PMR_NM_PORT_F, mirror_dport); } else { /* remote mirror */ /* convert size to dwords */ packet_size = packet_size / 4 + 1; mad_set_field(buf, 0, IB_PMR_MAX_MIRROR_LEN_F, packet_size); mad_set_field(buf, 0, IB_PMR_MT_F, MT_MIRROR_ENCAP); mad_set_field(buf, 0, IB_PMR_LRH_SL_F, mirror_sl); mad_set_field(buf, 0, IB_PMR_LRH_DLID_F, mirror_dlid); mad_set_field(buf, 0, IB_PMR_LRH_SLID_F, portid->lid); } if (!smp_set_via(buf, portid, ATTRID_PM_ROUTE, 0, 0, srcport)) IBEXIT("port mirror route set failed"); Exit: mad_dump_portmirror_route(str, sizeof str, buf, sizeof buf); printf("Port Mirror Route\n%s", str); } void port_mirror_ports(ib_portid_t * portid, int query, int clear) { int p, rqf, tqf, rqv, tqv; memset(&buf, 0, sizeof(buf)); if (clear) { if (!smp_set_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport)) IBEXIT("Clear port mirror ports set failed"); return; } if (query) { if (!smp_query_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport)) IBEXIT("Read port mirror ports get failed"); goto Exit; } /* Port Mirror Ports */ rqf = IB_PMP_RQ_1_F; tqf = IB_PMP_TQ_1_F; for (p = 1; p < MAX_SWITCH_PORTS; p++) { rqv = mrx_ports[p] ? MP_MIRROR_ALWAYS : MP_DISABLED; tqv = mtx_ports[p] ? MP_MIRROR_ALWAYS : MT_MIRROR_AS_RX; mad_set_field(buf, 0, rqf, rqv); mad_set_field(buf, 0, tqf, tqv); rqf += 2; tqf += 2; } if (!smp_set_via(buf, portid, ATTRID_PM_PORTS, 0, 0, srcport)) IBEXIT("port mirror ports set failed"); Exit: mad_dump_portmirror_ports(str, sizeof str, buf, sizeof buf); printf("Port Mirror Ports\n%s", str); } int get_out_port(ib_portid_t* portid) { int block; int offset; if (mirror_dlid) { block = mirror_dlid / IB_SMP_DATA_SIZE; offset = mirror_dlid - block * IB_SMP_DATA_SIZE; /* get out port from lft */ if (!smp_query_via(buf, portid, IB_ATTR_LINEARFORWTBL, block, 0, srcport)) IBEXIT("linear forwarding table get failed"); block = mirror_dlid / IB_SMP_DATA_SIZE; offset = mirror_dlid - block * IB_SMP_DATA_SIZE; return buf[offset]; } else return mirror_dport; } int get_peer(ib_portid_t* portid, int outport, int* peerlid, int* peerport) { ib_portid_t selfportid = { 0 }; ib_portid_t peerportid = { 0 }; int selfport = 0; /* set peerportid for peer port */ memcpy(&peerportid, portid, sizeof(peerportid)); peerportid.drpath.cnt = 1; peerportid.drpath.p[1] = outport; if (ib_resolve_self_via(&selfportid, &selfport, 0, srcport) < 0) IBEXIT("failed to resolve self portid"); peerportid.drpath.drslid = (uint16_t) selfportid.lid; peerportid.drpath.drdlid = 0xffff; if (!smp_query_via(buf, &peerportid, IB_ATTR_PORT_INFO, 0, 0, srcport)) IBEXIT("get peer portinfo failed - unable to configure lossy\n"); mad_decode_field(buf, IB_PORT_LID_F, peerlid); mad_decode_field(buf, IB_PORT_LOCAL_PORT_F, peerport); return 0; } int get_mirror_vl(ib_portid_t* portid, int outport) { ib_slvl_table_t * p_slvl_tbl; int portnum; int vl; /* hack; assume all sl2vl mappings are the same for any in port and outport */ portnum = (1 << 8) | outport; /* get sl2vl mapping */ if (!smp_query_via(buf, portid, IB_ATTR_SLVL_TABLE, portnum, 0, srcport)) IBEXIT("slvl query failed"); p_slvl_tbl = (ib_slvl_table_t *) buf; vl = ib_slvl_table_get(p_slvl_tbl, mirror_sl); printf("mirror_sl %d, mirror_vl %d\n", mirror_sl, vl); return vl; } int lossy_config(ib_portid_t* portid, int query, int clear) { int outport; int peerport; int attr_mod; uint8_t mirror_vl; ib_portid_t peerportid = { 0 }; ib_portid_t * p_portid; lossy_config_t local_lossy_cfg; lossy_config_t peer_lossy_cfg; lossy_config_t lossy_cfg; outport = get_out_port(portid); if (outport == 0) IBEXIT("get_out_port failed, mirror_dlid and mirror_dport are 0"); get_peer(portid, outport, &peerportid.lid, &peerport); printf("local lid %d / port %d\n", portid->lid, outport); printf("peer lid %d / port %d\n", peerportid.lid, peerport); mirror_vl = get_mirror_vl(portid, outport); /* read local lossy configuration */ if (!smp_query_via(buf, portid, ATTRID_LOSSY_CFG, outport, 0, srcport)) IBEXIT("get lossy config from lid %d port %d failed - not supported\n", portid->lid, outport); memcpy(&local_lossy_cfg, buf, sizeof(local_lossy_cfg)); /* read peer lossy configuration */ if (!smp_query_via(buf, &peerportid, ATTRID_LOSSY_CFG, peerport, 0, srcport)) IBEXIT("get lossy config from lid %d port %d failed - not supported\n", peerportid.lid, peerport); memcpy(&peer_lossy_cfg, buf, sizeof(peer_lossy_cfg)); if (query) { printf("local port lid %d port %d ignore_buffer 0x%04x, ignore_credit 0x%04x\n", portid->lid, outport, ntohs(local_lossy_cfg.ignore_buffer_mask), ntohs(local_lossy_cfg.ignore_credit_mask)); printf("peer port lid %d port %d ignore_buffer 0x%04x, ignore_credit 0x%04x\n", peerportid.lid, peerport, ntohs(peer_lossy_cfg.ignore_buffer_mask), ntohs(peer_lossy_cfg.ignore_credit_mask)); return 0; } /* 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 */ /* ignore Buf Overrun ignore Credits */ /* when mirror activated set ignore buffer overrun on peer port */ /* when mirror is de-activated clear ignore credits on local port */ memset(&buf, 0, sizeof(buf)); if (clear) { p_portid = portid; attr_mod = outport; } else { /* set buffer overrun on peer port */ p_portid = &peerportid; attr_mod = peerport; lossy_cfg.ignore_buffer_mask = htons(1<lid); /* when mirror activated set ignore credit on local port */ /* when mirror de-activated clear buffer overrun on peer */ memset(&buf, 0, sizeof(buf)); if (clear) { p_portid = &peerportid; attr_mod = peerport; } else { /* set ignore credit on local port */ p_portid = portid; attr_mod = outport; lossy_cfg.ignore_credit_mask = htons(1<lid); return 0; } int mirror_config(ib_portid_t* portid, int query, int clear) { port_mirror_route(portid, query, clear); /* port_mirror_filter(portid, query, clear); */ port_mirror_ports(portid, query, clear); return 0; } static int process_opt(void *context, int ch, char *optarg) { switch (ch) { case 'p': mirror_dport = strtoul(optarg, NULL, 0); break; case 'S': packet_size = strtoul(optarg, NULL, 0); break; case 'l': mirror_sl = strtoul(optarg, NULL, 0); break; case 'L': mirror_dlid = strtoul(optarg, NULL, 0); break; case 'R': set_mrx = 1; if (-1 == parse_ports(optarg, mrx_ports)) return -1; break; case 'T': set_mtx = 1; if (-1 == parse_ports(optarg, mtx_ports)) return -1; break; case 'D': mirror_clear = 1; break; case 'Q': mirror_query = 1; break; case 'y': lossy_set = 1; break; default: return -1; } return 0; } int main(int argc, char **argv) { int mgmt_classes[4] = { IB_SMI_CLASS, IB_SMI_DIRECT_CLASS, IB_SA_CLASS, IB_MLX_VENDOR_CLASS }; ib_portid_t portid = { 0 }; int port = 0; ib_vendor_call_t call; is3_general_info_t *gi; uint32_t fw_ver; char op_str[32]; const struct ibdiag_opt opts[] = { {"dport", 'p', 1, "", "set mirror destination port"}, {"dlid", 'L', 1, "", "set mirror destination LID"}, {"sl", 'l', 1, "", "set mirror SL"}, {"size", 'S', 1, "", "set packet size"}, {"rxports", 'R', 1, NULL, "mirror receive port list"}, {"txports", 'T', 1, NULL, "mirror transmit port list"}, {"clear", 'D', 0, NULL, "clear ports mirroring"}, {"query", 'Q', 0, NULL, "read mirror configuration"}, {"lossy", 'y', 0, NULL, "set lossy configuration on out port"}, {0} }; char usage_args[] = ""; const char *usage_examples[] = { "-R 1,2,3 -T 2,5 -l1 -L25 -S100 \t# configure mirror ports", "-D \t# clear mirror configuration", "-Q \t# read mirror configuration", NULL }; ibdiag_process_opts(argc, argv, NULL, "GDLs", opts, process_opt, usage_args, usage_examples); argc -= optind; argv += optind; if (argc == 0) ibdiag_show_usage(); srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 4); if (!srcport) IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); if (argc) { if (ib_resolve_portid_str_via(&portid, argv[0], ibd_dest_type, ibd_sm_id, srcport) < 0) IBEXIT("can't resolve destination port %s", argv[0]); } memset(&buf, 0, sizeof(buf)); memset(&call, 0, sizeof(call)); call.mgmt_class = IB_MLX_VENDOR_CLASS; call.method = IB_MAD_METHOD_GET; call.timeout = ibd_timeout; call.attrid = IB_MLX_IS3_GENERAL_INFO; if (!ib_vendor_call_via(&buf, &portid, &call, srcport)) IBEXIT("failed to read vendor info"); gi = (is3_general_info_t *) & buf; if (ntohs(gi->hw_info.device_id) != 0x1b3) IBEXIT("device id 0x%x does not support mirroring", ntohs(gi->hw_info.device_id)); fw_ver = gi->fw_info.major * 100000 + gi->fw_info.minor * 1000 + gi->fw_info.sub_minor; printf("FW version %08d\n", fw_ver); if (lossy_set && fw_ver < 704000) IBEXIT("FW version %d.%d.%d does not support lossy config", gi->fw_info.major, gi->fw_info.minor, gi->fw_info.sub_minor); if (ibdebug) { printf( "switch_lid = %d\n" "mirror_clear = %d\n" "mirror_dlid = %d\n" "mirror_sl = %d\n" "mirror_port = %d\n", portid.lid, mirror_clear, mirror_dlid, mirror_sl, mirror_dport); for (port = 1; port < MAX_SWITCH_PORTS; port++) { if (mtx_ports[port]) printf("TX: %d\n",port); else if(mrx_ports[port]) printf("RX: %d\n",port); } } if (mirror_clear) strcpy(op_str, "Clear"); else if (mirror_query) strcpy(op_str, "Read"); else if (!mirror_dport && !mirror_dlid) IBEXIT("Mirror remote LID and local port are zero"); else if (!set_mtx && !set_mrx) IBEXIT("Mirror Rx and Tx ports not selected"); else strcpy(op_str, "Set"); printf("\n%s Mirror Configuration\n", op_str); mirror_config(&portid, mirror_query, mirror_clear); if (lossy_set) { printf("%s Lossy Configuration\n", op_str); lossy_config(&portid, mirror_query, mirror_clear); } mad_rpc_close_port(srcport); exit(0); }