aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/netlink_compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/tipc/netlink_compat.c')
-rw-r--r--net/tipc/netlink_compat.c205
1 files changed, 205 insertions, 0 deletions
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