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 #include "bearer.h" 26 27 static int link_list_cb(const struct nlmsghdr *nlh, void *data) 28 { 29 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 30 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 31 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; 32 33 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 34 if (!info[TIPC_NLA_LINK]) 35 return MNL_CB_ERROR; 36 37 mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); 38 if (!attrs[TIPC_NLA_LINK_NAME]) 39 return MNL_CB_ERROR; 40 41 printf("%s: ", mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME])); 42 43 if (attrs[TIPC_NLA_LINK_UP]) 44 printf("up\n"); 45 else 46 printf("down\n"); 47 48 return MNL_CB_OK; 49 } 50 51 static int cmd_link_list(struct nlmsghdr *nlh, const struct cmd *cmd, 52 struct cmdl *cmdl, void *data) 53 { 54 char buf[MNL_SOCKET_BUFFER_SIZE]; 55 56 if (help_flag) { 57 fprintf(stderr, "Usage: %s link list\n", cmdl->argv[0]); 58 return -EINVAL; 59 } 60 61 nlh = msg_init(buf, TIPC_NL_LINK_GET); 62 if (!nlh) { 63 fprintf(stderr, "error, message initialisation failed\n"); 64 return -1; 65 } 66 67 return msg_dumpit(nlh, link_list_cb, NULL); 68 } 69 70 static int link_get_cb(const struct nlmsghdr *nlh, void *data) 71 { 72 int *prop = data; 73 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 74 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 75 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; 76 struct nlattr *props[TIPC_NLA_PROP_MAX + 1] = {}; 77 78 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 79 if (!info[TIPC_NLA_LINK]) 80 return MNL_CB_ERROR; 81 82 mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); 83 if (!attrs[TIPC_NLA_LINK_PROP]) 84 return MNL_CB_ERROR; 85 86 mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_PROP], parse_attrs, props); 87 if (!props[*prop]) 88 return MNL_CB_ERROR; 89 90 printf("%u\n", mnl_attr_get_u32(props[*prop])); 91 92 return MNL_CB_OK; 93 } 94 95 static int cmd_link_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, 96 struct cmdl *cmdl, void *data) 97 { 98 int prop; 99 char buf[MNL_SOCKET_BUFFER_SIZE]; 100 struct opt *opt; 101 struct opt opts[] = { 102 { "link", OPT_KEYVAL, NULL }, 103 { NULL } 104 }; 105 106 if (strcmp(cmd->cmd, "priority") == 0) 107 prop = TIPC_NLA_PROP_PRIO; 108 else if ((strcmp(cmd->cmd, "tolerance") == 0)) 109 prop = TIPC_NLA_PROP_TOL; 110 else if ((strcmp(cmd->cmd, "window") == 0)) 111 prop = TIPC_NLA_PROP_WIN; 112 else 113 return -EINVAL; 114 115 if (help_flag) { 116 (cmd->help)(cmdl); 117 return -EINVAL; 118 } 119 120 if (parse_opts(opts, cmdl) < 0) 121 return -EINVAL; 122 123 nlh = msg_init(buf, TIPC_NL_LINK_GET); 124 if (!nlh) { 125 fprintf(stderr, "error, message initialisation failed\n"); 126 return -1; 127 } 128 129 opt = get_opt(opts, "link"); 130 if (!opt) { 131 fprintf(stderr, "error, missing link\n"); 132 return -EINVAL; 133 } 134 mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, opt->val); 135 136 return msg_doit(nlh, link_get_cb, &prop); 137 } 138 139 static void cmd_link_get_help(struct cmdl *cmdl) 140 { 141 fprintf(stderr, "Usage: %s link get PPROPERTY link LINK\n\n" 142 "PROPERTIES\n" 143 " tolerance - Get link tolerance\n" 144 " priority - Get link priority\n" 145 " window - Get link window\n", 146 cmdl->argv[0]); 147 } 148 149 static int cmd_link_get(struct nlmsghdr *nlh, const struct cmd *cmd, 150 struct cmdl *cmdl, void *data) 151 { 152 const struct cmd cmds[] = { 153 { "priority", cmd_link_get_prop, cmd_link_get_help }, 154 { "tolerance", cmd_link_get_prop, cmd_link_get_help }, 155 { "window", cmd_link_get_prop, cmd_link_get_help }, 156 { NULL } 157 }; 158 159 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 160 } 161 162 static void cmd_link_stat_reset_help(struct cmdl *cmdl) 163 { 164 fprintf(stderr, "Usage: %s link stat reset link LINK\n\n", cmdl->argv[0]); 165 } 166 167 static int cmd_link_stat_reset(struct nlmsghdr *nlh, const struct cmd *cmd, 168 struct cmdl *cmdl, void *data) 169 { 170 char *link; 171 char buf[MNL_SOCKET_BUFFER_SIZE]; 172 struct opt *opt; 173 struct nlattr *nest; 174 struct opt opts[] = { 175 { "link", OPT_KEYVAL, NULL }, 176 { NULL } 177 }; 178 179 if (help_flag) { 180 (cmd->help)(cmdl); 181 return -EINVAL; 182 } 183 184 if (parse_opts(opts, cmdl) != 1) { 185 (cmd->help)(cmdl); 186 return -EINVAL; 187 } 188 189 nlh = msg_init(buf, TIPC_NL_LINK_RESET_STATS); 190 if (!nlh) { 191 fprintf(stderr, "error, message initialisation failed\n"); 192 return -1; 193 } 194 195 opt = get_opt(opts, "link"); 196 if (!opt) { 197 fprintf(stderr, "error, missing link\n"); 198 return -EINVAL; 199 } 200 link = opt->val; 201 202 nest = mnl_attr_nest_start(nlh, TIPC_NLA_LINK); 203 mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, link); 204 mnl_attr_nest_end(nlh, nest); 205 206 return msg_doit(nlh, NULL, NULL); 207 } 208 209 static uint32_t perc(uint32_t count, uint32_t total) 210 { 211 return (count * 100 + (total / 2)) / total; 212 } 213 214 static int _show_link_stat(struct nlattr *attrs[], struct nlattr *prop[], 215 struct nlattr *stats[]) 216 { 217 uint32_t proft; 218 219 if (attrs[TIPC_NLA_LINK_ACTIVE]) 220 printf(" ACTIVE"); 221 else if (attrs[TIPC_NLA_LINK_UP]) 222 printf(" STANDBY"); 223 else 224 printf(" DEFUNCT"); 225 226 printf(" MTU:%u Priority:%u Tolerance:%u ms Window:%u packets\n", 227 mnl_attr_get_u32(attrs[TIPC_NLA_LINK_MTU]), 228 mnl_attr_get_u32(prop[TIPC_NLA_PROP_PRIO]), 229 mnl_attr_get_u32(prop[TIPC_NLA_PROP_TOL]), 230 mnl_attr_get_u32(prop[TIPC_NLA_PROP_WIN])); 231 232 printf(" RX packets:%u fragments:%u/%u bundles:%u/%u\n", 233 mnl_attr_get_u32(attrs[TIPC_NLA_LINK_RX]) - 234 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_INFO]), 235 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]), 236 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]), 237 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]), 238 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED])); 239 240 printf(" TX packets:%u fragments:%u/%u bundles:%u/%u\n", 241 mnl_attr_get_u32(attrs[TIPC_NLA_LINK_TX]) - 242 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_INFO]), 243 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]), 244 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]), 245 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]), 246 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED])); 247 248 proft = mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]); 249 printf(" TX profile sample:%u packets average:%u octets\n", 250 mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]), 251 mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) / proft); 252 253 printf(" 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% -16384:%u%% -32768:%u%% -66000:%u%%\n", 254 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]), proft), 255 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]), proft), 256 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]), proft), 257 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]), proft), 258 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]), proft), 259 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]), proft), 260 perc(mnl_attr_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]), proft)); 261 262 printf(" RX states:%u probes:%u naks:%u defs:%u dups:%u\n", 263 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_STATES]), 264 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]), 265 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]), 266 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]), 267 mnl_attr_get_u32(stats[TIPC_NLA_STATS_DUPLICATES])); 268 269 printf(" TX states:%u probes:%u naks:%u acks:%u dups:%u\n", 270 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_STATES]), 271 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]), 272 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]), 273 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]), 274 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED])); 275 276 printf(" Congestion link:%u Send queue max:%u avg:%u\n", 277 mnl_attr_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]), 278 mnl_attr_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]), 279 mnl_attr_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE])); 280 281 return MNL_CB_OK; 282 } 283 284 static int _show_bc_link_stat(struct nlattr *prop[], struct nlattr *stats[]) 285 { 286 printf(" Window:%u packets\n", 287 mnl_attr_get_u32(prop[TIPC_NLA_PROP_WIN])); 288 289 printf(" RX packets:%u fragments:%u/%u bundles:%u/%u\n", 290 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_INFO]), 291 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]), 292 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]), 293 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]), 294 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED])); 295 296 printf(" TX packets:%u fragments:%u/%u bundles:%u/%u\n", 297 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_INFO]), 298 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]), 299 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]), 300 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]), 301 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED])); 302 303 printf(" RX naks:%u defs:%u dups:%u\n", 304 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]), 305 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]), 306 mnl_attr_get_u32(stats[TIPC_NLA_STATS_DUPLICATES])); 307 308 printf(" TX naks:%u acks:%u dups:%u\n", 309 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]), 310 mnl_attr_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]), 311 mnl_attr_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED])); 312 313 printf(" Congestion link:%u Send queue max:%u avg:%u\n", 314 mnl_attr_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]), 315 mnl_attr_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]), 316 mnl_attr_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE])); 317 318 return MNL_CB_OK; 319 } 320 321 static int link_stat_show_cb(const struct nlmsghdr *nlh, void *data) 322 { 323 const char *name; 324 const char *link = data; 325 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 326 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 327 struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1] = {}; 328 struct nlattr *prop[TIPC_NLA_PROP_MAX + 1] = {}; 329 struct nlattr *stats[TIPC_NLA_STATS_MAX + 1] = {}; 330 331 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 332 if (!info[TIPC_NLA_LINK]) 333 return MNL_CB_ERROR; 334 335 mnl_attr_parse_nested(info[TIPC_NLA_LINK], parse_attrs, attrs); 336 if (!attrs[TIPC_NLA_LINK_NAME] || !attrs[TIPC_NLA_LINK_PROP] || 337 !attrs[TIPC_NLA_LINK_STATS]) 338 return MNL_CB_ERROR; 339 340 mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_PROP], parse_attrs, prop); 341 mnl_attr_parse_nested(attrs[TIPC_NLA_LINK_STATS], parse_attrs, stats); 342 343 name = mnl_attr_get_str(attrs[TIPC_NLA_LINK_NAME]); 344 345 /* If a link is passed, skip all but that link */ 346 if (link && (strcmp(name, link) != 0)) 347 return MNL_CB_OK; 348 349 if (attrs[TIPC_NLA_LINK_BROADCAST]) { 350 printf("Link <%s>\n", name); 351 return _show_bc_link_stat(prop, stats); 352 } 353 354 printf("\nLink <%s>\n", name); 355 356 return _show_link_stat(attrs, prop, stats); 357 } 358 359 static void cmd_link_stat_show_help(struct cmdl *cmdl) 360 { 361 fprintf(stderr, "Usage: %s link stat show [ link LINK ]\n", 362 cmdl->argv[0]); 363 } 364 365 static int cmd_link_stat_show(struct nlmsghdr *nlh, const struct cmd *cmd, 366 struct cmdl *cmdl, void *data) 367 { 368 char *link = NULL; 369 char buf[MNL_SOCKET_BUFFER_SIZE]; 370 struct opt *opt; 371 struct opt opts[] = { 372 { "link", OPT_KEYVAL, NULL }, 373 { NULL } 374 }; 375 376 if (help_flag) { 377 (cmd->help)(cmdl); 378 return -EINVAL; 379 } 380 381 nlh = msg_init(buf, TIPC_NL_LINK_GET); 382 if (!nlh) { 383 fprintf(stderr, "error, message initialisation failed\n"); 384 return -1; 385 } 386 387 if (parse_opts(opts, cmdl) < 0) 388 return -EINVAL; 389 390 opt = get_opt(opts, "link"); 391 if (opt) 392 link = opt->val; 393 394 return msg_dumpit(nlh, link_stat_show_cb, link); 395 } 396 397 static void cmd_link_stat_help(struct cmdl *cmdl) 398 { 399 fprintf(stderr, "Usage: %s link stat COMMAND [ARGS]\n\n" 400 "COMMANDS:\n" 401 " reset - Reset link statistics for link\n" 402 " show - Get link priority\n", 403 cmdl->argv[0]); 404 } 405 406 static int cmd_link_stat(struct nlmsghdr *nlh, const struct cmd *cmd, 407 struct cmdl *cmdl, void *data) 408 { 409 const struct cmd cmds[] = { 410 { "reset", cmd_link_stat_reset, cmd_link_stat_reset_help }, 411 { "show", cmd_link_stat_show, cmd_link_stat_show_help }, 412 { NULL } 413 }; 414 415 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 416 } 417 418 static void cmd_link_set_help(struct cmdl *cmdl) 419 { 420 fprintf(stderr, "Usage: %s link set PPROPERTY link LINK\n\n" 421 "PROPERTIES\n" 422 " tolerance TOLERANCE - Set link tolerance\n" 423 " priority PRIORITY - Set link priority\n" 424 " window WINDOW - Set link window\n", 425 cmdl->argv[0]); 426 } 427 428 static int cmd_link_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, 429 struct cmdl *cmdl, void *data) 430 { 431 int val; 432 int prop; 433 char buf[MNL_SOCKET_BUFFER_SIZE]; 434 struct nlattr *props; 435 struct nlattr *attrs; 436 struct opt *opt; 437 struct opt opts[] = { 438 { "link", OPT_KEYVAL, NULL }, 439 { NULL } 440 }; 441 442 if (strcmp(cmd->cmd, "priority") == 0) 443 prop = TIPC_NLA_PROP_PRIO; 444 else if ((strcmp(cmd->cmd, "tolerance") == 0)) 445 prop = TIPC_NLA_PROP_TOL; 446 else if ((strcmp(cmd->cmd, "window") == 0)) 447 prop = TIPC_NLA_PROP_WIN; 448 else 449 return -EINVAL; 450 451 if (help_flag) { 452 (cmd->help)(cmdl); 453 return -EINVAL; 454 } 455 456 if (cmdl->optind >= cmdl->argc) { 457 fprintf(stderr, "error, missing value\n"); 458 return -EINVAL; 459 } 460 val = atoi(shift_cmdl(cmdl)); 461 462 if (parse_opts(opts, cmdl) < 0) 463 return -EINVAL; 464 465 nlh = msg_init(buf, TIPC_NL_LINK_SET); 466 if (!nlh) { 467 fprintf(stderr, "error, message initialisation failed\n"); 468 return -1; 469 } 470 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_LINK); 471 472 opt = get_opt(opts, "link"); 473 if (!opt) { 474 fprintf(stderr, "error, missing link\n"); 475 return -EINVAL; 476 } 477 mnl_attr_put_strz(nlh, TIPC_NLA_LINK_NAME, opt->val); 478 479 props = mnl_attr_nest_start(nlh, TIPC_NLA_LINK_PROP); 480 mnl_attr_put_u32(nlh, prop, val); 481 mnl_attr_nest_end(nlh, props); 482 483 mnl_attr_nest_end(nlh, attrs); 484 485 return msg_doit(nlh, link_get_cb, &prop); 486 } 487 488 static int cmd_link_set(struct nlmsghdr *nlh, const struct cmd *cmd, 489 struct cmdl *cmdl, void *data) 490 { 491 const struct cmd cmds[] = { 492 { "priority", cmd_link_set_prop, cmd_link_set_help }, 493 { "tolerance", cmd_link_set_prop, cmd_link_set_help }, 494 { "window", cmd_link_set_prop, cmd_link_set_help }, 495 { NULL } 496 }; 497 498 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 499 } 500 501 static int cmd_link_mon_set_prop(struct nlmsghdr *nlh, const struct cmd *cmd, 502 struct cmdl *cmdl, void *data) 503 { 504 int size; 505 char buf[MNL_SOCKET_BUFFER_SIZE]; 506 struct nlattr *attrs; 507 508 if (cmdl->argc != cmdl->optind + 1) { 509 fprintf(stderr, "error, missing value\n"); 510 return -EINVAL; 511 } 512 size = atoi(shift_cmdl(cmdl)); 513 514 nlh = msg_init(buf, TIPC_NL_MON_SET); 515 if (!nlh) { 516 fprintf(stderr, "error, message initialisation failed\n"); 517 return -1; 518 } 519 attrs = mnl_attr_nest_start(nlh, TIPC_NLA_MON); 520 521 mnl_attr_put_u32(nlh, TIPC_NLA_MON_ACTIVATION_THRESHOLD, size); 522 523 mnl_attr_nest_end(nlh, attrs); 524 525 return msg_doit(nlh, NULL, NULL); 526 } 527 528 static int link_mon_summary_cb(const struct nlmsghdr *nlh, void *data) 529 { 530 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 531 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 532 struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; 533 534 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 535 if (!info[TIPC_NLA_MON]) 536 return MNL_CB_ERROR; 537 538 mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); 539 540 printf("\nbearer %s\n", 541 mnl_attr_get_str(attrs[TIPC_NLA_MON_BEARER_NAME])); 542 543 printf(" table_generation %u\n", 544 mnl_attr_get_u32(attrs[TIPC_NLA_MON_LISTGEN])); 545 printf(" cluster_size %u\n", 546 mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEERCNT])); 547 printf(" algorithm %s\n", 548 attrs[TIPC_NLA_MON_ACTIVE] ? "overlapping-ring" : "full-mesh"); 549 550 return MNL_CB_OK; 551 } 552 553 static int cmd_link_mon_summary(struct nlmsghdr *nlh, const struct cmd *cmd, 554 struct cmdl *cmdl, void *data) 555 { 556 char buf[MNL_SOCKET_BUFFER_SIZE]; 557 558 if (help_flag) { 559 fprintf(stderr, "Usage: %s monitor summary\n", cmdl->argv[0]); 560 return -EINVAL; 561 } 562 563 nlh = msg_init(buf, TIPC_NL_MON_GET); 564 if (!nlh) { 565 fprintf(stderr, "error, message initialisation failed\n"); 566 return -1; 567 } 568 569 return msg_dumpit(nlh, link_mon_summary_cb, NULL); 570 } 571 572 #define STATUS_WIDTH 7 573 #define MAX_NODE_WIDTH 14 /* 255.4095.4095 */ 574 #define MAX_DOM_GEN_WIDTH 11 /* 65535 */ 575 #define DIRECTLY_MON_WIDTH 10 576 577 #define APPL_NODE_STATUS_WIDTH 5 578 579 static int map_get(uint64_t up_map, int i) 580 { 581 return (up_map & (1 << i)) >> i; 582 } 583 584 /* print the applied members, since we know the the members 585 * are listed in ascending order, we print only the state 586 */ 587 static void link_mon_print_applied(uint16_t applied, uint64_t up_map) 588 { 589 int i; 590 char state; 591 592 for (i = 0; i < applied; i++) { 593 /* print the delimiter for every -n- entry */ 594 if (i && !(i % APPL_NODE_STATUS_WIDTH)) 595 printf(","); 596 597 state = map_get(up_map, i) ? 'U' : 'D'; 598 printf("%c", state); 599 } 600 } 601 602 /* print the non applied members, since we dont know 603 * the members, we print them along with the state 604 */ 605 static void link_mon_print_non_applied(uint16_t applied, uint16_t member_cnt, 606 uint64_t up_map, uint32_t *members) 607 { 608 int i; 609 char state; 610 611 printf(" ["); 612 for (i = applied; i < member_cnt; i++) { 613 char addr_str[16]; 614 615 /* print the delimiter for every entry */ 616 if (i != applied) 617 printf(","); 618 619 sprintf(addr_str, "%u.%u.%u:", tipc_zone(members[i]), 620 tipc_cluster(members[i]), tipc_node(members[i])); 621 state = map_get(up_map, i) ? 'U' : 'D'; 622 printf("%s%c", addr_str, state); 623 } 624 printf("]"); 625 } 626 627 static void link_mon_print_peer_state(const uint32_t addr, const char *status, 628 const char *monitored, 629 const uint32_t dom_gen) 630 { 631 char addr_str[16]; 632 633 sprintf(addr_str, "%u.%u.%u", tipc_zone(addr), tipc_cluster(addr), 634 tipc_node(addr)); 635 636 printf("%-*s", MAX_NODE_WIDTH, addr_str); 637 printf("%-*s", STATUS_WIDTH, status); 638 printf("%-*s", DIRECTLY_MON_WIDTH, monitored); 639 printf("%-*u", MAX_DOM_GEN_WIDTH, dom_gen); 640 } 641 642 static int link_mon_peer_list_cb(const struct nlmsghdr *nlh, void *data) 643 { 644 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 645 struct nlattr *attrs[TIPC_NLA_MON_PEER_MAX + 1] = {}; 646 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 647 uint16_t member_cnt; 648 uint32_t applied; 649 uint32_t dom_gen; 650 uint64_t up_map; 651 char status[16]; 652 char monitored[16]; 653 654 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 655 if (!info[TIPC_NLA_MON_PEER]) 656 return MNL_CB_ERROR; 657 658 mnl_attr_parse_nested(info[TIPC_NLA_MON_PEER], parse_attrs, attrs); 659 660 (attrs[TIPC_NLA_MON_PEER_LOCAL] || attrs[TIPC_NLA_MON_PEER_HEAD]) ? 661 strcpy(monitored, "direct") : 662 strcpy(monitored, "indirect"); 663 664 attrs[TIPC_NLA_MON_PEER_UP] ? 665 strcpy(status, "up") : 666 strcpy(status, "down"); 667 668 dom_gen = attrs[TIPC_NLA_MON_PEER_DOMGEN] ? 669 mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_DOMGEN]) : 0; 670 671 link_mon_print_peer_state(mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_ADDR]), 672 status, monitored, dom_gen); 673 674 applied = mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEER_APPLIED]); 675 676 if (!applied) 677 goto exit; 678 679 up_map = mnl_attr_get_u64(attrs[TIPC_NLA_MON_PEER_UPMAP]); 680 681 member_cnt = mnl_attr_get_payload_len(attrs[TIPC_NLA_MON_PEER_MEMBERS]); 682 683 /* each tipc address occupies 4 bytes of payload, hence compensate it */ 684 member_cnt /= sizeof(uint32_t); 685 686 link_mon_print_applied(applied, up_map); 687 688 link_mon_print_non_applied(applied, member_cnt, up_map, 689 mnl_attr_get_payload(attrs[TIPC_NLA_MON_PEER_MEMBERS])); 690 691 exit: 692 printf("\n"); 693 694 return MNL_CB_OK; 695 } 696 697 static int link_mon_peer_list(uint32_t mon_ref) 698 { 699 struct nlmsghdr *nlh; 700 char buf[MNL_SOCKET_BUFFER_SIZE]; 701 struct nlattr *nest; 702 703 nlh = msg_init(buf, TIPC_NL_MON_PEER_GET); 704 if (!nlh) { 705 fprintf(stderr, "error, message initialisation failed\n"); 706 return -1; 707 } 708 709 nest = mnl_attr_nest_start(nlh, TIPC_NLA_MON); 710 mnl_attr_put_u32(nlh, TIPC_NLA_MON_REF, mon_ref); 711 mnl_attr_nest_end(nlh, nest); 712 713 return msg_dumpit(nlh, link_mon_peer_list_cb, NULL); 714 } 715 716 static int link_mon_list_cb(const struct nlmsghdr *nlh, void *data) 717 { 718 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 719 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 720 struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; 721 char *req_bearer = data; 722 const char *bname; 723 const char title[] = 724 "node status monitored generation applied_node_status [non_applied_node:status]"; 725 726 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 727 if (!info[TIPC_NLA_MON]) 728 return MNL_CB_ERROR; 729 730 mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); 731 732 bname = mnl_attr_get_str(attrs[TIPC_NLA_MON_BEARER_NAME]); 733 734 if (*req_bearer && (strcmp(req_bearer, bname) != 0)) 735 return MNL_CB_OK; 736 737 printf("\nbearer %s\n", bname); 738 printf("%s\n", title); 739 740 if (mnl_attr_get_u32(attrs[TIPC_NLA_MON_PEERCNT])) 741 link_mon_peer_list(mnl_attr_get_u32(attrs[TIPC_NLA_MON_REF])); 742 743 return MNL_CB_OK; 744 } 745 746 static void cmd_link_mon_list_help(struct cmdl *cmdl) 747 { 748 fprintf(stderr, "Usage: %s monitor list [ media MEDIA ARGS...]\n\n", 749 cmdl->argv[0]); 750 print_bearer_media(); 751 } 752 753 static void cmd_link_mon_list_l2_help(struct cmdl *cmdl, char *media) 754 { 755 fprintf(stderr, 756 "Usage: %s monitor list media %s device DEVICE [OPTIONS]\n", 757 cmdl->argv[0], media); 758 } 759 760 static void cmd_link_mon_list_udp_help(struct cmdl *cmdl, char *media) 761 { 762 fprintf(stderr, 763 "Usage: %s monitor list media udp name NAME\n\n", 764 cmdl->argv[0]); 765 } 766 767 static int cmd_link_mon_list(struct nlmsghdr *nlh, const struct cmd *cmd, 768 struct cmdl *cmdl, void *data) 769 { 770 char buf[MNL_SOCKET_BUFFER_SIZE]; 771 char bname[TIPC_MAX_BEARER_NAME] = {0}; 772 struct opt opts[] = { 773 { "media", OPT_KEYVAL, NULL }, 774 { "device", OPT_KEYVAL, NULL }, 775 { "name", OPT_KEYVAL, NULL }, 776 { NULL } 777 }; 778 struct tipc_sup_media sup_media[] = { 779 { "udp", "name", cmd_link_mon_list_udp_help}, 780 { "eth", "device", cmd_link_mon_list_l2_help }, 781 { "ib", "device", cmd_link_mon_list_l2_help }, 782 { NULL, }, 783 }; 784 785 int err; 786 787 if (parse_opts(opts, cmdl) < 0) 788 return -EINVAL; 789 790 if (get_opt(opts, "media")) { 791 err = cmd_get_unique_bearer_name(cmd, cmdl, opts, bname, 792 sup_media); 793 if (err) 794 return err; 795 } 796 797 if (help_flag) { 798 cmd->help(cmdl); 799 return -EINVAL; 800 } 801 802 nlh = msg_init(buf, TIPC_NL_MON_GET); 803 if (!nlh) { 804 fprintf(stderr, "error, message initialisation failed\n"); 805 return -1; 806 } 807 808 return msg_dumpit(nlh, link_mon_list_cb, bname); 809 } 810 811 static void cmd_link_mon_set_help(struct cmdl *cmdl) 812 { 813 fprintf(stderr, "Usage: %s monitor set PPROPERTY\n\n" 814 "PROPERTIES\n" 815 " threshold SIZE - Set monitor activation threshold\n", 816 cmdl->argv[0]); 817 } 818 819 static int cmd_link_mon_set(struct nlmsghdr *nlh, const struct cmd *cmd, 820 struct cmdl *cmdl, void *data) 821 { 822 const struct cmd cmds[] = { 823 { "threshold", cmd_link_mon_set_prop, NULL }, 824 { NULL } 825 }; 826 827 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 828 } 829 830 static void cmd_link_mon_get_help(struct cmdl *cmdl) 831 { 832 fprintf(stderr, "Usage: %s monitor get PPROPERTY\n\n" 833 "PROPERTIES\n" 834 " threshold - Get monitor activation threshold\n", 835 cmdl->argv[0]); 836 } 837 838 static int link_mon_get_cb(const struct nlmsghdr *nlh, void *data) 839 { 840 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh); 841 struct nlattr *info[TIPC_NLA_MAX + 1] = {}; 842 struct nlattr *attrs[TIPC_NLA_MON_MAX + 1] = {}; 843 844 mnl_attr_parse(nlh, sizeof(*genl), parse_attrs, info); 845 if (!info[TIPC_NLA_MON]) 846 return MNL_CB_ERROR; 847 848 mnl_attr_parse_nested(info[TIPC_NLA_MON], parse_attrs, attrs); 849 if (!attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD]) 850 return MNL_CB_ERROR; 851 852 printf("%u\n", 853 mnl_attr_get_u32(attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD])); 854 855 return MNL_CB_OK; 856 } 857 858 static int cmd_link_mon_get_prop(struct nlmsghdr *nlh, const struct cmd *cmd, 859 struct cmdl *cmdl, void *data) 860 { 861 char buf[MNL_SOCKET_BUFFER_SIZE]; 862 863 nlh = msg_init(buf, TIPC_NL_MON_GET); 864 if (!nlh) { 865 fprintf(stderr, "error, message initialisation failed\n"); 866 return -1; 867 } 868 869 return msg_doit(nlh, link_mon_get_cb, NULL); 870 } 871 872 static int cmd_link_mon_get(struct nlmsghdr *nlh, const struct cmd *cmd, 873 struct cmdl *cmdl, void *data) 874 { 875 const struct cmd cmds[] = { 876 { "threshold", cmd_link_mon_get_prop, NULL}, 877 { NULL } 878 }; 879 880 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 881 } 882 883 static void cmd_link_mon_help(struct cmdl *cmdl) 884 { 885 fprintf(stderr, 886 "Usage: %s montior COMMAND [ARGS] ...\n\n" 887 "COMMANDS\n" 888 " set - Set monitor properties\n" 889 " get - Get monitor properties\n" 890 " list - List all cluster members\n" 891 " summary - Show local node monitor summary\n", 892 cmdl->argv[0]); 893 } 894 895 static int cmd_link_mon(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, 896 void *data) 897 { 898 const struct cmd cmds[] = { 899 { "set", cmd_link_mon_set, cmd_link_mon_set_help }, 900 { "get", cmd_link_mon_get, cmd_link_mon_get_help }, 901 { "list", cmd_link_mon_list, cmd_link_mon_list_help }, 902 { "summary", cmd_link_mon_summary, NULL }, 903 { NULL } 904 }; 905 906 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 907 } 908 909 void cmd_link_help(struct cmdl *cmdl) 910 { 911 fprintf(stderr, 912 "Usage: %s link COMMAND [ARGS] ...\n" 913 "\n" 914 "COMMANDS\n" 915 " list - List links\n" 916 " get - Get various link properties\n" 917 " set - Set various link properties\n" 918 " statistics - Show or reset statistics\n" 919 " monitor - Show or set link supervision\n", 920 cmdl->argv[0]); 921 } 922 923 int cmd_link(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl, 924 void *data) 925 { 926 const struct cmd cmds[] = { 927 { "get", cmd_link_get, cmd_link_get_help }, 928 { "list", cmd_link_list, NULL }, 929 { "set", cmd_link_set, cmd_link_set_help }, 930 { "statistics", cmd_link_stat, cmd_link_stat_help }, 931 { "monitor", cmd_link_mon, cmd_link_mon_help }, 932 { NULL } 933 }; 934 935 return run_cmd(nlh, cmd, cmds, cmdl, NULL); 936 } 937