aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRichard Alpe <richard.alpe@ericsson.com>2015-02-09 03:50:06 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-09 16:20:47 -0500
commitf2b3b2d4ccbf9666f5f42a21347cd1aaa532b2fa (patch)
tree36a8eea16c58cd54f91ced3862da77803b223dcf /net
parent9ab154658a7ff2c5076607e02f18581c6859fc2a (diff)
tipc: convert legacy nl link stat to nl compat
Add functionality for safely appending string data to a TLV without keeping write count in the caller. Convert TIPC_CMD_SHOW_LINK_STATS to compat dumpit. Signed-off-by: Richard Alpe <richard.alpe@ericsson.com> Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-by: Ying Xue <ying.xue@windriver.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/tipc/bcast.c43
-rw-r--r--net/tipc/bcast.h1
-rw-r--r--net/tipc/config.c4
-rw-r--r--net/tipc/link.c141
-rw-r--r--net/tipc/link.h3
-rw-r--r--net/tipc/netlink_compat.c205
6 files changed, 205 insertions, 192 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index e96fd6a6d5c2..3e41704832de 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -860,49 +860,6 @@ msg_full:
860 return -EMSGSIZE; 860 return -EMSGSIZE;
861} 861}
862 862
863int tipc_bclink_stats(struct net *net, char *buf, const u32 buf_size)
864{
865 int ret;
866 struct tipc_stats *s;
867 struct tipc_net *tn = net_generic(net, tipc_net_id);
868 struct tipc_link *bcl = tn->bcl;
869
870 if (!bcl)
871 return 0;
872
873 tipc_bclink_lock(net);
874
875 s = &bcl->stats;
876
877 ret = tipc_snprintf(buf, buf_size, "Link <%s>\n"
878 " Window:%u packets\n",
879 bcl->name, bcl->queue_limit[0]);
880 ret += tipc_snprintf(buf + ret, buf_size - ret,
881 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
882 s->recv_info, s->recv_fragments,
883 s->recv_fragmented, s->recv_bundles,
884 s->recv_bundled);
885 ret += tipc_snprintf(buf + ret, buf_size - ret,
886 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
887 s->sent_info, s->sent_fragments,
888 s->sent_fragmented, s->sent_bundles,
889 s->sent_bundled);
890 ret += tipc_snprintf(buf + ret, buf_size - ret,
891 " RX naks:%u defs:%u dups:%u\n",
892 s->recv_nacks, s->deferred_recv, s->duplicates);
893 ret += tipc_snprintf(buf + ret, buf_size - ret,
894 " TX naks:%u acks:%u dups:%u\n",
895 s->sent_nacks, s->sent_acks, s->retransmitted);
896 ret += tipc_snprintf(buf + ret, buf_size - ret,
897 " Congestion link:%u Send queue max:%u avg:%u\n",
898 s->link_congs, s->max_queue_sz,
899 s->queue_sz_counts ?
900 (s->accu_queue_sz / s->queue_sz_counts) : 0);
901
902 tipc_bclink_unlock(net);
903 return ret;
904}
905
906int tipc_bclink_reset_stats(struct net *net) 863int tipc_bclink_reset_stats(struct net *net)
907{ 864{
908 struct tipc_net *tn = net_generic(net, tipc_net_id); 865 struct tipc_net *tn = net_generic(net, tipc_net_id);
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h
index a910c0b9f249..43f397fbac55 100644
--- a/net/tipc/bcast.h
+++ b/net/tipc/bcast.h
@@ -127,7 +127,6 @@ u32 tipc_bclink_get_last_sent(struct net *net);
127u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); 127u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr);
128void tipc_bclink_update_link_state(struct tipc_node *node, 128void tipc_bclink_update_link_state(struct tipc_node *node,
129 u32 last_sent); 129 u32 last_sent);
130int tipc_bclink_stats(struct net *net, char *stats_buf, const u32 buf_size);
131int tipc_bclink_reset_stats(struct net *net); 130int tipc_bclink_reset_stats(struct net *net);
132int tipc_bclink_set_queue_limits(struct net *net, u32 limit); 131int tipc_bclink_set_queue_limits(struct net *net, u32 limit);
133void tipc_bcbearer_sort(struct net *net, struct tipc_node_map *nm_ptr, 132void tipc_bcbearer_sort(struct net *net, struct tipc_node_map *nm_ptr,
diff --git a/net/tipc/config.c b/net/tipc/config.c
index f8cd5e1b545f..67b76ee847f3 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -213,10 +213,6 @@ struct sk_buff *tipc_cfg_do_cmd(struct net *net, u32 orig_node, u16 cmd,
213 rep_tlv_buf = tipc_node_get_links(net, req_tlv_area, 213 rep_tlv_buf = tipc_node_get_links(net, req_tlv_area,
214 req_tlv_space); 214 req_tlv_space);
215 break; 215 break;
216 case TIPC_CMD_SHOW_LINK_STATS:
217 rep_tlv_buf = tipc_link_cmd_show_stats(net, req_tlv_area,
218 req_tlv_space);
219 break;
220 case TIPC_CMD_RESET_LINK_STATS: 216 case TIPC_CMD_RESET_LINK_STATS:
221 rep_tlv_buf = tipc_link_cmd_reset_stats(net, req_tlv_area, 217 rep_tlv_buf = tipc_link_cmd_reset_stats(net, req_tlv_area,
222 req_tlv_space); 218 req_tlv_space);
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 466f28fcf215..2622fb99344a 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2146,147 +2146,6 @@ struct sk_buff *tipc_link_cmd_reset_stats(struct net *net,
2146 return tipc_cfg_reply_none(); 2146 return tipc_cfg_reply_none();
2147} 2147}
2148 2148
2149/**
2150 * percent - convert count to a percentage of total (rounding up or down)
2151 */
2152static u32 percent(u32 count, u32 total)
2153{
2154 return (count * 100 + (total / 2)) / total;
2155}
2156
2157/**
2158 * tipc_link_stats - print link statistics
2159 * @net: the applicable net namespace
2160 * @name: link name
2161 * @buf: print buffer area
2162 * @buf_size: size of print buffer area
2163 *
2164 * Returns length of print buffer data string (or 0 if error)
2165 */
2166static int tipc_link_stats(struct net *net, const char *name, char *buf,
2167 const u32 buf_size)
2168{
2169 struct tipc_link *l;
2170 struct tipc_stats *s;
2171 struct tipc_node *node;
2172 char *status;
2173 u32 profile_total = 0;
2174 unsigned int bearer_id;
2175 int ret;
2176
2177 if (!strcmp(name, tipc_bclink_name))
2178 return tipc_bclink_stats(net, buf, buf_size);
2179
2180 node = tipc_link_find_owner(net, name, &bearer_id);
2181 if (!node)
2182 return 0;
2183
2184 tipc_node_lock(node);
2185
2186 l = node->links[bearer_id];
2187 if (!l) {
2188 tipc_node_unlock(node);
2189 return 0;
2190 }
2191
2192 s = &l->stats;
2193
2194 if (tipc_link_is_active(l))
2195 status = "ACTIVE";
2196 else if (tipc_link_is_up(l))
2197 status = "STANDBY";
2198 else
2199 status = "DEFUNCT";
2200
2201 ret = tipc_snprintf(buf, buf_size, "Link <%s>\n"
2202 " %s MTU:%u Priority:%u Tolerance:%u ms"
2203 " Window:%u packets\n",
2204 l->name, status, l->max_pkt, l->priority,
2205 l->tolerance, l->queue_limit[0]);
2206
2207 ret += tipc_snprintf(buf + ret, buf_size - ret,
2208 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
2209 l->next_in_no - s->recv_info, s->recv_fragments,
2210 s->recv_fragmented, s->recv_bundles,
2211 s->recv_bundled);
2212
2213 ret += tipc_snprintf(buf + ret, buf_size - ret,
2214 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
2215 l->next_out_no - s->sent_info, s->sent_fragments,
2216 s->sent_fragmented, s->sent_bundles,
2217 s->sent_bundled);
2218
2219 profile_total = s->msg_length_counts;
2220 if (!profile_total)
2221 profile_total = 1;
2222
2223 ret += tipc_snprintf(buf + ret, buf_size - ret,
2224 " TX profile sample:%u packets average:%u octets\n"
2225 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% "
2226 "-16384:%u%% -32768:%u%% -66000:%u%%\n",
2227 s->msg_length_counts,
2228 s->msg_lengths_total / profile_total,
2229 percent(s->msg_length_profile[0], profile_total),
2230 percent(s->msg_length_profile[1], profile_total),
2231 percent(s->msg_length_profile[2], profile_total),
2232 percent(s->msg_length_profile[3], profile_total),
2233 percent(s->msg_length_profile[4], profile_total),
2234 percent(s->msg_length_profile[5], profile_total),
2235 percent(s->msg_length_profile[6], profile_total));
2236
2237 ret += tipc_snprintf(buf + ret, buf_size - ret,
2238 " RX states:%u probes:%u naks:%u defs:%u"
2239 " dups:%u\n", s->recv_states, s->recv_probes,
2240 s->recv_nacks, s->deferred_recv, s->duplicates);
2241
2242 ret += tipc_snprintf(buf + ret, buf_size - ret,
2243 " TX states:%u probes:%u naks:%u acks:%u"
2244 " dups:%u\n", s->sent_states, s->sent_probes,
2245 s->sent_nacks, s->sent_acks, s->retransmitted);
2246
2247 ret += tipc_snprintf(buf + ret, buf_size - ret,
2248 " Congestion link:%u Send queue"
2249 " max:%u avg:%u\n", s->link_congs,
2250 s->max_queue_sz, s->queue_sz_counts ?
2251 (s->accu_queue_sz / s->queue_sz_counts) : 0);
2252
2253 tipc_node_unlock(node);
2254 return ret;
2255}
2256
2257struct sk_buff *tipc_link_cmd_show_stats(struct net *net,
2258 const void *req_tlv_area,
2259 int req_tlv_space)
2260{
2261 struct sk_buff *buf;
2262 struct tlv_desc *rep_tlv;
2263 int str_len;
2264 int pb_len;
2265 char *pb;
2266
2267 if (!TLV_CHECK(req_tlv_area, req_tlv_space, TIPC_TLV_LINK_NAME))
2268 return tipc_cfg_reply_error_string(TIPC_CFG_TLV_ERROR);
2269
2270 buf = tipc_cfg_reply_alloc(TLV_SPACE(ULTRA_STRING_MAX_LEN));
2271 if (!buf)
2272 return NULL;
2273
2274 rep_tlv = (struct tlv_desc *)buf->data;
2275 pb = TLV_DATA(rep_tlv);
2276 pb_len = ULTRA_STRING_MAX_LEN;
2277 str_len = tipc_link_stats(net, (char *)TLV_DATA(req_tlv_area),
2278 pb, pb_len);
2279 if (!str_len) {
2280 kfree_skb(buf);
2281 return tipc_cfg_reply_error_string("link not found");
2282 }
2283 str_len += 1; /* for "\0" */
2284 skb_put(buf, TLV_SPACE(str_len));
2285 TLV_SET(rep_tlv, TIPC_TLV_ULTRA_STRING, NULL, str_len);
2286
2287 return buf;
2288}
2289
2290static void link_print(struct tipc_link *l_ptr, const char *str) 2149static void link_print(struct tipc_link *l_ptr, const char *str)
2291{ 2150{
2292 struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id); 2151 struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id);
diff --git a/net/tipc/link.h b/net/tipc/link.h
index 34d3f55c4cea..8c8340cf991f 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -217,9 +217,6 @@ int tipc_link_is_active(struct tipc_link *l_ptr);
217void tipc_link_purge_queues(struct tipc_link *l_ptr); 217void tipc_link_purge_queues(struct tipc_link *l_ptr);
218struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area, 218struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area,
219 int req_tlv_space, u16 cmd); 219 int req_tlv_space, u16 cmd);
220struct sk_buff *tipc_link_cmd_show_stats(struct net *net,
221 const void *req_tlv_area,
222 int req_tlv_space);
223struct sk_buff *tipc_link_cmd_reset_stats(struct net *net, 220struct sk_buff *tipc_link_cmd_reset_stats(struct net *net,
224 const void *req_tlv_area, 221 const void *req_tlv_area,
225 int req_tlv_space); 222 int req_tlv_space);
diff --git a/net/tipc/netlink_compat.c b/net/tipc/netlink_compat.c
index 12b0f4424797..899bd94da467 100644
--- a/net/tipc/netlink_compat.c
+++ b/net/tipc/netlink_compat.c
@@ -34,6 +34,7 @@
34#include "core.h" 34#include "core.h"
35#include "config.h" 35#include "config.h"
36#include "bearer.h" 36#include "bearer.h"
37#include "link.h"
37#include <net/genetlink.h> 38#include <net/genetlink.h>
38#include <linux/tipc_config.h> 39#include <linux/tipc_config.h>
39 40
@@ -48,6 +49,7 @@
48 49
49struct tipc_nl_compat_msg { 50struct tipc_nl_compat_msg {
50 u16 cmd; 51 u16 cmd;
52 int rep_type;
51 int rep_size; 53 int rep_size;
52 int req_type; 54 int req_type;
53 struct sk_buff *rep; 55 struct sk_buff *rep;
@@ -95,6 +97,40 @@ static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len)
95 return 0; 97 return 0;
96} 98}
97 99
100static void tipc_tlv_init(struct sk_buff *skb, u16 type)
101{
102 struct tlv_desc *tlv = (struct tlv_desc *)skb->data;
103
104 TLV_SET_LEN(tlv, 0);
105 TLV_SET_TYPE(tlv, type);
106 skb_put(skb, sizeof(struct tlv_desc));
107}
108
109static int tipc_tlv_sprintf(struct sk_buff *skb, const char *fmt, ...)
110{
111 int n;
112 u16 len;
113 u32 rem;
114 char *buf;
115 struct tlv_desc *tlv;
116 va_list args;
117
118 rem = tipc_skb_tailroom(skb);
119
120 tlv = (struct tlv_desc *)skb->data;
121 len = TLV_GET_LEN(tlv);
122 buf = TLV_DATA(tlv) + len;
123
124 va_start(args, fmt);
125 n = vscnprintf(buf, rem, fmt, args);
126 va_end(args);
127
128 TLV_SET_LEN(tlv, n + len);
129 skb_put(skb, n);
130
131 return n;
132}
133
98static struct sk_buff *tipc_tlv_alloc(int size) 134static struct sk_buff *tipc_tlv_alloc(int size)
99{ 135{
100 int hdr_len; 136 int hdr_len;
@@ -200,10 +236,16 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd,
200 int err; 236 int err;
201 struct sk_buff *arg; 237 struct sk_buff *arg;
202 238
239 if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
240 return -EINVAL;
241
203 msg->rep = tipc_tlv_alloc(msg->rep_size); 242 msg->rep = tipc_tlv_alloc(msg->rep_size);
204 if (!msg->rep) 243 if (!msg->rep)
205 return -ENOMEM; 244 return -ENOMEM;
206 245
246 if (msg->rep_type)
247 tipc_tlv_init(msg->rep, msg->rep_type);
248
207 arg = nlmsg_new(0, GFP_KERNEL); 249 arg = nlmsg_new(0, GFP_KERNEL);
208 if (!arg) { 250 if (!arg) {
209 kfree_skb(msg->rep); 251 kfree_skb(msg->rep);
@@ -356,6 +398,161 @@ static int tipc_nl_compat_bearer_disable(struct sk_buff *skb,
356 return 0; 398 return 0;
357} 399}
358 400
401static inline u32 perc(u32 count, u32 total)
402{
403 return (count * 100 + (total / 2)) / total;
404}
405
406static void __fill_bc_link_stat(struct tipc_nl_compat_msg *msg,
407 struct nlattr *prop[], struct nlattr *stats[])
408{
409 tipc_tlv_sprintf(msg->rep, " Window:%u packets\n",
410 nla_get_u32(prop[TIPC_NLA_PROP_WIN]));
411
412 tipc_tlv_sprintf(msg->rep,
413 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
414 nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
415 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
416 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
417 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
418 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
419
420 tipc_tlv_sprintf(msg->rep,
421 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
422 nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
423 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
424 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
425 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
426 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
427
428 tipc_tlv_sprintf(msg->rep, " RX naks:%u defs:%u dups:%u\n",
429 nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
430 nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
431 nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
432
433 tipc_tlv_sprintf(msg->rep, " TX naks:%u acks:%u dups:%u\n",
434 nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
435 nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
436 nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
437
438 tipc_tlv_sprintf(msg->rep,
439 " Congestion link:%u Send queue max:%u avg:%u",
440 nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
441 nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
442 nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
443}
444
445static int tipc_nl_compat_link_stat_dump(struct tipc_nl_compat_msg *msg,
446 struct nlattr **attrs)
447{
448 char *name;
449 struct nlattr *link[TIPC_NLA_LINK_MAX + 1];
450 struct nlattr *prop[TIPC_NLA_PROP_MAX + 1];
451 struct nlattr *stats[TIPC_NLA_STATS_MAX + 1];
452
453 nla_parse_nested(link, TIPC_NLA_LINK_MAX, attrs[TIPC_NLA_LINK], NULL);
454
455 nla_parse_nested(prop, TIPC_NLA_PROP_MAX, link[TIPC_NLA_LINK_PROP],
456 NULL);
457
458 nla_parse_nested(stats, TIPC_NLA_STATS_MAX, link[TIPC_NLA_LINK_STATS],
459 NULL);
460
461 name = (char *)TLV_DATA(msg->req);
462 if (strcmp(name, nla_data(link[TIPC_NLA_LINK_NAME])) != 0)
463 return 0;
464
465 tipc_tlv_sprintf(msg->rep, "\nLink <%s>\n",
466 nla_data(link[TIPC_NLA_LINK_NAME]));
467
468 if (link[TIPC_NLA_LINK_BROADCAST]) {
469 __fill_bc_link_stat(msg, prop, stats);
470 return 0;
471 }
472
473 if (link[TIPC_NLA_LINK_ACTIVE])
474 tipc_tlv_sprintf(msg->rep, " ACTIVE");
475 else if (link[TIPC_NLA_LINK_UP])
476 tipc_tlv_sprintf(msg->rep, " STANDBY");
477 else
478 tipc_tlv_sprintf(msg->rep, " DEFUNCT");
479
480 tipc_tlv_sprintf(msg->rep, " MTU:%u Priority:%u",
481 nla_get_u32(link[TIPC_NLA_LINK_MTU]),
482 nla_get_u32(prop[TIPC_NLA_PROP_PRIO]));
483
484 tipc_tlv_sprintf(msg->rep, " Tolerance:%u ms Window:%u packets\n",
485 nla_get_u32(prop[TIPC_NLA_PROP_TOL]),
486 nla_get_u32(prop[TIPC_NLA_PROP_WIN]));
487
488 tipc_tlv_sprintf(msg->rep,
489 " RX packets:%u fragments:%u/%u bundles:%u/%u\n",
490 nla_get_u32(link[TIPC_NLA_LINK_RX]) -
491 nla_get_u32(stats[TIPC_NLA_STATS_RX_INFO]),
492 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTS]),
493 nla_get_u32(stats[TIPC_NLA_STATS_RX_FRAGMENTED]),
494 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLES]),
495 nla_get_u32(stats[TIPC_NLA_STATS_RX_BUNDLED]));
496
497 tipc_tlv_sprintf(msg->rep,
498 " TX packets:%u fragments:%u/%u bundles:%u/%u\n",
499 nla_get_u32(link[TIPC_NLA_LINK_TX]) -
500 nla_get_u32(stats[TIPC_NLA_STATS_TX_INFO]),
501 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTS]),
502 nla_get_u32(stats[TIPC_NLA_STATS_TX_FRAGMENTED]),
503 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLES]),
504 nla_get_u32(stats[TIPC_NLA_STATS_TX_BUNDLED]));
505
506 tipc_tlv_sprintf(msg->rep,
507 " TX profile sample:%u packets average:%u octets\n",
508 nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_CNT]),
509 nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_TOT]) /
510 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT]));
511
512 tipc_tlv_sprintf(msg->rep,
513 " 0-64:%u%% -256:%u%% -1024:%u%% -4096:%u%% ",
514 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P0]),
515 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
516 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P1]),
517 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
518 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P2]),
519 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
520 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P3]),
521 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])));
522
523 tipc_tlv_sprintf(msg->rep, "-16384:%u%% -32768:%u%% -66000:%u%%\n",
524 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P4]),
525 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
526 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P5]),
527 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])),
528 perc(nla_get_u32(stats[TIPC_NLA_STATS_MSG_LEN_P6]),
529 nla_get_u32(stats[TIPC_NLA_STATS_MSG_PROF_TOT])));
530
531 tipc_tlv_sprintf(msg->rep,
532 " RX states:%u probes:%u naks:%u defs:%u dups:%u\n",
533 nla_get_u32(stats[TIPC_NLA_STATS_RX_STATES]),
534 nla_get_u32(stats[TIPC_NLA_STATS_RX_PROBES]),
535 nla_get_u32(stats[TIPC_NLA_STATS_RX_NACKS]),
536 nla_get_u32(stats[TIPC_NLA_STATS_RX_DEFERRED]),
537 nla_get_u32(stats[TIPC_NLA_STATS_DUPLICATES]));
538
539 tipc_tlv_sprintf(msg->rep,
540 " TX states:%u probes:%u naks:%u acks:%u dups:%u\n",
541 nla_get_u32(stats[TIPC_NLA_STATS_TX_STATES]),
542 nla_get_u32(stats[TIPC_NLA_STATS_TX_PROBES]),
543 nla_get_u32(stats[TIPC_NLA_STATS_TX_NACKS]),
544 nla_get_u32(stats[TIPC_NLA_STATS_TX_ACKS]),
545 nla_get_u32(stats[TIPC_NLA_STATS_RETRANSMITTED]));
546
547 tipc_tlv_sprintf(msg->rep,
548 " Congestion link:%u Send queue max:%u avg:%u",
549 nla_get_u32(stats[TIPC_NLA_STATS_LINK_CONGS]),
550 nla_get_u32(stats[TIPC_NLA_STATS_MAX_QUEUE]),
551 nla_get_u32(stats[TIPC_NLA_STATS_AVG_QUEUE]));
552
553 return 0;
554}
555
359static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) 556static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
360{ 557{
361 struct tipc_nl_compat_cmd_dump dump; 558 struct tipc_nl_compat_cmd_dump dump;
@@ -380,6 +577,13 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
380 doit.doit = tipc_nl_bearer_disable; 577 doit.doit = tipc_nl_bearer_disable;
381 doit.transcode = tipc_nl_compat_bearer_disable; 578 doit.transcode = tipc_nl_compat_bearer_disable;
382 return tipc_nl_compat_doit(&doit, msg); 579 return tipc_nl_compat_doit(&doit, msg);
580 case TIPC_CMD_SHOW_LINK_STATS:
581 msg->req_type = TIPC_TLV_LINK_NAME;
582 msg->rep_size = ULTRA_STRING_MAX_LEN;
583 msg->rep_type = TIPC_TLV_ULTRA_STRING;
584 dump.dumpit = tipc_nl_link_dump;
585 dump.format = tipc_nl_compat_link_stat_dump;
586 return tipc_nl_compat_dumpit(&dump, msg);
383 } 587 }
384 588
385 return -EOPNOTSUPP; 589 return -EOPNOTSUPP;
@@ -479,6 +683,7 @@ static int tipc_nl_compat_tmp_wrap(struct sk_buff *skb, struct genl_info *info)
479 case TIPC_CMD_GET_BEARER_NAMES: 683 case TIPC_CMD_GET_BEARER_NAMES:
480 case TIPC_CMD_ENABLE_BEARER: 684 case TIPC_CMD_ENABLE_BEARER:
481 case TIPC_CMD_DISABLE_BEARER: 685 case TIPC_CMD_DISABLE_BEARER:
686 case TIPC_CMD_SHOW_LINK_STATS:
482 return tipc_nl_compat_recv(skb, info); 687 return tipc_nl_compat_recv(skb, info);
483 } 688 }
484 689