2 * link.c TIPC link functionality.
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.
9 * Authors: Richard Alpe <richard.alpe@ericsson.com>
17 #include <linux/tipc_netlink.h>
18 #include <linux/tipc.h>
19 #include <linux/genetlink.h>
20 #include <libmnl/libmnl.h>
26 static int link_list_cb(const struct nlmsghdr
*nlh
, void *data
)
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] = {};
32 mnl_attr_parse(nlh
, sizeof(*genl
), parse_attrs
, info
);
33 if (!info
[TIPC_NLA_LINK
])
36 mnl_attr_parse_nested(info
[TIPC_NLA_LINK
], parse_attrs
, attrs
);
37 if (!attrs
[TIPC_NLA_LINK_NAME
])
40 printf("%s: ", mnl_attr_get_str(attrs
[TIPC_NLA_LINK_NAME
]));
42 if (attrs
[TIPC_NLA_LINK_UP
])
50 static int cmd_link_list(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
51 struct cmdl
*cmdl
, void *data
)
53 char buf
[MNL_SOCKET_BUFFER_SIZE
];
56 fprintf(stderr
, "Usage: %s link list\n", cmdl
->argv
[0]);
60 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_GET
))) {
61 fprintf(stderr
, "error, message initialisation failed\n");
65 return msg_dumpit(nlh
, link_list_cb
, NULL
);
68 static int link_get_cb(const struct nlmsghdr
*nlh
, void *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] = {};
76 mnl_attr_parse(nlh
, sizeof(*genl
), parse_attrs
, info
);
77 if (!info
[TIPC_NLA_LINK
])
80 mnl_attr_parse_nested(info
[TIPC_NLA_LINK
], parse_attrs
, attrs
);
81 if (!attrs
[TIPC_NLA_LINK_PROP
])
84 mnl_attr_parse_nested(attrs
[TIPC_NLA_LINK_PROP
], parse_attrs
, props
);
88 printf("%u\n", mnl_attr_get_u32(props
[*prop
]));
94 static int cmd_link_get_prop(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
95 struct cmdl
*cmdl
, void *data
)
98 char buf
[MNL_SOCKET_BUFFER_SIZE
];
100 struct opt opts
[] = {
101 { "link", OPT_KEYVAL
, NULL
},
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
;
119 if (parse_opts(opts
, cmdl
) < 0)
122 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_GET
))) {
123 fprintf(stderr
, "error, message initialisation failed\n");
127 if (!(opt
= get_opt(opts
, "link"))) {
128 fprintf(stderr
, "error, missing link\n");
131 mnl_attr_put_strz(nlh
, TIPC_NLA_LINK_NAME
, opt
->val
);
133 return msg_doit(nlh
, link_get_cb
, &prop
);
136 static void cmd_link_get_help(struct cmdl
*cmdl
)
138 fprintf(stderr
, "Usage: %s link get PPROPERTY link LINK\n\n"
140 " tolerance - Get link tolerance\n"
141 " priority - Get link priority\n"
142 " window - Get link window\n",
146 static int cmd_link_get(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
147 struct cmdl
*cmdl
, void *data
)
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
},
156 return run_cmd(nlh
, cmd
, cmds
, cmdl
, NULL
);
159 static void cmd_link_stat_reset_help(struct cmdl
*cmdl
)
161 fprintf(stderr
, "Usage: %s link stat reset link LINK\n\n", cmdl
->argv
[0]);
164 static int cmd_link_stat_reset(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
165 struct cmdl
*cmdl
, void *data
)
168 char buf
[MNL_SOCKET_BUFFER_SIZE
];
171 struct opt opts
[] = {
172 { "link", OPT_KEYVAL
, NULL
},
181 if (parse_opts(opts
, cmdl
) != 1) {
186 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_RESET_STATS
))) {
187 fprintf(stderr
, "error, message initialisation failed\n");
191 if (!(opt
= get_opt(opts
, "link"))) {
192 fprintf(stderr
, "error, missing link\n");
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
);
201 return msg_doit(nlh
, NULL
, NULL
);
204 static uint32_t perc(uint32_t count
, uint32_t total
)
206 return (count
* 100 + (total
/ 2)) / total
;
209 static int _show_link_stat(struct nlattr
*attrs
[], struct nlattr
*prop
[],
210 struct nlattr
*stats
[])
214 if (attrs
[TIPC_NLA_LINK_ACTIVE
])
216 else if (attrs
[TIPC_NLA_LINK_UP
])
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
]));
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
]));
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
]));
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
);
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
));
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
]));
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
]));
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
]));
280 static int _show_bc_link_stat(struct nlattr
*prop
[], struct nlattr
*stats
[])
282 printf(" Window:%u packets\n",
283 mnl_attr_get_u32(prop
[TIPC_NLA_PROP_WIN
]));
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
]));
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
]));
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
]));
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
]));
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
]));
317 static int link_stat_show_cb(const struct nlmsghdr
*nlh
, void *data
)
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] = {};
327 mnl_attr_parse(nlh
, sizeof(*genl
), parse_attrs
, info
);
328 if (!info
[TIPC_NLA_LINK
])
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
])
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
);
339 name
= mnl_attr_get_str(attrs
[TIPC_NLA_LINK_NAME
]);
341 /* If a link is passed, skip all but that link */
342 if (link
&& (strcmp(name
, link
) != 0))
345 if (attrs
[TIPC_NLA_LINK_BROADCAST
]) {
346 printf("Link <%s>\n", name
);
347 return _show_bc_link_stat(prop
, stats
);
350 printf("\nLink <%s>\n", name
);
352 return _show_link_stat(attrs
, prop
, stats
);
355 static void cmd_link_stat_show_help(struct cmdl
*cmdl
)
357 fprintf(stderr
, "Usage: %s link stat show [ link LINK ]\n",
361 static int cmd_link_stat_show(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
362 struct cmdl
*cmdl
, void *data
)
365 char buf
[MNL_SOCKET_BUFFER_SIZE
];
367 struct opt opts
[] = {
368 { "link", OPT_KEYVAL
, NULL
},
377 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_GET
))) {
378 fprintf(stderr
, "error, message initialisation failed\n");
382 if (parse_opts(opts
, cmdl
) < 0)
385 if ((opt
= get_opt(opts
, "link")))
388 return msg_dumpit(nlh
, link_stat_show_cb
, link
);
391 static void cmd_link_stat_help(struct cmdl
*cmdl
)
393 fprintf(stderr
, "Usage: %s link stat COMMAND [ARGS]\n\n"
395 " reset - Reset link statistics for link\n"
396 " show - Get link priority\n",
400 static int cmd_link_stat(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
401 struct cmdl
*cmdl
, void *data
)
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
},
409 return run_cmd(nlh
, cmd
, cmds
, cmdl
, NULL
);
412 static void cmd_link_set_help(struct cmdl
*cmdl
)
414 fprintf(stderr
, "Usage: %s link set PPROPERTY link LINK\n\n"
416 " tolerance TOLERANCE - Set link tolerance\n"
417 " priority PRIORITY - Set link priority\n"
418 " window WINDOW - Set link window\n",
422 static int cmd_link_set_prop(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
423 struct cmdl
*cmdl
, void *data
)
427 char buf
[MNL_SOCKET_BUFFER_SIZE
];
428 struct nlattr
*props
;
429 struct nlattr
*attrs
;
431 struct opt opts
[] = {
432 { "link", OPT_KEYVAL
, NULL
},
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
;
450 if (cmdl
->optind
>= cmdl
->argc
) {
451 fprintf(stderr
, "error, missing value\n");
454 val
= atoi(shift_cmdl(cmdl
));
456 if (parse_opts(opts
, cmdl
) < 0)
459 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_SET
))) {
460 fprintf(stderr
, "error, message initialisation failed\n");
463 attrs
= mnl_attr_nest_start(nlh
, TIPC_NLA_LINK
);
465 if (!(opt
= get_opt(opts
, "link"))) {
466 fprintf(stderr
, "error, missing link\n");
469 mnl_attr_put_strz(nlh
, TIPC_NLA_LINK_NAME
, opt
->val
);
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
);
475 mnl_attr_nest_end(nlh
, attrs
);
477 return msg_doit(nlh
, link_get_cb
, &prop
);
482 static int cmd_link_set(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
483 struct cmdl
*cmdl
, void *data
)
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
},
492 return run_cmd(nlh
, cmd
, cmds
, cmdl
, NULL
);
495 void cmd_link_help(struct cmdl
*cmdl
)
498 "Usage: %s link COMMAND [ARGS] ...\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",
508 int cmd_link(struct nlmsghdr
*nlh
, const struct cmd
*cmd
, struct cmdl
*cmdl
,
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
},
519 return run_cmd(nlh
, cmd
, cmds
, cmdl
, NULL
);