1 /* 2 * link.c TIPC link functionality. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Richard Alpe <richard.alpe (at) ericsson.com> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <errno.h> 16 17 #include <linux/tipc_netlink.h> 18 #include <linux/tipc.h> 19 #include <linux/genetlink.h> 20 #include <libmnl/libmnl.h> 21 22 #include "cmdl.h" 23 #include "msg.h" 24 #include "link.h" 25 26 static int link_list_cb(const struct nlmsghdr *nlh, void *data) 27 { 28 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 29 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 30 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; 31 32 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 33 if (!info[TIPC_NLA_LINK]) 34 return MNL_CB_ERROR; 35 36 mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); 37 if (!attrs[TIPC_NLA_LINK_NAME]) 38 return MNL_CB_ERROR; 39 40 printf("%s: ", mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME])); 41 42 if (attrs[TIPC_NLA_LINK_UP]) 43 printf("up\n"); 44 else 45 printf("down\n"); 46 47 return MNL_CB_OK; 48 } 49 50 static int cmd_link_list(struct nlmsghdr *nlh, const struct cmd *cmd, 51 struct cmdl *cmdl, void *data) 52 { 53 char buf[MNL_SOCKET_BUFFER_SIZE]; 54 55 if (help_flag) { 56 fprintf(stderr, "Usage: %s link list\n", cmdl->argv[0]); 57 return -EINVAL; 58 } 59 60 if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) { 61 fprintf(stderr, "error, message initialisation failed\n"); 62 return -1; 63 } 64 65 return msg_dumpit(nlh, link_list_cb, NULL); 66 } 67 68 static int link_get_cb(const struct nlmsghdr *nlh, void *data) 69 { 70 int *prop = data; 71 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 72 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 73 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; 74 struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {}; 75 76 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 77 if (!info[TIPC_NLA_LINK]) 78 return MNL_CB_ERROR; 79 80 mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); 81 if (!attrs[TIPC_NLA_LINK_PROP]) 82 return MNL_CB_ERROR; 83 84 mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_PROP], parse_attrs, props); 85 if (!props[*prop]) 86 return MNL_CB_ERROR; 87 88 printf("%u\n", mnl_attr_get_u32(props[*prop])); 89 90 return MNL_CB_OK; 91 } 92 93 94 static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, 95 struct cmdl *cmdl, void *data) 96 { 97 int prop; 98 char buf[MNL_SOCKET_BUFFER_SIZE]; 99 struct opt *opt; 100 struct opt opts[] = { 101 { "link", NULL }, 102 { NULL } 103 }; 104 105 if (strcmp(cmd->cmd, "priority") == 0) 106 prop = TIPC_NLA_PROP_PRIO; 107 else if ((strcmp(cmd->cmd, "tolerance") == 0)) 108 prop = TIPC_NLA_PROP_TOL; 109 else if ((strcmp(cmd->cmd, "window") == 0)) 110 prop = TIPC_NLA_PROP_WIN; 111 else 112 return -EINVAL; 113 114 if (help_flag) { 115 (cmd->help)(cmdl); 116 return -EINVAL; 117 } 118 119 if (parse_opts(opts, cmdl) < 0) 120 return -EINVAL; 121 122 if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) { 123 fprintf(stderr, "error, message initialisation failed\n"); 124 return -1; 125 } 126 127 if (!(opt = get_opt(opts, "link"))) { 128 fprintf(stderr, "error, missing link\n"); 129 return -EINVAL; 130 } 131 mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, opt->val); 132 133 return msg_doit(nlh, link_get_cb, &prop); 134 } 135 136 static void cmd_link_get_help(struct cmdl *cmdl) 137 { 138 fprintf(stderr, "Usage: %s link get PPROPERTY link LINK\n\n" 139 "PROPERTIES\n" 140 " tolerance - Get link tolerance\n" 141 " priority - Get link priority\n" 142 " window - Get link window\n", 143 cmdl->argv[0]); 144 } 145 146 static int cmd_link_get(struct nlmsghdr *nlh, const struct cmd *cmd, 147 struct cmdl *cmdl, void *data) 148 { 149 const struct cmd cmds[] = { 150 { "priority", cmd_link_get_prop, cmd_link_get_help }, 151 { "tolerance", cmd_link_get_prop, cmd_link_get_help }, 152 { "window", cmd_link_get_prop, cmd_link_get_help }, 153 { NULL } 154 }; 155 156 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 157 } 158 159 static void cmd_link_stat_reset_help(struct cmdl *cmdl) 160 { 161 fprintf(stderr, "Usage: %s link stat reset link LINK\n\n", cmdl->argv[0]); 162 } 163 164 static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd, 165 struct cmdl *cmdl, void *data) 166 { 167 char *link; 168 char buf[MNL_SOCKET_BUFFER_SIZE]; 169 struct opt *opt; 170 struct nlattr *nest; 171 struct opt opts[] = { 172 { "link", NULL }, 173 { NULL } 174 }; 175 176 if (help_flag) { 177 (cmd->help)(cmdl); 178 return -EINVAL; 179 } 180 181 if (parse_opts(opts, cmdl) != 1) { 182 (cmd->help)(cmdl); 183 return -EINVAL; 184 } 185 186 if (!(nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS))) { 187 fprintf(stderr, "error, message initialisation failed\n"); 188 return -1; 189 } 190 191 if (!(opt = get_opt(opts, "link"))) { 192 fprintf(stderr, "error, missing link\n"); 193 return -EINVAL; 194 } 195 link = opt->val; 196 197 nest = mnl_attr_nest_start(nlh, TIPC_NLA_LINK); 198 mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, link); 199 mnl_attr_nest_end(nlh, nest); 200 201 return msg_doit(nlh, NULL, NULL); 202 } 203 204 static uint32_t perc(uint32_t count, uint32_t total) 205 { 206 return (count * 100 + (total / 2)) / total; 207 } 208 209 static int _show_link_stat(struct nlattr *attrs[], struct nlattr *prop[], 210 struct nlattr *stats[]) 211 { 212 uint32_t proft; 213 214 if (attrs[TIPC_NLA_LINK_ACTIVE]) 215 printf(" ACTIVE"); 216 else if (attrs[TIPC_NLA_LINK_UP]) 217 printf(" STANDBY"); 218 else 219 printf(" DEFUNCT"); 220 221 printf(" MTU:%u Priority:%u Tolerance:%u ms Window:%u packets\n", 222 mnl_attr_get_u32(attrs[TIPC_NLA_LINK_MTU]), 223 mnl_attr_get_u32(prop[TIPC_NLA_PROP_PRIO]), 224 mnl_attr_get_u32(prop[TIPC_NLA_PROP_TOL]), 225 mnl_attr_get_u32(prop[TIPC_NLA_PROP_WIN])); 226 227 printf(" RX packets:%u fragments:%u/%u bundles:%u/%u\n", 228 mnl_attr_get_u32(attrs[TIPC_NLA_LINK_RX]) - 229 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_INFO]), 230 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]), 231 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]), 232 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]), 233 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED])); 234 235 printf(" TX packets:%u fragments:%u/%u bundles:%u/%u\n", 236 mnl_attr_get_u32(attrs[TIPC_NLA_LINK_TX]) - 237 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_INFO]), 238 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]), 239 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]), 240 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]), 241 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED])); 242 243 proft = mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]); 244 printf(" TX profile sample:%u packets average:%u octets\n", 245 mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]), 246 mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) / proft); 247 248 printf(" 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% " 249 "-16384:%u%% -32768:%u%% -66000:%u%%\n", 250 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]), proft), 251 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]), proft), 252 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]), proft), 253 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]), proft), 254 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]), proft), 255 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]), proft), 256 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]), proft)); 257 258 printf(" RX states:%u probes:%u naks:%u defs:%u dups:%u\n", 259 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_STATES]), 260 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]), 261 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]), 262 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]), 263 mnl_attr_get_u32(stats[TIPC_NLA_STATS_DUPLICATES])); 264 265 printf(" TX states:%u probes:%u naks:%u acks:%u dups:%u\n", 266 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_STATES]), 267 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]), 268 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]), 269 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]), 270 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED])); 271 272 printf(" Congestion link:%u Send queue max:%u avg:%u\n", 273 mnl_attr_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]), 274 mnl_attr_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]), 275 mnl_attr_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE])); 276 277 return MNL_CB_OK; 278 } 279 280 static int _show_bc_link_stat(struct nlattr *prop[], struct nlattr *stats[]) 281 { 282 printf(" Window:%u packets\n", 283 mnl_attr_get_u32(prop[TIPC_NLA_PROP_WIN])); 284 285 printf(" RX packets:%u fragments:%u/%u bundles:%u/%u\n", 286 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_INFO]), 287 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]), 288 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]), 289 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]), 290 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED])); 291 292 printf(" TX packets:%u fragments:%u/%u bundles:%u/%u\n", 293 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_INFO]), 294 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]), 295 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]), 296 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]), 297 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED])); 298 299 printf(" RX naks:%u defs:%u dups:%u\n", 300 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]), 301 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]), 302 mnl_attr_get_u32(stats[TIPC_NLA_STATS_DUPLICATES])); 303 304 printf(" TX naks:%u acks:%u dups:%u\n", 305 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]), 306 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]), 307 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED])); 308 309 printf(" Congestion link:%u Send queue max:%u avg:%u\n", 310 mnl_attr_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]), 311 mnl_attr_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]), 312 mnl_attr_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE])); 313 314 return MNL_CB_OK; 315 } 316 317 static int link_stat_show_cb(const struct nlmsghdr *nlh, void *data) 318 { 319 const char *name; 320 const char *link = data; 321 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 322 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 323 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; 324 struct nlattr *prop[TIPC_NLA_PROP_MAX + 1] = {}; 325 struct nlattr *stats[TIPC_NLA_STATS_MAX + 1] = {}; 326 327 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 328 if (!info[TIPC_NLA_LINK]) 329 return MNL_CB_ERROR; 330 331 mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); 332 if (!attrs[TIPC_NLA_LINK_NAME] || !attrs[TIPC_NLA_LINK_PROP] || 333 !attrs[TIPC_NLA_LINK_STATS]) 334 return MNL_CB_ERROR; 335 336 mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_PROP], parse_attrs, prop); 337 mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_STATS], parse_attrs, stats); 338 339 name = mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME]); 340 341 /* If a link is passed, skip all but that link */ 342 if (link && (strcmp(name, link) != 0)) 343 return MNL_CB_OK; 344 345 if (attrs[TIPC_NLA_LINK_BROADCAST]) { 346 printf("Link <%s>\n", name); 347 return _show_bc_link_stat(prop, stats); 348 } 349 350 printf("\nLink <%s>\n", name); 351 352 return _show_link_stat(attrs, prop, stats); 353 } 354 355 static void cmd_link_stat_show_help(struct cmdl *cmdl) 356 { 357 fprintf(stderr, "Usage: %s link stat show [ link LINK ]\n", 358 cmdl->argv[0]); 359 } 360 361 static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, 362 struct cmdl *cmdl, void *data) 363 { 364 char *link = NULL; 365 char buf[MNL_SOCKET_BUFFER_SIZE]; 366 struct opt *opt; 367 struct opt opts[] = { 368 { "link", NULL }, 369 { NULL } 370 }; 371 372 if (help_flag) { 373 (cmd->help)(cmdl); 374 return -EINVAL; 375 } 376 377 if (!(nlh = msg_init(buf, TIPC_NL_LINK_GET))) { 378 fprintf(stderr, "error, message initialisation failed\n"); 379 return -1; 380 } 381 382 if (parse_opts(opts, cmdl) < 0) 383 return -EINVAL; 384 385 if ((opt = get_opt(opts, "link"))) 386 link = opt->val; 387 388 return msg_dumpit(nlh, link_stat_show_cb, link); 389 } 390 391 static void cmd_link_stat_help(struct cmdl *cmdl) 392 { 393 fprintf(stderr, "Usage: %s link stat COMMAND [ARGS]\n\n" 394 "COMMANDS:\n" 395 " reset - Reset link statistics for link\n" 396 " show - Get link priority\n", 397 cmdl->argv[0]); 398 } 399 400 static int cmd_link_stat(struct nlmsghdr *nlh, const struct cmd *cmd, 401 struct cmdl *cmdl, void *data) 402 { 403 const struct cmd cmds[] = { 404 { "reset", cmd_link_stat_reset, cmd_link_stat_reset_help }, 405 { "show", cmd_link_stat_show, cmd_link_stat_show_help }, 406 { NULL } 407 }; 408 409 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 410 } 411 412 static void cmd_link_set_help(struct cmdl *cmdl) 413 { 414 fprintf(stderr, "Usage: %s link set PPROPERTY link LINK\n\n" 415 "PROPERTIES\n" 416 " tolerance TOLERANCE - Set link tolerance\n" 417 " priority PRIORITY - Set link priority\n" 418 " window WINDOW - Set link window\n", 419 cmdl->argv[0]); 420 } 421 422 static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, 423 struct cmdl *cmdl, void *data) 424 { 425 int val; 426 int prop; 427 char buf[MNL_SOCKET_BUFFER_SIZE]; 428 struct nlattr *props; 429 struct nlattr *attrs; 430 struct opt *opt; 431 struct opt opts[] = { 432 { "link", NULL }, 433 { NULL } 434 }; 435 436 if (strcmp(cmd->cmd, "priority") == 0) 437 prop = TIPC_NLA_PROP_PRIO; 438 else if ((strcmp(cmd->cmd, "tolerance") == 0)) 439 prop = TIPC_NLA_PROP_TOL; 440 else if ((strcmp(cmd->cmd, "window") == 0)) 441 prop = TIPC_NLA_PROP_WIN; 442 else 443 return -EINVAL; 444 445 if (help_flag) { 446 (cmd->help)(cmdl); 447 return -EINVAL; 448 } 449 450 if (cmdl->optind >= cmdl->argc) { 451 fprintf(stderr, "error, missing value\n"); 452 return -EINVAL; 453 } 454 val = atoi(shift_cmdl(cmdl)); 455 456 if (parse_opts(opts, cmdl) < 0) 457 return -EINVAL; 458 459 if (!(nlh = msg_init(buf, TIPC_NL_LINK_SET))) { 460 fprintf(stderr, "error, message initialisation failed\n"); 461 return -1; 462 } 463 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_LINK); 464 465 if (!(opt = get_opt(opts, "link"))) { 466 fprintf(stderr, "error, missing link\n"); 467 return -EINVAL; 468 } 469 mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, opt->val); 470 471 props = mnl_attr_nest_start(nlh, TIPC_NLA_LINK_PROP); 472 mnl_attr_put_u32(nlh, prop, val); 473 mnl_attr_nest_end(nlh, props); 474 475 mnl_attr_nest_end(nlh, attrs); 476 477 return msg_doit(nlh, link_get_cb, &prop); 478 479 return 0; 480 } 481 482 static int cmd_link_set(struct nlmsghdr *nlh, const struct cmd *cmd, 483 struct cmdl *cmdl, void *data) 484 { 485 const struct cmd cmds[] = { 486 { "priority", cmd_link_set_prop, cmd_link_set_help }, 487 { "tolerance", cmd_link_set_prop, cmd_link_set_help }, 488 { "window", cmd_link_set_prop, cmd_link_set_help }, 489 { NULL } 490 }; 491 492 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 493 } 494 495 void cmd_link_help(struct cmdl *cmdl) 496 { 497 fprintf(stderr, 498 "Usage: %s link COMMAND [ARGS] ...\n" 499 "\n" 500 "COMMANDS\n" 501 " list - List links\n" 502 " get - Get various link properties\n" 503 " set - Set various link properties\n" 504 " statistics - Show or reset statistics\n", 505 cmdl->argv[0]); 506 } 507 508 int cmd_link(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, 509 void *data) 510 { 511 const struct cmd cmds[] = { 512 { "get", cmd_link_get, cmd_link_get_help }, 513 { "list", cmd_link_list, NULL }, 514 { "set", cmd_link_set, cmd_link_set_help }, 515 { "statistics", cmd_link_stat, cmd_link_stat_help }, 516 { NULL } 517 }; 518 519 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 520 } 521