diff options
author | Richard Alpe <richard.alpe@ericsson.com> | 2015-02-09 03:50:06 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-02-09 16:20:47 -0500 |
commit | f2b3b2d4ccbf9666f5f42a21347cd1aaa532b2fa (patch) | |
tree | 36a8eea16c58cd54f91ced3862da77803b223dcf | |
parent | 9ab154658a7ff2c5076607e02f18581c6859fc2a (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>
-rw-r--r-- | include/uapi/linux/tipc_config.h | 10 | ||||
-rw-r--r-- | net/tipc/bcast.c | 43 | ||||
-rw-r--r-- | net/tipc/bcast.h | 1 | ||||
-rw-r--r-- | net/tipc/config.c | 4 | ||||
-rw-r--r-- | net/tipc/link.c | 141 | ||||
-rw-r--r-- | net/tipc/link.h | 3 | ||||
-rw-r--r-- | net/tipc/netlink_compat.c | 205 |
7 files changed, 215 insertions, 192 deletions
diff --git a/include/uapi/linux/tipc_config.h b/include/uapi/linux/tipc_config.h index f9226566c1b8..087b0ef82c07 100644 --- a/include/uapi/linux/tipc_config.h +++ b/include/uapi/linux/tipc_config.h | |||
@@ -277,11 +277,21 @@ static inline int TLV_GET_LEN(struct tlv_desc *tlv) | |||
277 | return ntohs(tlv->tlv_len); | 277 | return ntohs(tlv->tlv_len); |
278 | } | 278 | } |
279 | 279 | ||
280 | static inline void TLV_SET_LEN(struct tlv_desc *tlv, __u16 len) | ||
281 | { | ||
282 | tlv->tlv_len = htons(len); | ||
283 | } | ||
284 | |||
280 | static inline int TLV_CHECK_TYPE(struct tlv_desc *tlv, __u16 type) | 285 | static inline int TLV_CHECK_TYPE(struct tlv_desc *tlv, __u16 type) |
281 | { | 286 | { |
282 | return (ntohs(tlv->tlv_type) == type); | 287 | return (ntohs(tlv->tlv_type) == type); |
283 | } | 288 | } |
284 | 289 | ||
290 | static inline void TLV_SET_TYPE(struct tlv_desc *tlv, __u16 type) | ||
291 | { | ||
292 | tlv->tlv_type = htons(type); | ||
293 | } | ||
294 | |||
285 | static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len) | 295 | static inline int TLV_SET(void *tlv, __u16 type, void *data, __u16 len) |
286 | { | 296 | { |
287 | struct tlv_desc *tlv_ptr; | 297 | struct tlv_desc *tlv_ptr; |
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 | ||
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 | |||
906 | int tipc_bclink_reset_stats(struct net *net) | 863 | int 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); | |||
127 | u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); | 127 | u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr); |
128 | void tipc_bclink_update_link_state(struct tipc_node *node, | 128 | void tipc_bclink_update_link_state(struct tipc_node *node, |
129 | u32 last_sent); | 129 | u32 last_sent); |
130 | int tipc_bclink_stats(struct net *net, char *stats_buf, const u32 buf_size); | ||
131 | int tipc_bclink_reset_stats(struct net *net); | 130 | int tipc_bclink_reset_stats(struct net *net); |
132 | int tipc_bclink_set_queue_limits(struct net *net, u32 limit); | 131 | int tipc_bclink_set_queue_limits(struct net *net, u32 limit); |
133 | void tipc_bcbearer_sort(struct net *net, struct tipc_node_map *nm_ptr, | 132 | void 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 | */ | ||
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 | |||
2290 | static void link_print(struct tipc_link *l_ptr, const char *str) | 2149 | static 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); | |||
217 | void tipc_link_purge_queues(struct tipc_link *l_ptr); | 217 | void tipc_link_purge_queues(struct tipc_link *l_ptr); |
218 | struct sk_buff *tipc_link_cmd_config(struct net *net, const void *req_tlv_area, | 218 | struct 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); |
220 | struct sk_buff *tipc_link_cmd_show_stats(struct net *net, | ||
221 | const void *req_tlv_area, | ||
222 | int req_tlv_space); | ||
223 | struct sk_buff *tipc_link_cmd_reset_stats(struct net *net, | 220 | struct 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 | ||
49 | struct tipc_nl_compat_msg { | 50 | struct 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 | ||
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 | |||
98 | static struct sk_buff *tipc_tlv_alloc(int size) | 134 | static 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 | ||
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 | |||
359 | static int tipc_nl_compat_handle(struct tipc_nl_compat_msg *msg) | 556 | static 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 | ||