diff options
Diffstat (limited to 'net/tipc/netlink_compat.c')
-rw-r--r-- | net/tipc/netlink_compat.c | 205 |
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 | ||
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 | ||