1321936Shselasky/* 2321936Shselasky * Copyright (c) 2004-2009 Voltaire Inc. All rights reserved. 3321936Shselasky * Copyright (c) 2011 Mellanox Technologies LTD. All rights reserved. 4321936Shselasky * Copyright (c) 2011 Lawrence Livermore National Lab. All rights reserved. 5321936Shselasky * 6321936Shselasky * This software is available to you under a choice of one of two 7321936Shselasky * licenses. You may choose to be licensed under the terms of the GNU 8321936Shselasky * General Public License (GPL) Version 2, available from the file 9321936Shselasky * COPYING in the main directory of this source tree, or the 10321936Shselasky * OpenIB.org BSD license below: 11321936Shselasky * 12321936Shselasky * Redistribution and use in source and binary forms, with or 13321936Shselasky * without modification, are permitted provided that the following 14321936Shselasky * conditions are met: 15321936Shselasky * 16321936Shselasky * - Redistributions of source code must retain the above 17321936Shselasky * copyright notice, this list of conditions and the following 18321936Shselasky * disclaimer. 19321936Shselasky * 20321936Shselasky * - Redistributions in binary form must reproduce the above 21321936Shselasky * copyright notice, this list of conditions and the following 22321936Shselasky * disclaimer in the documentation and/or other materials 23321936Shselasky * provided with the distribution. 24321936Shselasky * 25321936Shselasky * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 26321936Shselasky * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 27321936Shselasky * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 28321936Shselasky * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 29321936Shselasky * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 30321936Shselasky * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 31321936Shselasky * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 32321936Shselasky * SOFTWARE. 33321936Shselasky * 34321936Shselasky */ 35321936Shselasky 36321936Shselasky#if HAVE_CONFIG_H 37321936Shselasky# include <config.h> 38321936Shselasky#endif /* HAVE_CONFIG_H */ 39321936Shselasky 40321936Shselasky#include <stdio.h> 41321936Shselasky#include <stdlib.h> 42321936Shselasky#include <unistd.h> 43321936Shselasky#include <string.h> 44321936Shselasky#include <getopt.h> 45321936Shselasky#include <errno.h> 46321936Shselasky#include <netinet/in.h> 47321936Shselasky#include <limits.h> 48321936Shselasky#include <ctype.h> 49321936Shselasky 50321936Shselasky#define __STDC_FORMAT_MACROS 51321936Shselasky#include <inttypes.h> 52321936Shselasky 53321936Shselasky#include <infiniband/mad.h> 54321936Shselasky 55321936Shselasky#include "ibdiag_common.h" 56321936Shselasky 57321936Shselaskystruct ibmad_port *srcport; 58321936Shselasky 59321936Shselaskystatic ibmad_gid_t dgid; 60321936Shselaskystatic int with_grh; 61321936Shselasky 62321936Shselaskystatic op_fn_t congestion_key_info; 63321936Shselaskystatic op_fn_t switch_congestion_setting; 64321936Shselaskystatic op_fn_t switch_port_congestion_setting; 65321936Shselaskystatic op_fn_t ca_congestion_setting; 66321936Shselaskystatic op_fn_t congestion_control_table; 67321936Shselasky 68321936Shselaskystatic const match_rec_t match_tbl[] = { 69321936Shselasky {"CongestionKeyInfo", "CK", congestion_key_info, 0, 70321936Shselasky "<cckey> <cckeyprotectbit> <cckeyleaseperiod> <cckeyviolations>"}, 71321936Shselasky {"SwitchCongestionSetting", "SS", switch_congestion_setting, 0, 72321936Shselasky "<controlmap> <victimmask> <creditmask> <threshold> <packetsize> " 73321936Shselasky "<csthreshold> <csreturndelay> <markingrate>"}, 74321936Shselasky {"SwitchPortCongestionSetting", "SP", switch_port_congestion_setting, 1, 75321936Shselasky "<valid> <control_type> <threshold> <packet_size> <cong_parm_marking_rate>"}, 76321936Shselasky {"CACongestionSetting", "CS", ca_congestion_setting, 0, 77321936Shselasky "<port_control> <control_map> <ccti_timer> <ccti_increase> " 78321936Shselasky "<trigger_threshold> <ccti_min>"}, 79321936Shselasky {"CongestionControlTable", "CT", congestion_control_table, 0, 80321936Shselasky "<cctilimit> <index> <cctentry> <cctentry> ..."}, 81321936Shselasky {0} 82321936Shselasky}; 83321936Shselasky 84321936Shselaskyuint64_t cckey = 0; 85321936Shselasky 86321936Shselasky/*******************************************/ 87321936Shselaskystatic char *parselonglongint(char *arg, uint64_t *val) 88321936Shselasky{ 89321936Shselasky char *endptr = NULL; 90321936Shselasky 91321936Shselasky errno = 0; 92321936Shselasky *val = strtoull(arg, &endptr, 0); 93321936Shselasky if ((endptr && *endptr != '\0') 94321936Shselasky || errno != 0) { 95321936Shselasky if (errno == ERANGE) 96321936Shselasky return "value out of range"; 97321936Shselasky return "invalid integer input"; 98321936Shselasky } 99321936Shselasky 100321936Shselasky return NULL; 101321936Shselasky} 102321936Shselasky 103321936Shselaskystatic char *parseint(char *arg, uint32_t *val, int hexonly) 104321936Shselasky{ 105321936Shselasky char *endptr = NULL; 106321936Shselasky 107321936Shselasky errno = 0; 108321936Shselasky *val = strtoul(arg, &endptr, hexonly ? 16 : 0); 109321936Shselasky if ((endptr && *endptr != '\0') 110321936Shselasky || errno != 0) { 111321936Shselasky if (errno == ERANGE) 112321936Shselasky return "value out of range"; 113321936Shselasky return "invalid integer input"; 114321936Shselasky } 115321936Shselasky 116321936Shselasky return NULL; 117321936Shselasky} 118321936Shselasky 119321936Shselaskystatic char *congestion_key_info(ib_portid_t * dest, char **argv, int argc) 120321936Shselasky{ 121321936Shselasky uint8_t rcv[IB_CC_DATA_SZ] = { 0 }; 122321936Shselasky uint8_t payload[IB_CC_DATA_SZ] = { 0 }; 123321936Shselasky uint64_t cc_key; 124321936Shselasky uint32_t cc_keyprotectbit; 125321936Shselasky uint32_t cc_keyleaseperiod; 126321936Shselasky uint32_t cc_keyviolations; 127321936Shselasky char *errstr; 128321936Shselasky 129321936Shselasky if (argc != 4) 130321936Shselasky return "invalid number of parameters for CongestionKeyInfo"; 131321936Shselasky 132321936Shselasky if ((errstr = parselonglongint(argv[0], &cc_key))) 133321936Shselasky return errstr; 134321936Shselasky if ((errstr = parseint(argv[1], &cc_keyprotectbit, 0))) 135321936Shselasky return errstr; 136321936Shselasky if ((errstr = parseint(argv[2], &cc_keyleaseperiod, 0))) 137321936Shselasky return errstr; 138321936Shselasky if ((errstr = parseint(argv[3], &cc_keyviolations, 0))) 139321936Shselasky return errstr; 140321936Shselasky 141321936Shselasky if (cc_keyprotectbit != 0 && cc_keyprotectbit != 1) 142321936Shselasky return "invalid cc_keyprotectbit value"; 143321936Shselasky 144321936Shselasky if (cc_keyleaseperiod > USHRT_MAX) 145321936Shselasky return "invalid cc_keyleaseperiod value"; 146321936Shselasky 147321936Shselasky if (cc_keyviolations > USHRT_MAX) 148321936Shselasky return "invalid cc_keyviolations value"; 149321936Shselasky 150321936Shselasky mad_set_field64(payload, 151321936Shselasky 0, 152321936Shselasky IB_CC_CONGESTION_KEY_INFO_CC_KEY_F, 153321936Shselasky cc_key); 154321936Shselasky 155321936Shselasky mad_encode_field(payload, 156321936Shselasky IB_CC_CONGESTION_KEY_INFO_CC_KEY_PROTECT_BIT_F, 157321936Shselasky &cc_keyprotectbit); 158321936Shselasky 159321936Shselasky mad_encode_field(payload, 160321936Shselasky IB_CC_CONGESTION_KEY_INFO_CC_KEY_LEASE_PERIOD_F, 161321936Shselasky &cc_keyleaseperiod); 162321936Shselasky 163321936Shselasky /* spec says "setting the counter to a value other than zero results 164321936Shselasky * in the counter being left unchanged. So if user wants no change, 165321936Shselasky * they gotta input non-zero 166321936Shselasky */ 167321936Shselasky mad_encode_field(payload, 168321936Shselasky IB_CC_CONGESTION_KEY_INFO_CC_KEY_VIOLATIONS_F, 169321936Shselasky &cc_keyviolations); 170321936Shselasky 171321936Shselasky if (!cc_config_status_via(payload, rcv, dest, IB_CC_ATTR_CONGESTION_KEY_INFO, 172321936Shselasky 0, 0, NULL, srcport, cckey)) 173321936Shselasky return "congestion key info config failed"; 174321936Shselasky 175321936Shselasky return NULL; 176321936Shselasky} 177321936Shselasky 178321936Shselasky 179321936Shselasky/* parse like it's a hypothetical 256 bit hex code */ 180321936Shselaskystatic char *parse256(char *arg, uint8_t *buf) 181321936Shselasky{ 182321936Shselasky int numdigits = 0; 183321936Shselasky int startindex; 184321936Shselasky char *ptr; 185321936Shselasky int i; 186321936Shselasky 187321936Shselasky if (!strncmp(arg, "0x", 2) || !strncmp(arg, "0X", 2)) 188321936Shselasky arg += 2; 189321936Shselasky 190321936Shselasky for (ptr = arg; *ptr; ptr++) { 191321936Shselasky if (!isxdigit(*ptr)) 192321936Shselasky return "invalid hex digit read"; 193321936Shselasky numdigits++; 194321936Shselasky } 195321936Shselasky 196321936Shselasky if (numdigits > 64) 197321936Shselasky return "hex code too long"; 198321936Shselasky 199321936Shselasky /* we need to imagine that this is like a 256-bit int stored 200321936Shselasky * in big endian. So we need to find the first index 201321936Shselasky * point where the user's input would start in our array. 202321936Shselasky */ 203321936Shselasky startindex = 32 - ((numdigits - 1) / 2) - 1; 204321936Shselasky 205321936Shselasky for (i = startindex; i <= 31; i++) { 206321936Shselasky char tmp[3] = { 0 }; 207321936Shselasky uint32_t tmpint; 208321936Shselasky char *errstr; 209321936Shselasky 210321936Shselasky /* I can't help but think there is a strtoX that 211321936Shselasky * will do this for me, but I can't find it. 212321936Shselasky */ 213321936Shselasky if (i == startindex && numdigits % 2) { 214321936Shselasky memcpy(tmp, arg, 1); 215321936Shselasky arg++; 216321936Shselasky } 217321936Shselasky else { 218321936Shselasky memcpy(tmp, arg, 2); 219321936Shselasky arg += 2; 220321936Shselasky } 221321936Shselasky 222321936Shselasky if ((errstr = parseint(tmp, &tmpint, 1))) 223321936Shselasky return errstr; 224321936Shselasky buf[i] = tmpint; 225321936Shselasky } 226321936Shselasky 227321936Shselasky return NULL; 228321936Shselasky} 229321936Shselasky 230321936Shselaskystatic char *parsecct(char *arg, uint32_t *shift, uint32_t *multiplier) 231321936Shselasky{ 232321936Shselasky char buf[1024] = { 0 }; 233321936Shselasky char *errstr; 234321936Shselasky char *ptr; 235321936Shselasky 236321936Shselasky strcpy(buf, arg); 237321936Shselasky 238321936Shselasky if (!(ptr = strchr(buf, ':'))) 239321936Shselasky return "ccts are formatted shift:multiplier"; 240321936Shselasky 241321936Shselasky *ptr = '\0'; 242321936Shselasky ptr++; 243321936Shselasky 244321936Shselasky if ((errstr = parseint(buf, shift, 0))) 245321936Shselasky return errstr; 246321936Shselasky 247321936Shselasky if ((errstr = parseint(ptr, multiplier, 0))) 248321936Shselasky return errstr; 249321936Shselasky 250321936Shselasky return NULL; 251321936Shselasky} 252321936Shselasky 253321936Shselaskystatic char *switch_congestion_setting(ib_portid_t * dest, char **argv, int argc) 254321936Shselasky{ 255321936Shselasky uint8_t rcv[IB_CC_DATA_SZ] = { 0 }; 256321936Shselasky uint8_t payload[IB_CC_DATA_SZ] = { 0 }; 257321936Shselasky uint32_t control_map; 258321936Shselasky uint8_t victim_mask[32] = { 0 }; 259321936Shselasky uint8_t credit_mask[32] = { 0 }; 260321936Shselasky uint32_t threshold; 261321936Shselasky uint32_t packet_size; 262321936Shselasky uint32_t cs_threshold; 263321936Shselasky uint32_t cs_returndelay_s; 264321936Shselasky uint32_t cs_returndelay_m; 265321936Shselasky uint32_t cs_returndelay; 266321936Shselasky uint32_t marking_rate; 267321936Shselasky char *errstr; 268321936Shselasky 269321936Shselasky if (argc != 8) 270321936Shselasky return "invalid number of parameters for SwitchCongestionSetting"; 271321936Shselasky 272321936Shselasky if ((errstr = parseint(argv[0], &control_map, 0))) 273321936Shselasky return errstr; 274321936Shselasky 275321936Shselasky if ((errstr = parse256(argv[1], victim_mask))) 276321936Shselasky return errstr; 277321936Shselasky 278321936Shselasky if ((errstr = parse256(argv[2], credit_mask))) 279321936Shselasky return errstr; 280321936Shselasky 281321936Shselasky if ((errstr = parseint(argv[3], &threshold, 0))) 282321936Shselasky return errstr; 283321936Shselasky 284321936Shselasky if ((errstr = parseint(argv[4], &packet_size, 0))) 285321936Shselasky return errstr; 286321936Shselasky 287321936Shselasky if ((errstr = parseint(argv[5], &cs_threshold, 0))) 288321936Shselasky return errstr; 289321936Shselasky 290321936Shselasky if ((errstr = parsecct(argv[6], &cs_returndelay_s, &cs_returndelay_m))) 291321936Shselasky return errstr; 292321936Shselasky 293321936Shselasky cs_returndelay = cs_returndelay_m; 294321936Shselasky cs_returndelay |= (cs_returndelay_s << 14); 295321936Shselasky 296321936Shselasky if ((errstr = parseint(argv[7], &marking_rate, 0))) 297321936Shselasky return errstr; 298321936Shselasky 299321936Shselasky mad_encode_field(payload, 300321936Shselasky IB_CC_SWITCH_CONGESTION_SETTING_CONTROL_MAP_F, 301321936Shselasky &control_map); 302321936Shselasky 303321936Shselasky mad_set_array(payload, 304321936Shselasky 0, 305321936Shselasky IB_CC_SWITCH_CONGESTION_SETTING_VICTIM_MASK_F, 306321936Shselasky victim_mask); 307321936Shselasky 308321936Shselasky mad_set_array(payload, 309321936Shselasky 0, 310321936Shselasky IB_CC_SWITCH_CONGESTION_SETTING_CREDIT_MASK_F, 311321936Shselasky credit_mask); 312321936Shselasky 313321936Shselasky mad_encode_field(payload, 314321936Shselasky IB_CC_SWITCH_CONGESTION_SETTING_THRESHOLD_F, 315321936Shselasky &threshold); 316321936Shselasky 317321936Shselasky mad_encode_field(payload, 318321936Shselasky IB_CC_SWITCH_CONGESTION_SETTING_PACKET_SIZE_F, 319321936Shselasky &packet_size); 320321936Shselasky 321321936Shselasky mad_encode_field(payload, 322321936Shselasky IB_CC_SWITCH_CONGESTION_SETTING_CS_THRESHOLD_F, 323321936Shselasky &cs_threshold); 324321936Shselasky 325321936Shselasky mad_encode_field(payload, 326321936Shselasky IB_CC_SWITCH_CONGESTION_SETTING_CS_RETURN_DELAY_F, 327321936Shselasky &cs_returndelay); 328321936Shselasky 329321936Shselasky mad_encode_field(payload, 330321936Shselasky IB_CC_SWITCH_CONGESTION_SETTING_MARKING_RATE_F, 331321936Shselasky &marking_rate); 332321936Shselasky 333321936Shselasky if (!cc_config_status_via(payload, rcv, dest, IB_CC_ATTR_SWITCH_CONGESTION_SETTING, 334321936Shselasky 0, 0, NULL, srcport, cckey)) 335321936Shselasky return "switch congestion setting config failed"; 336321936Shselasky 337321936Shselasky return NULL; 338321936Shselasky} 339321936Shselasky 340321936Shselaskystatic char *switch_port_congestion_setting(ib_portid_t * dest, char **argv, int argc) 341321936Shselasky{ 342321936Shselasky uint8_t rcv[IB_CC_DATA_SZ] = { 0 }; 343321936Shselasky uint8_t payload[IB_CC_DATA_SZ] = { 0 }; 344321936Shselasky uint8_t data[IB_CC_DATA_SZ] = { 0 }; 345321936Shselasky uint32_t portnum; 346321936Shselasky uint32_t valid; 347321936Shselasky uint32_t control_type; 348321936Shselasky uint32_t threshold; 349321936Shselasky uint32_t packet_size; 350321936Shselasky uint32_t cong_parm_marking_rate; 351321936Shselasky uint32_t type; 352321936Shselasky uint32_t numports; 353321936Shselasky uint8_t *ptr; 354321936Shselasky char *errstr; 355321936Shselasky 356321936Shselasky if (argc != 6) 357321936Shselasky return "invalid number of parameters for SwitchPortCongestion"; 358321936Shselasky 359321936Shselasky if ((errstr = parseint(argv[0], &portnum, 0))) 360321936Shselasky return errstr; 361321936Shselasky 362321936Shselasky if ((errstr = parseint(argv[1], &valid, 0))) 363321936Shselasky return errstr; 364321936Shselasky 365321936Shselasky if ((errstr = parseint(argv[2], &control_type, 0))) 366321936Shselasky return errstr; 367321936Shselasky 368321936Shselasky if ((errstr = parseint(argv[3], &threshold, 0))) 369321936Shselasky return errstr; 370321936Shselasky 371321936Shselasky if ((errstr = parseint(argv[4], &packet_size, 0))) 372321936Shselasky return errstr; 373321936Shselasky 374321936Shselasky if ((errstr = parseint(argv[5], &cong_parm_marking_rate, 0))) 375321936Shselasky return errstr; 376321936Shselasky 377321936Shselasky /* Figure out number of ports first */ 378321936Shselasky if (!smp_query_via(data, dest, IB_ATTR_NODE_INFO, 0, 0, srcport)) 379321936Shselasky return "node info config failed"; 380321936Shselasky 381321936Shselasky mad_decode_field((uint8_t *)data, IB_NODE_TYPE_F, &type); 382321936Shselasky mad_decode_field((uint8_t *)data, IB_NODE_NPORTS_F, &numports); 383321936Shselasky 384321936Shselasky if (type != IB_NODE_SWITCH) 385321936Shselasky return "destination not a switch"; 386321936Shselasky 387321936Shselasky if (portnum > numports) 388321936Shselasky return "invalid port number specified"; 389321936Shselasky 390321936Shselasky /* We are modifying only 1 port, so get the current config */ 391321936Shselasky if (!cc_query_status_via(payload, dest, IB_CC_ATTR_SWITCH_PORT_CONGESTION_SETTING, 392321936Shselasky portnum / 32, 0, NULL, srcport, cckey)) 393321936Shselasky return "switch port congestion setting query failed"; 394321936Shselasky 395321936Shselasky ptr = payload + (((portnum % 32) * 4)); 396321936Shselasky 397321936Shselasky mad_encode_field(ptr, 398321936Shselasky IB_CC_SWITCH_PORT_CONGESTION_SETTING_ELEMENT_VALID_F, 399321936Shselasky &valid); 400321936Shselasky 401321936Shselasky mad_encode_field(ptr, 402321936Shselasky IB_CC_SWITCH_PORT_CONGESTION_SETTING_ELEMENT_CONTROL_TYPE_F, 403321936Shselasky &control_type); 404321936Shselasky 405321936Shselasky mad_encode_field(ptr, 406321936Shselasky IB_CC_SWITCH_PORT_CONGESTION_SETTING_ELEMENT_THRESHOLD_F, 407321936Shselasky &threshold); 408321936Shselasky 409321936Shselasky mad_encode_field(ptr, 410321936Shselasky IB_CC_SWITCH_PORT_CONGESTION_SETTING_ELEMENT_PACKET_SIZE_F, 411321936Shselasky &packet_size); 412321936Shselasky 413321936Shselasky mad_encode_field(ptr, 414321936Shselasky IB_CC_SWITCH_PORT_CONGESTION_SETTING_ELEMENT_CONG_PARM_MARKING_RATE_F, 415321936Shselasky &cong_parm_marking_rate); 416321936Shselasky 417321936Shselasky if (!cc_config_status_via(payload, rcv, dest, IB_CC_ATTR_SWITCH_PORT_CONGESTION_SETTING, 418321936Shselasky portnum / 32, 0, NULL, srcport, cckey)) 419321936Shselasky return "switch port congestion setting config failed"; 420321936Shselasky 421321936Shselasky return NULL; 422321936Shselasky} 423321936Shselasky 424321936Shselaskystatic char *ca_congestion_setting(ib_portid_t * dest, char **argv, int argc) 425321936Shselasky{ 426321936Shselasky uint8_t rcv[IB_CC_DATA_SZ] = { 0 }; 427321936Shselasky uint8_t payload[IB_CC_DATA_SZ] = { 0 }; 428321936Shselasky uint32_t port_control; 429321936Shselasky uint32_t control_map; 430321936Shselasky uint32_t ccti_timer; 431321936Shselasky uint32_t ccti_increase; 432321936Shselasky uint32_t trigger_threshold; 433321936Shselasky uint32_t ccti_min; 434321936Shselasky char *errstr; 435321936Shselasky int i; 436321936Shselasky 437321936Shselasky if (argc != 6) 438321936Shselasky return "invalid number of parameters for CACongestionSetting"; 439321936Shselasky 440321936Shselasky if ((errstr = parseint(argv[0], &port_control, 0))) 441321936Shselasky return errstr; 442321936Shselasky 443321936Shselasky if ((errstr = parseint(argv[1], &control_map, 0))) 444321936Shselasky return errstr; 445321936Shselasky 446321936Shselasky if ((errstr = parseint(argv[2], &ccti_timer, 0))) 447321936Shselasky return errstr; 448321936Shselasky 449321936Shselasky if ((errstr = parseint(argv[3], &ccti_increase, 0))) 450321936Shselasky return errstr; 451321936Shselasky 452321936Shselasky if ((errstr = parseint(argv[4], &trigger_threshold, 0))) 453321936Shselasky return errstr; 454321936Shselasky 455321936Shselasky if ((errstr = parseint(argv[5], &ccti_min, 0))) 456321936Shselasky return errstr; 457321936Shselasky 458321936Shselasky mad_encode_field(payload, 459321936Shselasky IB_CC_CA_CONGESTION_SETTING_PORT_CONTROL_F, 460321936Shselasky &port_control); 461321936Shselasky 462321936Shselasky mad_encode_field(payload, 463321936Shselasky IB_CC_CA_CONGESTION_SETTING_CONTROL_MAP_F, 464321936Shselasky &control_map); 465321936Shselasky 466321936Shselasky for (i = 0; i < 16; i++) { 467321936Shselasky uint8_t *ptr; 468321936Shselasky 469321936Shselasky if (!(control_map & (0x1 << i))) 470321936Shselasky continue; 471321936Shselasky 472321936Shselasky ptr = payload + 2 + 2 + i * 8; 473321936Shselasky 474321936Shselasky mad_encode_field(ptr, 475321936Shselasky IB_CC_CA_CONGESTION_ENTRY_CCTI_TIMER_F, 476321936Shselasky &ccti_timer); 477321936Shselasky 478321936Shselasky mad_encode_field(ptr, 479321936Shselasky IB_CC_CA_CONGESTION_ENTRY_CCTI_INCREASE_F, 480321936Shselasky &ccti_increase); 481321936Shselasky 482321936Shselasky mad_encode_field(ptr, 483321936Shselasky IB_CC_CA_CONGESTION_ENTRY_TRIGGER_THRESHOLD_F, 484321936Shselasky &trigger_threshold); 485321936Shselasky 486321936Shselasky mad_encode_field(ptr, 487321936Shselasky IB_CC_CA_CONGESTION_ENTRY_CCTI_MIN_F, 488321936Shselasky &ccti_min); 489321936Shselasky } 490321936Shselasky 491321936Shselasky if (!cc_config_status_via(payload, rcv, dest, IB_CC_ATTR_CA_CONGESTION_SETTING, 492321936Shselasky 0, 0, NULL, srcport, cckey)) 493321936Shselasky return "ca congestion setting config failed"; 494321936Shselasky 495321936Shselasky return NULL; 496321936Shselasky} 497321936Shselasky 498321936Shselaskystatic char *congestion_control_table(ib_portid_t * dest, char **argv, int argc) 499321936Shselasky{ 500321936Shselasky uint8_t rcv[IB_CC_DATA_SZ] = { 0 }; 501321936Shselasky uint8_t payload[IB_CC_DATA_SZ] = { 0 }; 502321936Shselasky uint32_t ccti_limit; 503321936Shselasky uint32_t index; 504321936Shselasky uint32_t cctshifts[64]; 505321936Shselasky uint32_t cctmults[64]; 506321936Shselasky char *errstr; 507321936Shselasky int i; 508321936Shselasky 509321936Shselasky if (argc < 2 || argc > 66) 510321936Shselasky return "invalid number of parameters for CongestionControlTable"; 511321936Shselasky 512321936Shselasky if ((errstr = parseint(argv[0], &ccti_limit, 0))) 513321936Shselasky return errstr; 514321936Shselasky 515321936Shselasky if ((errstr = parseint(argv[1], &index, 0))) 516321936Shselasky return errstr; 517321936Shselasky 518321936Shselasky if (ccti_limit && (ccti_limit + 1) != (index * 64 + (argc - 2))) 519321936Shselasky return "invalid number of cct entries input given ccti_limit and index"; 520321936Shselasky 521321936Shselasky for (i = 0; i < (argc - 2); i++) { 522321936Shselasky if ((errstr = parsecct(argv[i + 2], &cctshifts[i], &cctmults[i]))) 523321936Shselasky return errstr; 524321936Shselasky } 525321936Shselasky 526321936Shselasky mad_encode_field(payload, 527321936Shselasky IB_CC_CONGESTION_CONTROL_TABLE_CCTI_LIMIT_F, 528321936Shselasky &ccti_limit); 529321936Shselasky 530321936Shselasky for (i = 0; i < (argc - 2); i++) { 531321936Shselasky mad_encode_field(payload + 4 + i * 2, 532321936Shselasky IB_CC_CONGESTION_CONTROL_TABLE_ENTRY_CCT_SHIFT_F, 533321936Shselasky &cctshifts[i]); 534321936Shselasky 535321936Shselasky mad_encode_field(payload + 4 + i * 2, 536321936Shselasky IB_CC_CONGESTION_CONTROL_TABLE_ENTRY_CCT_MULTIPLIER_F, 537321936Shselasky &cctmults[i]); 538321936Shselasky } 539321936Shselasky 540321936Shselasky if (!cc_config_status_via(payload, rcv, dest, IB_CC_ATTR_CONGESTION_CONTROL_TABLE, 541321936Shselasky index, 0, NULL, srcport, cckey)) 542321936Shselasky return "congestion control table config failed"; 543321936Shselasky 544321936Shselasky return NULL; 545321936Shselasky} 546321936Shselasky 547321936Shselaskystatic int process_opt(void *context, int ch, char *optarg) 548321936Shselasky{ 549321936Shselasky switch (ch) { 550321936Shselasky case 'c': 551321936Shselasky cckey = (uint64_t) strtoull(optarg, 0, 0); 552321936Shselasky break; 553321936Shselasky case 25: 554321936Shselasky if (!inet_pton(AF_INET6, optarg, &dgid)) { 555321936Shselasky fprintf(stderr, "dgid format is wrong!\n"); 556321936Shselasky ibdiag_show_usage(); 557321936Shselasky return 1; 558321936Shselasky } 559321936Shselasky with_grh = 1; 560321936Shselasky break; 561321936Shselasky default: 562321936Shselasky return -1; 563321936Shselasky } 564321936Shselasky return 0; 565321936Shselasky} 566321936Shselasky 567321936Shselaskyint main(int argc, char **argv) 568321936Shselasky{ 569321936Shselasky char usage_args[1024]; 570321936Shselasky int mgmt_classes[3] = { IB_SMI_CLASS, IB_SA_CLASS, IB_CC_CLASS }; 571321936Shselasky ib_portid_t portid = { 0 }; 572321936Shselasky char *err; 573321936Shselasky op_fn_t *fn; 574321936Shselasky const match_rec_t *r; 575321936Shselasky int n; 576321936Shselasky 577321936Shselasky const struct ibdiag_opt opts[] = { 578321936Shselasky {"cckey", 'c', 1, "<key>", "CC key"}, 579321936Shselasky {"dgid", 25, 1, NULL, "remote gid (IPv6 format)"}, 580321936Shselasky {0} 581321936Shselasky }; 582321936Shselasky const char *usage_examples[] = { 583321936Shselasky "SwitchCongestionSetting 2 0x1F 0x1FFFFFFFFF 0x0 0xF 8 0 0:0 1\t# Configure Switch Congestion Settings", 584321936Shselasky "CACongestionSetting 1 0 0x3 150 1 0 0\t\t# Configure CA Congestion Settings to SL 0 and SL 1", 585321936Shselasky "CACongestionSetting 1 0 0x4 200 1 0 0\t\t# Configure CA Congestion Settings to SL 2", 586321936Shselasky "CongestionControlTable 1 63 0 0:0 0:1 ...\t# Configure first block of Congestion Control Table", 587321936Shselasky "CongestionControlTable 1 127 0 0:64 0:65 ...\t# Configure second block of Congestion Control Table", 588321936Shselasky NULL 589321936Shselasky }; 590321936Shselasky 591321936Shselasky n = sprintf(usage_args, "[-c key] <op> <lid|guid>\n" 592321936Shselasky "\nWARNING -- You should understand what you are " 593321936Shselasky "doing before using this tool. Misuse of this " 594321936Shselasky "tool could result in a broken fabric.\n" 595321936Shselasky "\nSupported ops (and aliases, case insensitive):\n"); 596321936Shselasky for (r = match_tbl; r->name; r++) { 597321936Shselasky n += snprintf(usage_args + n, sizeof(usage_args) - n, 598321936Shselasky " %s (%s) <lid|guid>%s%s%s\n", r->name, 599321936Shselasky r->alias ? r->alias : "", 600321936Shselasky r->opt_portnum ? " <portnum>" : "", 601321936Shselasky r->ops_extra ? " " : "", 602321936Shselasky r->ops_extra ? r->ops_extra : ""); 603321936Shselasky if (n >= sizeof(usage_args)) 604321936Shselasky exit(-1); 605321936Shselasky } 606321936Shselasky 607321936Shselasky ibdiag_process_opts(argc, argv, NULL, "DK", opts, process_opt, 608321936Shselasky usage_args, usage_examples); 609321936Shselasky 610321936Shselasky argc -= optind; 611321936Shselasky argv += optind; 612321936Shselasky 613321936Shselasky if (argc < 2) 614321936Shselasky ibdiag_show_usage(); 615321936Shselasky 616321936Shselasky if (!(fn = match_op(match_tbl, argv[0]))) 617321936Shselasky IBEXIT("operation '%s' not supported", argv[0]); 618321936Shselasky 619321936Shselasky srcport = mad_rpc_open_port(ibd_ca, ibd_ca_port, mgmt_classes, 3); 620321936Shselasky if (!srcport) 621321936Shselasky IBEXIT("Failed to open '%s' port '%d'", ibd_ca, ibd_ca_port); 622321936Shselasky 623321936Shselasky smp_mkey_set(srcport, ibd_mkey); 624321936Shselasky 625321936Shselasky if (with_grh && ibd_dest_type != IB_DEST_LID) 626321936Shselasky IBEXIT("When using GRH, LID should be provided"); 627321936Shselasky if (resolve_portid_str(ibd_ca, ibd_ca_port, &portid, argv[1], 628321936Shselasky ibd_dest_type, ibd_sm_id, srcport) < 0) 629321936Shselasky IBEXIT("can't resolve destination %s", argv[1]); 630321936Shselasky if (with_grh) { 631321936Shselasky portid.grh_present = 1; 632321936Shselasky memcpy(&portid.gid, &dgid, sizeof(portid.gid)); 633321936Shselasky } 634321936Shselasky if ((err = fn(&portid, argv + 2, argc - 2))) 635321936Shselasky IBEXIT("operation %s: %s", argv[0], err); 636321936Shselasky 637321936Shselasky mad_rpc_close_port(srcport); 638321936Shselasky exit(0); 639321936Shselasky} 640