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
]));
93 static int cmd_link_get_prop(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
94 struct cmdl
*cmdl
, void *data
)
97 char buf
[MNL_SOCKET_BUFFER_SIZE
];
100 { "link", OPT_KEYVAL
, NULL
},
104 if (strcmp(cmd
->cmd
, "priority") == 0)
105 prop
= TIPC_NLA_PROP_PRIO
;
106 else if ((strcmp(cmd
->cmd
, "tolerance") == 0))
107 prop
= TIPC_NLA_PROP_TOL
;
108 else if ((strcmp(cmd
->cmd
, "window") == 0))
109 prop
= TIPC_NLA_PROP_WIN
;
118 if (parse_opts(opts
, cmdl
) < 0)
121 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_GET
))) {
122 fprintf(stderr
, "error, message initialisation failed\n");
126 if (!(opt
= get_opt(opts
, "link"))) {
127 fprintf(stderr
, "error, missing link\n");
130 mnl_attr_put_strz(nlh
, TIPC_NLA_LINK_NAME
, opt
->val
);
132 return msg_doit(nlh
, link_get_cb
, &prop
);
135 static void cmd_link_get_help(struct cmdl
*cmdl
)
137 fprintf(stderr
, "Usage: %s link get PPROPERTY link LINK\n\n"
139 " tolerance - Get link tolerance\n"
140 " priority - Get link priority\n"
141 " window - Get link window\n",
145 static int cmd_link_get(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
146 struct cmdl
*cmdl
, void *data
)
148 const struct cmd cmds
[] = {
149 { "priority", cmd_link_get_prop
, cmd_link_get_help
},
150 { "tolerance", cmd_link_get_prop
, cmd_link_get_help
},
151 { "window", cmd_link_get_prop
, cmd_link_get_help
},
155 return run_cmd(nlh
, cmd
, cmds
, cmdl
, NULL
);
158 static void cmd_link_stat_reset_help(struct cmdl
*cmdl
)
160 fprintf(stderr
, "Usage: %s link stat reset link LINK\n\n", cmdl
->argv
[0]);
163 static int cmd_link_stat_reset(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
164 struct cmdl
*cmdl
, void *data
)
167 char buf
[MNL_SOCKET_BUFFER_SIZE
];
170 struct opt opts
[] = {
171 { "link", OPT_KEYVAL
, NULL
},
180 if (parse_opts(opts
, cmdl
) != 1) {
185 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_RESET_STATS
))) {
186 fprintf(stderr
, "error, message initialisation failed\n");
190 if (!(opt
= get_opt(opts
, "link"))) {
191 fprintf(stderr
, "error, missing link\n");
196 nest
= mnl_attr_nest_start(nlh
, TIPC_NLA_LINK
);
197 mnl_attr_put_strz(nlh
, TIPC_NLA_LINK_NAME
, link
);
198 mnl_attr_nest_end(nlh
, nest
);
200 return msg_doit(nlh
, NULL
, NULL
);
203 static uint32_t perc(uint32_t count
, uint32_t total
)
205 return (count
* 100 + (total
/ 2)) / total
;
208 static int _show_link_stat(struct nlattr
*attrs
[], struct nlattr
*prop
[],
209 struct nlattr
*stats
[])
213 if (attrs
[TIPC_NLA_LINK_ACTIVE
])
215 else if (attrs
[TIPC_NLA_LINK_UP
])
220 printf(" MTU:%u Priority:%u Tolerance:%u ms Window:%u packets\n",
221 mnl_attr_get_u32(attrs
[TIPC_NLA_LINK_MTU
]),
222 mnl_attr_get_u32(prop
[TIPC_NLA_PROP_PRIO
]),
223 mnl_attr_get_u32(prop
[TIPC_NLA_PROP_TOL
]),
224 mnl_attr_get_u32(prop
[TIPC_NLA_PROP_WIN
]));
226 printf(" RX packets:%u fragments:%u/%u bundles:%u/%u\n",
227 mnl_attr_get_u32(attrs
[TIPC_NLA_LINK_RX
]) -
228 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_INFO
]),
229 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_FRAGMENTS
]),
230 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_FRAGMENTED
]),
231 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_BUNDLES
]),
232 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_BUNDLED
]));
234 printf(" TX packets:%u fragments:%u/%u bundles:%u/%u\n",
235 mnl_attr_get_u32(attrs
[TIPC_NLA_LINK_TX
]) -
236 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_INFO
]),
237 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_FRAGMENTS
]),
238 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_FRAGMENTED
]),
239 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_BUNDLES
]),
240 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_BUNDLED
]));
242 proft
= mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_PROF_TOT
]);
243 printf(" TX profile sample:%u packets average:%u octets\n",
244 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_CNT
]),
245 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_TOT
]) / proft
);
247 printf(" 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
248 "-16384:%u%% -32768:%u%% -66000:%u%%\n",
249 perc(mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P0
]), proft
),
250 perc(mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P1
]), proft
),
251 perc(mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P2
]), proft
),
252 perc(mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P3
]), proft
),
253 perc(mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P4
]), proft
),
254 perc(mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P5
]), proft
),
255 perc(mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MSG_LEN_P6
]), proft
));
257 printf(" RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
258 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_STATES
]),
259 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_PROBES
]),
260 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_NACKS
]),
261 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_DEFERRED
]),
262 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_DUPLICATES
]));
264 printf(" TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
265 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_STATES
]),
266 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_PROBES
]),
267 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_NACKS
]),
268 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_ACKS
]),
269 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RETRANSMITTED
]));
271 printf(" Congestion link:%u Send queue max:%u avg:%u\n",
272 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_LINK_CONGS
]),
273 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MAX_QUEUE
]),
274 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_AVG_QUEUE
]));
279 static int _show_bc_link_stat(struct nlattr
*prop
[], struct nlattr
*stats
[])
281 printf(" Window:%u packets\n",
282 mnl_attr_get_u32(prop
[TIPC_NLA_PROP_WIN
]));
284 printf(" RX packets:%u fragments:%u/%u bundles:%u/%u\n",
285 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_INFO
]),
286 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_FRAGMENTS
]),
287 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_FRAGMENTED
]),
288 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_BUNDLES
]),
289 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_BUNDLED
]));
291 printf(" TX packets:%u fragments:%u/%u bundles:%u/%u\n",
292 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_INFO
]),
293 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_FRAGMENTS
]),
294 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_FRAGMENTED
]),
295 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_BUNDLES
]),
296 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_BUNDLED
]));
298 printf(" RX naks:%u defs:%u dups:%u\n",
299 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_NACKS
]),
300 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RX_DEFERRED
]),
301 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_DUPLICATES
]));
303 printf(" TX naks:%u acks:%u dups:%u\n",
304 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_NACKS
]),
305 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_TX_ACKS
]),
306 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_RETRANSMITTED
]));
308 printf(" Congestion link:%u Send queue max:%u avg:%u\n",
309 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_LINK_CONGS
]),
310 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_MAX_QUEUE
]),
311 mnl_attr_get_u32(stats
[TIPC_NLA_STATS_AVG_QUEUE
]));
316 static int link_stat_show_cb(const struct nlmsghdr
*nlh
, void *data
)
319 const char *link
= data
;
320 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
321 struct nlattr
*info
[TIPC_NLA_MAX
+ 1] = {};
322 struct nlattr
*attrs
[TIPC_NLA_LINK_MAX
+ 1] = {};
323 struct nlattr
*prop
[TIPC_NLA_PROP_MAX
+ 1] = {};
324 struct nlattr
*stats
[TIPC_NLA_STATS_MAX
+ 1] = {};
326 mnl_attr_parse(nlh
, sizeof(*genl
), parse_attrs
, info
);
327 if (!info
[TIPC_NLA_LINK
])
330 mnl_attr_parse_nested(info
[TIPC_NLA_LINK
], parse_attrs
, attrs
);
331 if (!attrs
[TIPC_NLA_LINK_NAME
] || !attrs
[TIPC_NLA_LINK_PROP
] ||
332 !attrs
[TIPC_NLA_LINK_STATS
])
335 mnl_attr_parse_nested(attrs
[TIPC_NLA_LINK_PROP
], parse_attrs
, prop
);
336 mnl_attr_parse_nested(attrs
[TIPC_NLA_LINK_STATS
], parse_attrs
, stats
);
338 name
= mnl_attr_get_str(attrs
[TIPC_NLA_LINK_NAME
]);
340 /* If a link is passed, skip all but that link */
341 if (link
&& (strcmp(name
, link
) != 0))
344 if (attrs
[TIPC_NLA_LINK_BROADCAST
]) {
345 printf("Link <%s>\n", name
);
346 return _show_bc_link_stat(prop
, stats
);
349 printf("\nLink <%s>\n", name
);
351 return _show_link_stat(attrs
, prop
, stats
);
354 static void cmd_link_stat_show_help(struct cmdl
*cmdl
)
356 fprintf(stderr
, "Usage: %s link stat show [ link LINK ]\n",
360 static int cmd_link_stat_show(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
361 struct cmdl
*cmdl
, void *data
)
364 char buf
[MNL_SOCKET_BUFFER_SIZE
];
366 struct opt opts
[] = {
367 { "link", OPT_KEYVAL
, NULL
},
376 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_GET
))) {
377 fprintf(stderr
, "error, message initialisation failed\n");
381 if (parse_opts(opts
, cmdl
) < 0)
384 if ((opt
= get_opt(opts
, "link")))
387 return msg_dumpit(nlh
, link_stat_show_cb
, link
);
390 static void cmd_link_stat_help(struct cmdl
*cmdl
)
392 fprintf(stderr
, "Usage: %s link stat COMMAND [ARGS]\n\n"
394 " reset - Reset link statistics for link\n"
395 " show - Get link priority\n",
399 static int cmd_link_stat(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
400 struct cmdl
*cmdl
, void *data
)
402 const struct cmd cmds
[] = {
403 { "reset", cmd_link_stat_reset
, cmd_link_stat_reset_help
},
404 { "show", cmd_link_stat_show
, cmd_link_stat_show_help
},
408 return run_cmd(nlh
, cmd
, cmds
, cmdl
, NULL
);
411 static void cmd_link_set_help(struct cmdl
*cmdl
)
413 fprintf(stderr
, "Usage: %s link set PPROPERTY link LINK\n\n"
415 " tolerance TOLERANCE - Set link tolerance\n"
416 " priority PRIORITY - Set link priority\n"
417 " window WINDOW - Set link window\n",
421 static int cmd_link_set_prop(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
422 struct cmdl
*cmdl
, void *data
)
426 char buf
[MNL_SOCKET_BUFFER_SIZE
];
427 struct nlattr
*props
;
428 struct nlattr
*attrs
;
430 struct opt opts
[] = {
431 { "link", OPT_KEYVAL
, NULL
},
435 if (strcmp(cmd
->cmd
, "priority") == 0)
436 prop
= TIPC_NLA_PROP_PRIO
;
437 else if ((strcmp(cmd
->cmd
, "tolerance") == 0))
438 prop
= TIPC_NLA_PROP_TOL
;
439 else if ((strcmp(cmd
->cmd
, "window") == 0))
440 prop
= TIPC_NLA_PROP_WIN
;
449 if (cmdl
->optind
>= cmdl
->argc
) {
450 fprintf(stderr
, "error, missing value\n");
453 val
= atoi(shift_cmdl(cmdl
));
455 if (parse_opts(opts
, cmdl
) < 0)
458 if (!(nlh
= msg_init(buf
, TIPC_NL_LINK_SET
))) {
459 fprintf(stderr
, "error, message initialisation failed\n");
462 attrs
= mnl_attr_nest_start(nlh
, TIPC_NLA_LINK
);
464 if (!(opt
= get_opt(opts
, "link"))) {
465 fprintf(stderr
, "error, missing link\n");
468 mnl_attr_put_strz(nlh
, TIPC_NLA_LINK_NAME
, opt
->val
);
470 props
= mnl_attr_nest_start(nlh
, TIPC_NLA_LINK_PROP
);
471 mnl_attr_put_u32(nlh
, prop
, val
);
472 mnl_attr_nest_end(nlh
, props
);
474 mnl_attr_nest_end(nlh
, attrs
);
476 return msg_doit(nlh
, link_get_cb
, &prop
);
479 static int cmd_link_set(struct nlmsghdr
*nlh
, const struct cmd
*cmd
,
480 struct cmdl
*cmdl
, void *data
)
482 const struct cmd cmds
[] = {
483 { "priority", cmd_link_set_prop
, cmd_link_set_help
},
484 { "tolerance", cmd_link_set_prop
, cmd_link_set_help
},
485 { "window", cmd_link_set_prop
, cmd_link_set_help
},
489 return run_cmd(nlh
, cmd
, cmds
, cmdl
, NULL
);
492 void cmd_link_help(struct cmdl
*cmdl
)
495 "Usage: %s link COMMAND [ARGS] ...\n"
498 " list - List links\n"
499 " get - Get various link properties\n"
500 " set - Set various link properties\n"
501 " statistics - Show or reset statistics\n",
505 int cmd_link(struct nlmsghdr
*nlh
, const struct cmd
*cmd
, struct cmdl
*cmdl
,
508 const struct cmd cmds
[] = {
509 { "get", cmd_link_get
, cmd_link_get_help
},
510 { "list", cmd_link_list
, NULL
},
511 { "set", cmd_link_set
, cmd_link_set_help
},
512 { "statistics", cmd_link_stat
, cmd_link_stat_help
},
516 return run_cmd(nlh
, cmd
, cmds
, cmdl
, NULL
);