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