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