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