diff options
| -rw-r--r-- | include/uapi/linux/tipc_netlink.h | 62 | ||||
| -rw-r--r-- | net/tipc/bcast.c | 111 | ||||
| -rw-r--r-- | net/tipc/bcast.h | 4 | ||||
| -rw-r--r-- | net/tipc/link.c | 287 | ||||
| -rw-r--r-- | net/tipc/link.h | 2 | ||||
| -rw-r--r-- | net/tipc/netlink.c | 10 |
6 files changed, 475 insertions, 1 deletions
diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h index 7e51ff61dccd..1034fb43d32e 100644 --- a/include/uapi/linux/tipc_netlink.h +++ b/include/uapi/linux/tipc_netlink.h | |||
| @@ -47,6 +47,7 @@ enum { | |||
| 47 | TIPC_NL_BEARER_SET, | 47 | TIPC_NL_BEARER_SET, |
| 48 | TIPC_NL_SOCK_GET, | 48 | TIPC_NL_SOCK_GET, |
| 49 | TIPC_NL_PUBL_GET, | 49 | TIPC_NL_PUBL_GET, |
| 50 | TIPC_NL_LINK_GET, | ||
| 50 | 51 | ||
| 51 | __TIPC_NL_CMD_MAX, | 52 | __TIPC_NL_CMD_MAX, |
| 52 | TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 | 53 | TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 |
| @@ -58,6 +59,7 @@ enum { | |||
| 58 | TIPC_NLA_BEARER, /* nest */ | 59 | TIPC_NLA_BEARER, /* nest */ |
| 59 | TIPC_NLA_SOCK, /* nest */ | 60 | TIPC_NLA_SOCK, /* nest */ |
| 60 | TIPC_NLA_PUBL, /* nest */ | 61 | TIPC_NLA_PUBL, /* nest */ |
| 62 | TIPC_NLA_LINK, /* nest */ | ||
| 61 | 63 | ||
| 62 | __TIPC_NLA_MAX, | 64 | __TIPC_NLA_MAX, |
| 63 | TIPC_NLA_MAX = __TIPC_NLA_MAX - 1 | 65 | TIPC_NLA_MAX = __TIPC_NLA_MAX - 1 |
| @@ -86,6 +88,24 @@ enum { | |||
| 86 | TIPC_NLA_SOCK_MAX = __TIPC_NLA_SOCK_MAX - 1 | 88 | TIPC_NLA_SOCK_MAX = __TIPC_NLA_SOCK_MAX - 1 |
| 87 | }; | 89 | }; |
| 88 | 90 | ||
| 91 | /* Link info */ | ||
| 92 | enum { | ||
| 93 | TIPC_NLA_LINK_UNSPEC, | ||
| 94 | TIPC_NLA_LINK_NAME, /* string */ | ||
| 95 | TIPC_NLA_LINK_DEST, /* u32 */ | ||
| 96 | TIPC_NLA_LINK_MTU, /* u32 */ | ||
| 97 | TIPC_NLA_LINK_BROADCAST, /* flag */ | ||
| 98 | TIPC_NLA_LINK_UP, /* flag */ | ||
| 99 | TIPC_NLA_LINK_ACTIVE, /* flag */ | ||
| 100 | TIPC_NLA_LINK_PROP, /* nest */ | ||
| 101 | TIPC_NLA_LINK_STATS, /* nest */ | ||
| 102 | TIPC_NLA_LINK_RX, /* u32 */ | ||
| 103 | TIPC_NLA_LINK_TX, /* u32 */ | ||
| 104 | |||
| 105 | __TIPC_NLA_LINK_MAX, | ||
| 106 | TIPC_NLA_LINK_MAX = __TIPC_NLA_LINK_MAX - 1 | ||
| 107 | }; | ||
| 108 | |||
| 89 | /* Publication info */ | 109 | /* Publication info */ |
| 90 | enum { | 110 | enum { |
| 91 | TIPC_NLA_PUBL_UNSPEC, | 111 | TIPC_NLA_PUBL_UNSPEC, |
| @@ -128,4 +148,46 @@ enum { | |||
| 128 | TIPC_NLA_PROP_MAX = __TIPC_NLA_PROP_MAX - 1 | 148 | TIPC_NLA_PROP_MAX = __TIPC_NLA_PROP_MAX - 1 |
| 129 | }; | 149 | }; |
| 130 | 150 | ||
| 151 | /* Nest, statistics info */ | ||
| 152 | enum { | ||
| 153 | TIPC_NLA_STATS_UNSPEC, | ||
| 154 | |||
| 155 | TIPC_NLA_STATS_RX_INFO, /* u32 */ | ||
| 156 | TIPC_NLA_STATS_RX_FRAGMENTS, /* u32 */ | ||
| 157 | TIPC_NLA_STATS_RX_FRAGMENTED, /* u32 */ | ||
| 158 | TIPC_NLA_STATS_RX_BUNDLES, /* u32 */ | ||
| 159 | TIPC_NLA_STATS_RX_BUNDLED, /* u32 */ | ||
| 160 | TIPC_NLA_STATS_TX_INFO, /* u32 */ | ||
| 161 | TIPC_NLA_STATS_TX_FRAGMENTS, /* u32 */ | ||
| 162 | TIPC_NLA_STATS_TX_FRAGMENTED, /* u32 */ | ||
| 163 | TIPC_NLA_STATS_TX_BUNDLES, /* u32 */ | ||
| 164 | TIPC_NLA_STATS_TX_BUNDLED, /* u32 */ | ||
| 165 | TIPC_NLA_STATS_MSG_PROF_TOT, /* u32 */ | ||
| 166 | TIPC_NLA_STATS_MSG_LEN_CNT, /* u32 */ | ||
| 167 | TIPC_NLA_STATS_MSG_LEN_TOT, /* u32 */ | ||
| 168 | TIPC_NLA_STATS_MSG_LEN_P0, /* u32 */ | ||
| 169 | TIPC_NLA_STATS_MSG_LEN_P1, /* u32 */ | ||
| 170 | TIPC_NLA_STATS_MSG_LEN_P2, /* u32 */ | ||
| 171 | TIPC_NLA_STATS_MSG_LEN_P3, /* u32 */ | ||
| 172 | TIPC_NLA_STATS_MSG_LEN_P4, /* u32 */ | ||
| 173 | TIPC_NLA_STATS_MSG_LEN_P5, /* u32 */ | ||
| 174 | TIPC_NLA_STATS_MSG_LEN_P6, /* u32 */ | ||
| 175 | TIPC_NLA_STATS_RX_STATES, /* u32 */ | ||
| 176 | TIPC_NLA_STATS_RX_PROBES, /* u32 */ | ||
| 177 | TIPC_NLA_STATS_RX_NACKS, /* u32 */ | ||
| 178 | TIPC_NLA_STATS_RX_DEFERRED, /* u32 */ | ||
| 179 | TIPC_NLA_STATS_TX_STATES, /* u32 */ | ||
| 180 | TIPC_NLA_STATS_TX_PROBES, /* u32 */ | ||
| 181 | TIPC_NLA_STATS_TX_NACKS, /* u32 */ | ||
| 182 | TIPC_NLA_STATS_TX_ACKS, /* u32 */ | ||
| 183 | TIPC_NLA_STATS_RETRANSMITTED, /* u32 */ | ||
| 184 | TIPC_NLA_STATS_DUPLICATES, /* u32 */ | ||
| 185 | TIPC_NLA_STATS_LINK_CONGS, /* u32 */ | ||
| 186 | TIPC_NLA_STATS_MAX_QUEUE, /* u32 */ | ||
| 187 | TIPC_NLA_STATS_AVG_QUEUE, /* u32 */ | ||
| 188 | |||
| 189 | __TIPC_NLA_STATS_MAX, | ||
| 190 | TIPC_NLA_STATS_MAX = __TIPC_NLA_STATS_MAX - 1 | ||
| 191 | }; | ||
| 192 | |||
| 131 | #endif | 193 | #endif |
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index b8670bf262e2..dcf3589e3cc5 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
| @@ -767,6 +767,117 @@ void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action) | |||
| 767 | tipc_bclink_unlock(); | 767 | tipc_bclink_unlock(); |
| 768 | } | 768 | } |
| 769 | 769 | ||
| 770 | int __tipc_nl_add_bc_link_stat(struct sk_buff *skb, struct tipc_stats *stats) | ||
| 771 | { | ||
| 772 | int i; | ||
| 773 | struct nlattr *nest; | ||
| 774 | |||
| 775 | struct nla_map { | ||
| 776 | __u32 key; | ||
| 777 | __u32 val; | ||
| 778 | }; | ||
| 779 | |||
| 780 | struct nla_map map[] = { | ||
| 781 | {TIPC_NLA_STATS_RX_INFO, stats->recv_info}, | ||
| 782 | {TIPC_NLA_STATS_RX_FRAGMENTS, stats->recv_fragments}, | ||
| 783 | {TIPC_NLA_STATS_RX_FRAGMENTED, stats->recv_fragmented}, | ||
| 784 | {TIPC_NLA_STATS_RX_BUNDLES, stats->recv_bundles}, | ||
| 785 | {TIPC_NLA_STATS_RX_BUNDLED, stats->recv_bundled}, | ||
| 786 | {TIPC_NLA_STATS_TX_INFO, stats->sent_info}, | ||
| 787 | {TIPC_NLA_STATS_TX_FRAGMENTS, stats->sent_fragments}, | ||
| 788 | {TIPC_NLA_STATS_TX_FRAGMENTED, stats->sent_fragmented}, | ||
| 789 | {TIPC_NLA_STATS_TX_BUNDLES, stats->sent_bundles}, | ||
| 790 | {TIPC_NLA_STATS_TX_BUNDLED, stats->sent_bundled}, | ||
| 791 | {TIPC_NLA_STATS_RX_NACKS, stats->recv_nacks}, | ||
| 792 | {TIPC_NLA_STATS_RX_DEFERRED, stats->deferred_recv}, | ||
| 793 | {TIPC_NLA_STATS_TX_NACKS, stats->sent_nacks}, | ||
| 794 | {TIPC_NLA_STATS_TX_ACKS, stats->sent_acks}, | ||
| 795 | {TIPC_NLA_STATS_RETRANSMITTED, stats->retransmitted}, | ||
| 796 | {TIPC_NLA_STATS_DUPLICATES, stats->duplicates}, | ||
| 797 | {TIPC_NLA_STATS_LINK_CONGS, stats->link_congs}, | ||
| 798 | {TIPC_NLA_STATS_MAX_QUEUE, stats->max_queue_sz}, | ||
| 799 | {TIPC_NLA_STATS_AVG_QUEUE, stats->queue_sz_counts ? | ||
| 800 | (stats->accu_queue_sz / stats->queue_sz_counts) : 0} | ||
| 801 | }; | ||
| 802 | |||
| 803 | nest = nla_nest_start(skb, TIPC_NLA_LINK_STATS); | ||
| 804 | if (!nest) | ||
| 805 | return -EMSGSIZE; | ||
| 806 | |||
| 807 | for (i = 0; i < ARRAY_SIZE(map); i++) | ||
| 808 | if (nla_put_u32(skb, map[i].key, map[i].val)) | ||
| 809 | goto msg_full; | ||
| 810 | |||
| 811 | nla_nest_end(skb, nest); | ||
| 812 | |||
| 813 | return 0; | ||
| 814 | msg_full: | ||
| 815 | nla_nest_cancel(skb, nest); | ||
| 816 | |||
| 817 | return -EMSGSIZE; | ||
| 818 | } | ||
| 819 | |||
| 820 | int tipc_nl_add_bc_link(struct tipc_nl_msg *msg) | ||
| 821 | { | ||
| 822 | int err; | ||
| 823 | void *hdr; | ||
| 824 | struct nlattr *attrs; | ||
| 825 | struct nlattr *prop; | ||
| 826 | |||
| 827 | if (!bcl) | ||
| 828 | return 0; | ||
| 829 | |||
| 830 | tipc_bclink_lock(); | ||
| 831 | |||
| 832 | hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, | ||
| 833 | NLM_F_MULTI, TIPC_NL_LINK_GET); | ||
| 834 | if (!hdr) | ||
| 835 | return -EMSGSIZE; | ||
| 836 | |||
| 837 | attrs = nla_nest_start(msg->skb, TIPC_NLA_LINK); | ||
| 838 | if (!attrs) | ||
| 839 | goto msg_full; | ||
| 840 | |||
| 841 | /* The broadcast link is always up */ | ||
| 842 | if (nla_put_flag(msg->skb, TIPC_NLA_LINK_UP)) | ||
| 843 | goto attr_msg_full; | ||
| 844 | |||
| 845 | if (nla_put_flag(msg->skb, TIPC_NLA_LINK_BROADCAST)) | ||
| 846 | goto attr_msg_full; | ||
| 847 | if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, bcl->name)) | ||
| 848 | goto attr_msg_full; | ||
| 849 | if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, bcl->next_in_no)) | ||
| 850 | goto attr_msg_full; | ||
| 851 | if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, bcl->next_out_no)) | ||
| 852 | goto attr_msg_full; | ||
| 853 | |||
| 854 | prop = nla_nest_start(msg->skb, TIPC_NLA_LINK_PROP); | ||
| 855 | if (!prop) | ||
| 856 | goto attr_msg_full; | ||
| 857 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bcl->queue_limit[0])) | ||
| 858 | goto prop_msg_full; | ||
| 859 | nla_nest_end(msg->skb, prop); | ||
| 860 | |||
| 861 | err = __tipc_nl_add_bc_link_stat(msg->skb, &bcl->stats); | ||
| 862 | if (err) | ||
| 863 | goto attr_msg_full; | ||
| 864 | |||
| 865 | tipc_bclink_unlock(); | ||
| 866 | nla_nest_end(msg->skb, attrs); | ||
| 867 | genlmsg_end(msg->skb, hdr); | ||
| 868 | |||
| 869 | return 0; | ||
| 870 | |||
| 871 | prop_msg_full: | ||
| 872 | nla_nest_cancel(msg->skb, prop); | ||
| 873 | attr_msg_full: | ||
| 874 | nla_nest_cancel(msg->skb, attrs); | ||
| 875 | msg_full: | ||
| 876 | tipc_bclink_unlock(); | ||
| 877 | genlmsg_cancel(msg->skb, hdr); | ||
| 878 | |||
| 879 | return -EMSGSIZE; | ||
| 880 | } | ||
| 770 | 881 | ||
| 771 | int tipc_bclink_stats(char *buf, const u32 buf_size) | 882 | int tipc_bclink_stats(char *buf, const u32 buf_size) |
| 772 | { | 883 | { |
diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index e7b0f85a82bc..443de084d3e8 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h | |||
| @@ -37,6 +37,8 @@ | |||
| 37 | #ifndef _TIPC_BCAST_H | 37 | #ifndef _TIPC_BCAST_H |
| 38 | #define _TIPC_BCAST_H | 38 | #define _TIPC_BCAST_H |
| 39 | 39 | ||
| 40 | #include "netlink.h" | ||
| 41 | |||
| 40 | #define MAX_NODES 4096 | 42 | #define MAX_NODES 4096 |
| 41 | #define WSIZE 32 | 43 | #define WSIZE 32 |
| 42 | #define TIPC_BCLINK_RESET 1 | 44 | #define TIPC_BCLINK_RESET 1 |
| @@ -100,4 +102,6 @@ void tipc_bcbearer_sort(struct tipc_node_map *nm_ptr, u32 node, bool action); | |||
| 100 | uint tipc_bclink_get_mtu(void); | 102 | uint tipc_bclink_get_mtu(void); |
| 101 | int tipc_bclink_xmit(struct sk_buff *buf); | 103 | int tipc_bclink_xmit(struct sk_buff *buf); |
| 102 | void tipc_bclink_wakeup_users(void); | 104 | void tipc_bclink_wakeup_users(void); |
| 105 | int tipc_nl_add_bc_link(struct tipc_nl_msg *msg); | ||
| 106 | |||
| 103 | #endif | 107 | #endif |
diff --git a/net/tipc/link.c b/net/tipc/link.c index e7f365012bd1..bdc4b5e5bf56 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | 36 | ||
| 37 | #include "core.h" | 37 | #include "core.h" |
| 38 | #include "link.h" | 38 | #include "link.h" |
| 39 | #include "bcast.h" | ||
| 39 | #include "socket.h" | 40 | #include "socket.h" |
| 40 | #include "name_distr.h" | 41 | #include "name_distr.h" |
| 41 | #include "discover.h" | 42 | #include "discover.h" |
| @@ -51,6 +52,22 @@ static const char *link_co_err = "Link changeover error, "; | |||
| 51 | static const char *link_rst_msg = "Resetting link "; | 52 | static const char *link_rst_msg = "Resetting link "; |
| 52 | static const char *link_unk_evt = "Unknown link event "; | 53 | static const char *link_unk_evt = "Unknown link event "; |
| 53 | 54 | ||
| 55 | static const struct nla_policy tipc_nl_link_policy[TIPC_NLA_LINK_MAX + 1] = { | ||
| 56 | [TIPC_NLA_LINK_UNSPEC] = { .type = NLA_UNSPEC }, | ||
| 57 | [TIPC_NLA_LINK_NAME] = { | ||
| 58 | .type = NLA_STRING, | ||
| 59 | .len = TIPC_MAX_LINK_NAME | ||
| 60 | }, | ||
| 61 | [TIPC_NLA_LINK_MTU] = { .type = NLA_U32 }, | ||
| 62 | [TIPC_NLA_LINK_BROADCAST] = { .type = NLA_FLAG }, | ||
| 63 | [TIPC_NLA_LINK_UP] = { .type = NLA_FLAG }, | ||
| 64 | [TIPC_NLA_LINK_ACTIVE] = { .type = NLA_FLAG }, | ||
| 65 | [TIPC_NLA_LINK_PROP] = { .type = NLA_NESTED }, | ||
| 66 | [TIPC_NLA_LINK_STATS] = { .type = NLA_NESTED }, | ||
| 67 | [TIPC_NLA_LINK_RX] = { .type = NLA_U32 }, | ||
| 68 | [TIPC_NLA_LINK_TX] = { .type = NLA_U32 } | ||
| 69 | }; | ||
| 70 | |||
| 54 | /* Properties valid for media, bearar and link */ | 71 | /* Properties valid for media, bearar and link */ |
| 55 | static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { | 72 | static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { |
| 56 | [TIPC_NLA_PROP_UNSPEC] = { .type = NLA_UNSPEC }, | 73 | [TIPC_NLA_PROP_UNSPEC] = { .type = NLA_UNSPEC }, |
| @@ -2423,3 +2440,273 @@ int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]) | |||
| 2423 | 2440 | ||
| 2424 | return 0; | 2441 | return 0; |
| 2425 | } | 2442 | } |
| 2443 | |||
| 2444 | int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s) | ||
| 2445 | { | ||
| 2446 | int i; | ||
| 2447 | struct nlattr *stats; | ||
| 2448 | |||
| 2449 | struct nla_map { | ||
| 2450 | u32 key; | ||
| 2451 | u32 val; | ||
| 2452 | }; | ||
| 2453 | |||
| 2454 | struct nla_map map[] = { | ||
| 2455 | {TIPC_NLA_STATS_RX_INFO, s->recv_info}, | ||
| 2456 | {TIPC_NLA_STATS_RX_FRAGMENTS, s->recv_fragments}, | ||
| 2457 | {TIPC_NLA_STATS_RX_FRAGMENTED, s->recv_fragmented}, | ||
| 2458 | {TIPC_NLA_STATS_RX_BUNDLES, s->recv_bundles}, | ||
| 2459 | {TIPC_NLA_STATS_RX_BUNDLED, s->recv_bundled}, | ||
| 2460 | {TIPC_NLA_STATS_TX_INFO, s->sent_info}, | ||
| 2461 | {TIPC_NLA_STATS_TX_FRAGMENTS, s->sent_fragments}, | ||
| 2462 | {TIPC_NLA_STATS_TX_FRAGMENTED, s->sent_fragmented}, | ||
| 2463 | {TIPC_NLA_STATS_TX_BUNDLES, s->sent_bundles}, | ||
| 2464 | {TIPC_NLA_STATS_TX_BUNDLED, s->sent_bundled}, | ||
| 2465 | {TIPC_NLA_STATS_MSG_PROF_TOT, (s->msg_length_counts) ? | ||
| 2466 | s->msg_length_counts : 1}, | ||
| 2467 | {TIPC_NLA_STATS_MSG_LEN_CNT, s->msg_length_counts}, | ||
| 2468 | {TIPC_NLA_STATS_MSG_LEN_TOT, s->msg_lengths_total}, | ||
| 2469 | {TIPC_NLA_STATS_MSG_LEN_P0, s->msg_length_profile[0]}, | ||
| 2470 | {TIPC_NLA_STATS_MSG_LEN_P1, s->msg_length_profile[1]}, | ||
| 2471 | {TIPC_NLA_STATS_MSG_LEN_P2, s->msg_length_profile[2]}, | ||
| 2472 | {TIPC_NLA_STATS_MSG_LEN_P3, s->msg_length_profile[3]}, | ||
| 2473 | {TIPC_NLA_STATS_MSG_LEN_P4, s->msg_length_profile[4]}, | ||
| 2474 | {TIPC_NLA_STATS_MSG_LEN_P5, s->msg_length_profile[5]}, | ||
| 2475 | {TIPC_NLA_STATS_MSG_LEN_P6, s->msg_length_profile[6]}, | ||
| 2476 | {TIPC_NLA_STATS_RX_STATES, s->recv_states}, | ||
| 2477 | {TIPC_NLA_STATS_RX_PROBES, s->recv_probes}, | ||
| 2478 | {TIPC_NLA_STATS_RX_NACKS, s->recv_nacks}, | ||
| 2479 | {TIPC_NLA_STATS_RX_DEFERRED, s->deferred_recv}, | ||
| 2480 | {TIPC_NLA_STATS_TX_STATES, s->sent_states}, | ||
| 2481 | {TIPC_NLA_STATS_TX_PROBES, s->sent_probes}, | ||
| 2482 | {TIPC_NLA_STATS_TX_NACKS, s->sent_nacks}, | ||
| 2483 | {TIPC_NLA_STATS_TX_ACKS, s->sent_acks}, | ||
| 2484 | {TIPC_NLA_STATS_RETRANSMITTED, s->retransmitted}, | ||
| 2485 | {TIPC_NLA_STATS_DUPLICATES, s->duplicates}, | ||
| 2486 | {TIPC_NLA_STATS_LINK_CONGS, s->link_congs}, | ||
| 2487 | {TIPC_NLA_STATS_MAX_QUEUE, s->max_queue_sz}, | ||
| 2488 | {TIPC_NLA_STATS_AVG_QUEUE, s->queue_sz_counts ? | ||
| 2489 | (s->accu_queue_sz / s->queue_sz_counts) : 0} | ||
| 2490 | }; | ||
| 2491 | |||
| 2492 | stats = nla_nest_start(skb, TIPC_NLA_LINK_STATS); | ||
| 2493 | if (!stats) | ||
| 2494 | return -EMSGSIZE; | ||
| 2495 | |||
| 2496 | for (i = 0; i < ARRAY_SIZE(map); i++) | ||
| 2497 | if (nla_put_u32(skb, map[i].key, map[i].val)) | ||
| 2498 | goto msg_full; | ||
| 2499 | |||
| 2500 | nla_nest_end(skb, stats); | ||
| 2501 | |||
| 2502 | return 0; | ||
| 2503 | msg_full: | ||
| 2504 | nla_nest_cancel(skb, stats); | ||
| 2505 | |||
| 2506 | return -EMSGSIZE; | ||
| 2507 | } | ||
| 2508 | |||
| 2509 | /* Caller should hold appropriate locks to protect the link */ | ||
| 2510 | int __tipc_nl_add_link(struct tipc_nl_msg *msg, struct tipc_link *link) | ||
| 2511 | { | ||
| 2512 | int err; | ||
| 2513 | void *hdr; | ||
| 2514 | struct nlattr *attrs; | ||
| 2515 | struct nlattr *prop; | ||
| 2516 | |||
| 2517 | hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_v2_family, | ||
| 2518 | NLM_F_MULTI, TIPC_NL_LINK_GET); | ||
| 2519 | if (!hdr) | ||
| 2520 | return -EMSGSIZE; | ||
| 2521 | |||
| 2522 | attrs = nla_nest_start(msg->skb, TIPC_NLA_LINK); | ||
| 2523 | if (!attrs) | ||
| 2524 | goto msg_full; | ||
| 2525 | |||
| 2526 | if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, link->name)) | ||
| 2527 | goto attr_msg_full; | ||
| 2528 | if (nla_put_u32(msg->skb, TIPC_NLA_LINK_DEST, | ||
| 2529 | tipc_cluster_mask(tipc_own_addr))) | ||
| 2530 | goto attr_msg_full; | ||
| 2531 | if (nla_put_u32(msg->skb, TIPC_NLA_LINK_MTU, link->max_pkt)) | ||
| 2532 | goto attr_msg_full; | ||
| 2533 | if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, link->next_in_no)) | ||
| 2534 | goto attr_msg_full; | ||
| 2535 | if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, link->next_out_no)) | ||
| 2536 | goto attr_msg_full; | ||
| 2537 | |||
| 2538 | if (tipc_link_is_up(link)) | ||
| 2539 | if (nla_put_flag(msg->skb, TIPC_NLA_LINK_UP)) | ||
| 2540 | goto attr_msg_full; | ||
| 2541 | if (tipc_link_is_active(link)) | ||
| 2542 | if (nla_put_flag(msg->skb, TIPC_NLA_LINK_ACTIVE)) | ||
| 2543 | goto attr_msg_full; | ||
| 2544 | |||
| 2545 | prop = nla_nest_start(msg->skb, TIPC_NLA_LINK_PROP); | ||
| 2546 | if (!prop) | ||
| 2547 | goto attr_msg_full; | ||
| 2548 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, link->priority)) | ||
| 2549 | goto prop_msg_full; | ||
| 2550 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_TOL, link->tolerance)) | ||
| 2551 | goto prop_msg_full; | ||
| 2552 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, | ||
| 2553 | link->queue_limit[TIPC_LOW_IMPORTANCE])) | ||
| 2554 | goto prop_msg_full; | ||
| 2555 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_PRIO, link->priority)) | ||
| 2556 | goto prop_msg_full; | ||
| 2557 | nla_nest_end(msg->skb, prop); | ||
| 2558 | |||
| 2559 | err = __tipc_nl_add_stats(msg->skb, &link->stats); | ||
| 2560 | if (err) | ||
| 2561 | goto attr_msg_full; | ||
| 2562 | |||
| 2563 | nla_nest_end(msg->skb, attrs); | ||
| 2564 | genlmsg_end(msg->skb, hdr); | ||
| 2565 | |||
| 2566 | return 0; | ||
| 2567 | |||
| 2568 | prop_msg_full: | ||
| 2569 | nla_nest_cancel(msg->skb, prop); | ||
| 2570 | attr_msg_full: | ||
| 2571 | nla_nest_cancel(msg->skb, attrs); | ||
| 2572 | msg_full: | ||
| 2573 | genlmsg_cancel(msg->skb, hdr); | ||
| 2574 | |||
| 2575 | return -EMSGSIZE; | ||
| 2576 | } | ||
| 2577 | |||
| 2578 | /* Caller should hold node lock */ | ||
| 2579 | int __tipc_nl_add_node_links(struct tipc_nl_msg *msg, struct tipc_node *node, | ||
| 2580 | u32 *prev_link) | ||
| 2581 | { | ||
| 2582 | u32 i; | ||
| 2583 | int err; | ||
| 2584 | |||
| 2585 | for (i = *prev_link; i < MAX_BEARERS; i++) { | ||
| 2586 | *prev_link = i; | ||
| 2587 | |||
| 2588 | if (!node->links[i]) | ||
| 2589 | continue; | ||
| 2590 | |||
| 2591 | err = __tipc_nl_add_link(msg, node->links[i]); | ||
| 2592 | if (err) | ||
| 2593 | return err; | ||
| 2594 | } | ||
| 2595 | *prev_link = 0; | ||
| 2596 | |||
| 2597 | return 0; | ||
| 2598 | } | ||
| 2599 | |||
| 2600 | int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
| 2601 | { | ||
| 2602 | struct tipc_node *node; | ||
| 2603 | struct tipc_nl_msg msg; | ||
| 2604 | u32 prev_node = cb->args[0]; | ||
| 2605 | u32 prev_link = cb->args[1]; | ||
| 2606 | int done = cb->args[2]; | ||
| 2607 | int err; | ||
| 2608 | |||
| 2609 | if (done) | ||
| 2610 | return 0; | ||
| 2611 | |||
| 2612 | msg.skb = skb; | ||
| 2613 | msg.portid = NETLINK_CB(cb->skb).portid; | ||
| 2614 | msg.seq = cb->nlh->nlmsg_seq; | ||
| 2615 | |||
| 2616 | rcu_read_lock(); | ||
| 2617 | |||
| 2618 | if (prev_node) { | ||
| 2619 | node = tipc_node_find(prev_node); | ||
| 2620 | if (!node) { | ||
| 2621 | /* We never set seq or call nl_dump_check_consistent() | ||
| 2622 | * this means that setting prev_seq here will cause the | ||
| 2623 | * consistence check to fail in the netlink callback | ||
| 2624 | * handler. Resulting in the last NLMSG_DONE message | ||
| 2625 | * having the NLM_F_DUMP_INTR flag set. | ||
| 2626 | */ | ||
| 2627 | cb->prev_seq = 1; | ||
| 2628 | goto out; | ||
| 2629 | } | ||
| 2630 | |||
| 2631 | list_for_each_entry_continue_rcu(node, &tipc_node_list, list) { | ||
| 2632 | tipc_node_lock(node); | ||
| 2633 | err = __tipc_nl_add_node_links(&msg, node, &prev_link); | ||
| 2634 | tipc_node_unlock(node); | ||
| 2635 | if (err) | ||
| 2636 | goto out; | ||
| 2637 | |||
| 2638 | prev_node = node->addr; | ||
| 2639 | } | ||
| 2640 | } else { | ||
| 2641 | err = tipc_nl_add_bc_link(&msg); | ||
| 2642 | if (err) | ||
| 2643 | goto out; | ||
| 2644 | |||
| 2645 | list_for_each_entry_rcu(node, &tipc_node_list, list) { | ||
| 2646 | tipc_node_lock(node); | ||
| 2647 | err = __tipc_nl_add_node_links(&msg, node, &prev_link); | ||
| 2648 | tipc_node_unlock(node); | ||
| 2649 | if (err) | ||
| 2650 | goto out; | ||
| 2651 | |||
| 2652 | prev_node = node->addr; | ||
| 2653 | } | ||
| 2654 | } | ||
| 2655 | done = 1; | ||
| 2656 | out: | ||
| 2657 | rcu_read_unlock(); | ||
| 2658 | |||
| 2659 | cb->args[0] = prev_node; | ||
| 2660 | cb->args[1] = prev_link; | ||
| 2661 | cb->args[2] = done; | ||
| 2662 | |||
| 2663 | return skb->len; | ||
| 2664 | } | ||
| 2665 | |||
| 2666 | int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info) | ||
| 2667 | { | ||
| 2668 | struct sk_buff *ans_skb; | ||
| 2669 | struct tipc_nl_msg msg; | ||
| 2670 | struct tipc_link *link; | ||
| 2671 | struct tipc_node *node; | ||
| 2672 | char *name; | ||
| 2673 | int bearer_id; | ||
| 2674 | int err; | ||
| 2675 | |||
| 2676 | if (!info->attrs[TIPC_NLA_LINK_NAME]) | ||
| 2677 | return -EINVAL; | ||
| 2678 | |||
| 2679 | name = nla_data(info->attrs[TIPC_NLA_LINK_NAME]); | ||
| 2680 | node = tipc_link_find_owner(name, &bearer_id); | ||
| 2681 | if (!node) | ||
| 2682 | return -EINVAL; | ||
| 2683 | |||
| 2684 | ans_skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | ||
| 2685 | if (!ans_skb) | ||
| 2686 | return -ENOMEM; | ||
| 2687 | |||
| 2688 | msg.skb = ans_skb; | ||
| 2689 | msg.portid = info->snd_portid; | ||
| 2690 | msg.seq = info->snd_seq; | ||
| 2691 | |||
| 2692 | tipc_node_lock(node); | ||
| 2693 | link = node->links[bearer_id]; | ||
| 2694 | if (!link) { | ||
| 2695 | err = -EINVAL; | ||
| 2696 | goto err_out; | ||
| 2697 | } | ||
| 2698 | |||
| 2699 | err = __tipc_nl_add_link(&msg, link); | ||
| 2700 | if (err) | ||
| 2701 | goto err_out; | ||
| 2702 | |||
| 2703 | tipc_node_unlock(node); | ||
| 2704 | |||
| 2705 | return genlmsg_reply(ans_skb, info); | ||
| 2706 | |||
| 2707 | err_out: | ||
| 2708 | tipc_node_unlock(node); | ||
| 2709 | nlmsg_free(ans_skb); | ||
| 2710 | |||
| 2711 | return err; | ||
| 2712 | } | ||
diff --git a/net/tipc/link.h b/net/tipc/link.h index 4338294f20d4..8e3542a4a037 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
| @@ -240,6 +240,8 @@ void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window); | |||
| 240 | void tipc_link_retransmit(struct tipc_link *l_ptr, | 240 | void tipc_link_retransmit(struct tipc_link *l_ptr, |
| 241 | struct sk_buff *start, u32 retransmits); | 241 | struct sk_buff *start, u32 retransmits); |
| 242 | 242 | ||
| 243 | int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb); | ||
| 244 | int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info); | ||
| 243 | int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]); | 245 | int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]); |
| 244 | 246 | ||
| 245 | /* | 247 | /* |
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c index 9bc64aaff466..ea168b889caa 100644 --- a/net/tipc/netlink.c +++ b/net/tipc/netlink.c | |||
| @@ -38,6 +38,7 @@ | |||
| 38 | #include "config.h" | 38 | #include "config.h" |
| 39 | #include "socket.h" | 39 | #include "socket.h" |
| 40 | #include "bearer.h" | 40 | #include "bearer.h" |
| 41 | #include "link.h" | ||
| 41 | #include <net/genetlink.h> | 42 | #include <net/genetlink.h> |
| 42 | 43 | ||
| 43 | static int handle_cmd(struct sk_buff *skb, struct genl_info *info) | 44 | static int handle_cmd(struct sk_buff *skb, struct genl_info *info) |
| @@ -74,7 +75,8 @@ static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = { | |||
| 74 | [TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, }, | 75 | [TIPC_NLA_UNSPEC] = { .type = NLA_UNSPEC, }, |
| 75 | [TIPC_NLA_BEARER] = { .type = NLA_NESTED, }, | 76 | [TIPC_NLA_BEARER] = { .type = NLA_NESTED, }, |
| 76 | [TIPC_NLA_SOCK] = { .type = NLA_NESTED, }, | 77 | [TIPC_NLA_SOCK] = { .type = NLA_NESTED, }, |
| 77 | [TIPC_NLA_PUBL] = { .type = NLA_NESTED, } | 78 | [TIPC_NLA_PUBL] = { .type = NLA_NESTED, }, |
| 79 | [TIPC_NLA_LINK] = { .type = NLA_NESTED, }, | ||
| 78 | }; | 80 | }; |
| 79 | 81 | ||
| 80 | /* Legacy ASCII API */ | 82 | /* Legacy ASCII API */ |
| @@ -136,6 +138,12 @@ static const struct genl_ops tipc_genl_v2_ops[] = { | |||
| 136 | .cmd = TIPC_NL_PUBL_GET, | 138 | .cmd = TIPC_NL_PUBL_GET, |
| 137 | .dumpit = tipc_nl_publ_dump, | 139 | .dumpit = tipc_nl_publ_dump, |
| 138 | .policy = tipc_nl_policy, | 140 | .policy = tipc_nl_policy, |
| 141 | }, | ||
| 142 | { | ||
| 143 | .cmd = TIPC_NL_LINK_GET, | ||
| 144 | .doit = tipc_nl_link_get, | ||
| 145 | .dumpit = tipc_nl_link_dump, | ||
| 146 | .policy = tipc_nl_policy, | ||
| 139 | } | 147 | } |
| 140 | }; | 148 | }; |
| 141 | 149 | ||
