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