History

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.

Richard Alpe committed 11 years ago

Commit f2b3b2d1 parent 9ab15467 files · +215 −192Browse files

Unified · Split

7 files
  1. include/uapi/linux/tipc_config.h +10 −0
  2. net/tipc/bcast.c +0 −43
  3. net/tipc/bcast.h +0 −1
  4. net/tipc/config.c +0 −4
  5. net/tipc/link.c +0 −141
  6. net/tipc/link.h +0 −3
  7. net/tipc/netlink_compat.c +205 −0
include/uapi/linux/tipc_config.h+10−0
@@ -277,11 +277,21 @@ static inline int TLV_GET_LEN(struct tlv_desc *tlv) · 276 unmodified lines
277277 return ntohs(tlv->tlv_len);
278278 }
279279
280+static inline void TLV_SET_LEN(struct tlv_desc *tlv, __u16 len)
281+{
282+ tlv->tlv_len = htons(len);
283+}
284+
280285 static inline int TLV_CHECK_TYPE(struct tlv_desc *tlv, __u16 type)
281286 {
282287 return (ntohs(tlv->tlv_type) == type);
283288 }
284289
290+static inline void TLV_SET_TYPE(struct tlv_desc *tlv, __u16 type)
291+{
292+ tlv->tlv_type = htons(type);
293+}
294+
285295 static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len)
286296 {
287297 struct tlv_desc *tlv_ptr;
net/tipc/bcast.c+0−43
@@ -860,49 +860,6 @@ msg_full: · 859 unmodified lines
860860 return -EMSGSIZE;
861861 }
862862
863−int 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−
906863 int tipc_bclink_reset_stats(struct net *net)
907864 {
908865 struct tipc_net *tn = net_generic(net, tipc_net_id);
net/tipc/bcast.h+0−1
@@ -127,7 +127,6 @@ u32 tipc_bclink_get_last_sent(struct net *net); · 126 unmodified lines
127127 u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr);
128128 void tipc_bclink_update_link_state(struct tipc_node *node,
129129 u32 last_sent);
130−int tipc_bclink_stats(struct net *net, char *stats_buf, const u32 buf_size);
131130 int tipc_bclink_reset_stats(struct net *net);
132131 int tipc_bclink_set_queue_limits(struct net *net, u32 limit);
133132 void tipc_bcbearer_sort(struct net *net, struct tipc_node_map *nm_ptr,
net/tipc/config.c+0−4
@@ -213,10 +213,6 @@ struct sk_buff *tipc_cfg_do_cmd(struct net *net, u32 orig_node, u16 cmd, · 212 unmodified lines
213213 rep_tlv_buf = tipc_node_get_links(net, req_tlv_area,
214214 req_tlv_space);
215215 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;
220216 case TIPC_CMD_RESET_LINK_STATS:
221217 rep_tlv_buf = tipc_link_cmd_reset_stats(net, req_tlv_area,
222218 req_tlv_space);
net/tipc/link.c+0−141
@@ -2146,147 +2146,6 @@ struct sk_buff *tipc_link_cmd_reset_stats(struct net *net, · 2145 unmodified lines
21462146 return tipc_cfg_reply_none();
21472147 }
21482148
2149−/**
2150− * percent - convert count to a percentage of total (rounding up or down)
2151− */
2152−static 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− */
2166−static 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−
2257−struct 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−
22902149 static void link_print(struct tipc_link *l_ptr, const char *str)
22912150 {
22922151 struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id);
net/tipc/link.h+0−3
@@ -217,9 +217,6 @@ int tipc_link_is_active(struct tipc_link *l_ptr); · 216 unmodified lines
217217 void tipc_link_purge_queues(struct tipc_link *l_ptr);
218218 struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area,
219219 int req_tlv_space, u16 cmd);
220−struct sk_buff *tipc_link_cmd_show_stats(struct net *net,
221− const void *req_tlv_area,
222− int req_tlv_space);
223220 struct sk_buff *tipc_link_cmd_reset_stats(struct net *net,
224221 const void *req_tlv_area,
225222 int req_tlv_space);
net/tipc/netlink_compat.c+205−0
@@ -34,6 +34,7 @@ · 33 unmodified lines
3434 #include "core.h"
3535 #include "config.h"
3636 #include "bearer.h"
37+#include "link.h"
3738 #include <net/genetlink.h>
3839 #include <linux/tipc_config.h>
3940
@@ -48,6 +49,7 @@ · 8 unmodified lines
4849
4950 struct tipc_nl_compat_msg {
5051 u16 cmd;
52+ int rep_type;
5153 int rep_size;
5254 int req_type;
5355 struct sk_buff *rep;
@@ -95,6 +97,40 @@ static int tipc_add_tlv(struct sk_buff *skb, u16 type, void *data, u16 len) · 41 unmodified lines
9597 return 0;
9698 }
9799
100+static 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+
109+static 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+
98134 static struct sk_buff *tipc_tlv_alloc(int size)
99135 {
100136 int hdr_len;
@@ -200,10 +236,16 @@ static int tipc_nl_compat_dumpit(struct tipc_nl_compat_cmd_dump *cmd, · 99 unmodified lines
200236 int err;
201237 struct sk_buff *arg;
202238
239+ if (msg->req_type && !TLV_CHECK_TYPE(msg->req, msg->req_type))
240+ return -EINVAL;
241+
203242 msg->rep = tipc_tlv_alloc(msg->rep_size);
204243 if (!msg->rep)
205244 return -ENOMEM;
206245
246+ if (msg->rep_type)
247+ tipc_tlv_init(msg->rep, msg->rep_type);
248+
207249 arg = nlmsg_new(0, GFP_KERNEL);
208250 if (!arg) {
209251 kfree_skb(msg->rep);
@@ -356,6 +398,161 @@ static int tipc_nl_compat_bearer_disable(struct sk_buff *skb, · 146 unmodified lines
356398 return 0;
357399 }
358400
401+static inline u32 perc(u32 count, u32 total)
402+{
403+ return (count * 100 + (total / 2)) / total;
404+}
405+
406+static 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+
445+static 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+
359556 static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg)
360557 {
361558 struct tipc_nl_compat_cmd_dump dump;
@@ -380,6 +577,13 @@ static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) · 18 unmodified lines
380577 doit.doit = tipc_nl_bearer_disable;
381578 doit.transcode = tipc_nl_compat_bearer_disable;
382579 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);
383587 }
384588
385589 return -EOPNOTSUPP;
@@ -479,6 +683,7 @@ static int tipc_nl_compat_tmp_wrap(struct sk_buff *skb, struct genl_info *info) · 93 unmodified lines
479683 case TIPC_CMD_GET_BEARER_NAMES:
480684 case TIPC_CMD_ENABLE_BEARER:
481685 case TIPC_CMD_DISABLE_BEARER:
686+ case TIPC_CMD_SHOW_LINK_STATS:
482687 return tipc_nl_compat_recv(skb, info);
483688 }
484689