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