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