Home | History | Annotate | Download | only in tipc
      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