aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/uapi/linux/tipc.h30
-rw-r--r--include/uapi/linux/tipc_netlink.h37
-rw-r--r--net/tipc/addr.h5
-rw-r--r--net/tipc/bearer.c25
-rw-r--r--net/tipc/bearer.h1
-rw-r--r--net/tipc/monitor.c152
-rw-r--r--net/tipc/monitor.h9
-rw-r--r--net/tipc/netlink.c27
-rw-r--r--net/tipc/netlink.h1
-rw-r--r--net/tipc/node.c165
-rw-r--r--net/tipc/node.h5
11 files changed, 445 insertions, 12 deletions
diff --git a/include/uapi/linux/tipc.h b/include/uapi/linux/tipc.h
index 6f71b9b41595..bf049e8fe31b 100644
--- a/include/uapi/linux/tipc.h
+++ b/include/uapi/linux/tipc.h
@@ -60,26 +60,48 @@ struct tipc_name_seq {
60 __u32 upper; 60 __u32 upper;
61}; 61};
62 62
63/* TIPC Address Size, Offset, Mask specification for Z.C.N
64 */
65#define TIPC_NODE_BITS 12
66#define TIPC_CLUSTER_BITS 12
67#define TIPC_ZONE_BITS 8
68
69#define TIPC_NODE_OFFSET 0
70#define TIPC_CLUSTER_OFFSET TIPC_NODE_BITS
71#define TIPC_ZONE_OFFSET (TIPC_CLUSTER_OFFSET + TIPC_CLUSTER_BITS)
72
73#define TIPC_NODE_SIZE ((1UL << TIPC_NODE_BITS) - 1)
74#define TIPC_CLUSTER_SIZE ((1UL << TIPC_CLUSTER_BITS) - 1)
75#define TIPC_ZONE_SIZE ((1UL << TIPC_ZONE_BITS) - 1)
76
77#define TIPC_NODE_MASK (TIPC_NODE_SIZE << TIPC_NODE_OFFSET)
78#define TIPC_CLUSTER_MASK (TIPC_CLUSTER_SIZE << TIPC_CLUSTER_OFFSET)
79#define TIPC_ZONE_MASK (TIPC_ZONE_SIZE << TIPC_ZONE_OFFSET)
80
81#define TIPC_ZONE_CLUSTER_MASK (TIPC_ZONE_MASK | TIPC_CLUSTER_MASK)
82
63static inline __u32 tipc_addr(unsigned int zone, 83static inline __u32 tipc_addr(unsigned int zone,
64 unsigned int cluster, 84 unsigned int cluster,
65 unsigned int node) 85 unsigned int node)
66{ 86{
67 return (zone << 24) | (cluster << 12) | node; 87 return (zone << TIPC_ZONE_OFFSET) |
88 (cluster << TIPC_CLUSTER_OFFSET) |
89 node;
68} 90}
69 91
70static inline unsigned int tipc_zone(__u32 addr) 92static inline unsigned int tipc_zone(__u32 addr)
71{ 93{
72 return addr >> 24; 94 return addr >> TIPC_ZONE_OFFSET;
73} 95}
74 96
75static inline unsigned int tipc_cluster(__u32 addr) 97static inline unsigned int tipc_cluster(__u32 addr)
76{ 98{
77 return (addr >> 12) & 0xfff; 99 return (addr & TIPC_CLUSTER_MASK) >> TIPC_CLUSTER_OFFSET;
78} 100}
79 101
80static inline unsigned int tipc_node(__u32 addr) 102static inline unsigned int tipc_node(__u32 addr)
81{ 103{
82 return addr & 0xfff; 104 return addr & TIPC_NODE_MASK;
83} 105}
84 106
85/* 107/*
diff --git a/include/uapi/linux/tipc_netlink.h b/include/uapi/linux/tipc_netlink.h
index d4c8f142ba63..5f3f6d09fb79 100644
--- a/include/uapi/linux/tipc_netlink.h
+++ b/include/uapi/linux/tipc_netlink.h
@@ -56,6 +56,9 @@ enum {
56 TIPC_NL_NET_GET, 56 TIPC_NL_NET_GET,
57 TIPC_NL_NET_SET, 57 TIPC_NL_NET_SET,
58 TIPC_NL_NAME_TABLE_GET, 58 TIPC_NL_NAME_TABLE_GET,
59 TIPC_NL_MON_SET,
60 TIPC_NL_MON_GET,
61 TIPC_NL_MON_PEER_GET,
59 62
60 __TIPC_NL_CMD_MAX, 63 __TIPC_NL_CMD_MAX,
61 TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1 64 TIPC_NL_CMD_MAX = __TIPC_NL_CMD_MAX - 1
@@ -72,6 +75,8 @@ enum {
72 TIPC_NLA_NODE, /* nest */ 75 TIPC_NLA_NODE, /* nest */
73 TIPC_NLA_NET, /* nest */ 76 TIPC_NLA_NET, /* nest */
74 TIPC_NLA_NAME_TABLE, /* nest */ 77 TIPC_NLA_NAME_TABLE, /* nest */
78 TIPC_NLA_MON, /* nest */
79 TIPC_NLA_MON_PEER, /* nest */
75 80
76 __TIPC_NLA_MAX, 81 __TIPC_NLA_MAX,
77 TIPC_NLA_MAX = __TIPC_NLA_MAX - 1 82 TIPC_NLA_MAX = __TIPC_NLA_MAX - 1
@@ -166,6 +171,20 @@ enum {
166 TIPC_NLA_NAME_TABLE_MAX = __TIPC_NLA_NAME_TABLE_MAX - 1 171 TIPC_NLA_NAME_TABLE_MAX = __TIPC_NLA_NAME_TABLE_MAX - 1
167}; 172};
168 173
174/* Monitor info */
175enum {
176 TIPC_NLA_MON_UNSPEC,
177 TIPC_NLA_MON_ACTIVATION_THRESHOLD, /* u32 */
178 TIPC_NLA_MON_REF, /* u32 */
179 TIPC_NLA_MON_ACTIVE, /* flag */
180 TIPC_NLA_MON_BEARER_NAME, /* string */
181 TIPC_NLA_MON_PEERCNT, /* u32 */
182 TIPC_NLA_MON_LISTGEN, /* u32 */
183
184 __TIPC_NLA_MON_MAX,
185 TIPC_NLA_MON_MAX = __TIPC_NLA_MON_MAX - 1
186};
187
169/* Publication info */ 188/* Publication info */
170enum { 189enum {
171 TIPC_NLA_PUBL_UNSPEC, 190 TIPC_NLA_PUBL_UNSPEC,
@@ -182,6 +201,24 @@ enum {
182 TIPC_NLA_PUBL_MAX = __TIPC_NLA_PUBL_MAX - 1 201 TIPC_NLA_PUBL_MAX = __TIPC_NLA_PUBL_MAX - 1
183}; 202};
184 203
204/* Monitor peer info */
205enum {
206 TIPC_NLA_MON_PEER_UNSPEC,
207
208 TIPC_NLA_MON_PEER_ADDR, /* u32 */
209 TIPC_NLA_MON_PEER_DOMGEN, /* u32 */
210 TIPC_NLA_MON_PEER_APPLIED, /* u32 */
211 TIPC_NLA_MON_PEER_UPMAP, /* u64 */
212 TIPC_NLA_MON_PEER_MEMBERS, /* tlv */
213 TIPC_NLA_MON_PEER_UP, /* flag */
214 TIPC_NLA_MON_PEER_HEAD, /* flag */
215 TIPC_NLA_MON_PEER_LOCAL, /* flag */
216 TIPC_NLA_MON_PEER_PAD, /* flag */
217
218 __TIPC_NLA_MON_PEER_MAX,
219 TIPC_NLA_MON_PEER_MAX = __TIPC_NLA_MON_PEER_MAX - 1
220};
221
185/* Nest, connection info */ 222/* Nest, connection info */
186enum { 223enum {
187 TIPC_NLA_CON_UNSPEC, 224 TIPC_NLA_CON_UNSPEC,
diff --git a/net/tipc/addr.h b/net/tipc/addr.h
index 64f4004a6fac..bebb347803ce 100644
--- a/net/tipc/addr.h
+++ b/net/tipc/addr.h
@@ -43,9 +43,6 @@
43#include <net/netns/generic.h> 43#include <net/netns/generic.h>
44#include "core.h" 44#include "core.h"
45 45
46#define TIPC_ZONE_MASK 0xff000000u
47#define TIPC_CLUSTER_MASK 0xfffff000u
48
49static inline u32 tipc_own_addr(struct net *net) 46static inline u32 tipc_own_addr(struct net *net)
50{ 47{
51 struct tipc_net *tn = net_generic(net, tipc_net_id); 48 struct tipc_net *tn = net_generic(net, tipc_net_id);
@@ -60,7 +57,7 @@ static inline u32 tipc_zone_mask(u32 addr)
60 57
61static inline u32 tipc_cluster_mask(u32 addr) 58static inline u32 tipc_cluster_mask(u32 addr)
62{ 59{
63 return addr & TIPC_CLUSTER_MASK; 60 return addr & TIPC_ZONE_CLUSTER_MASK;
64} 61}
65 62
66u32 tipc_own_addr(struct net *net); 63u32 tipc_own_addr(struct net *net);
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 4131d5a86f55..65b1bbf133bd 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -171,6 +171,27 @@ struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name)
171 return NULL; 171 return NULL;
172} 172}
173 173
174/* tipc_bearer_get_name - get the bearer name from its id.
175 * @net: network namespace
176 * @name: a pointer to the buffer where the name will be stored.
177 * @bearer_id: the id to get the name from.
178 */
179int tipc_bearer_get_name(struct net *net, char *name, u32 bearer_id)
180{
181 struct tipc_net *tn = tipc_net(net);
182 struct tipc_bearer *b;
183
184 if (bearer_id >= MAX_BEARERS)
185 return -EINVAL;
186
187 b = rtnl_dereference(tn->bearer_list[bearer_id]);
188 if (!b)
189 return -EINVAL;
190
191 strcpy(name, b->name);
192 return 0;
193}
194
174void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest) 195void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest)
175{ 196{
176 struct tipc_net *tn = net_generic(net, tipc_net_id); 197 struct tipc_net *tn = net_generic(net, tipc_net_id);
@@ -225,7 +246,7 @@ static int tipc_enable_bearer(struct net *net, const char *name,
225 if (tipc_addr_domain_valid(disc_domain) && 246 if (tipc_addr_domain_valid(disc_domain) &&
226 (disc_domain != tn->own_addr)) { 247 (disc_domain != tn->own_addr)) {
227 if (tipc_in_scope(disc_domain, tn->own_addr)) { 248 if (tipc_in_scope(disc_domain, tn->own_addr)) {
228 disc_domain = tn->own_addr & TIPC_CLUSTER_MASK; 249 disc_domain = tn->own_addr & TIPC_ZONE_CLUSTER_MASK;
229 res = 0; /* accept any node in own cluster */ 250 res = 0; /* accept any node in own cluster */
230 } else if (in_own_cluster_exact(net, disc_domain)) 251 } else if (in_own_cluster_exact(net, disc_domain))
231 res = 0; /* accept specified node in own cluster */ 252 res = 0; /* accept specified node in own cluster */
@@ -832,7 +853,7 @@ int tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
832 u32 prio; 853 u32 prio;
833 854
834 prio = TIPC_MEDIA_LINK_PRI; 855 prio = TIPC_MEDIA_LINK_PRI;
835 domain = tn->own_addr & TIPC_CLUSTER_MASK; 856 domain = tn->own_addr & TIPC_ZONE_CLUSTER_MASK;
836 857
837 if (!info->attrs[TIPC_NLA_BEARER]) 858 if (!info->attrs[TIPC_NLA_BEARER])
838 return -EINVAL; 859 return -EINVAL;
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index f1e6db5e6345..43757f1f9cb3 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -197,6 +197,7 @@ int tipc_l2_send_msg(struct net *net, struct sk_buff *buf,
197void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest); 197void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest);
198void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest); 198void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest);
199struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name); 199struct tipc_bearer *tipc_bearer_find(struct net *net, const char *name);
200int tipc_bearer_get_name(struct net *net, char *name, u32 bearer_id);
200struct tipc_media *tipc_media_find(const char *name); 201struct tipc_media *tipc_media_find(const char *name);
201void tipc_bearer_reset_all(struct net *net); 202void tipc_bearer_reset_all(struct net *net);
202int tipc_bearer_setup(void); 203int tipc_bearer_setup(void);
diff --git a/net/tipc/monitor.c b/net/tipc/monitor.c
index 0d489e81fcca..be70a57c1ff9 100644
--- a/net/tipc/monitor.c
+++ b/net/tipc/monitor.c
@@ -33,9 +33,11 @@
33 * POSSIBILITY OF SUCH DAMAGE. 33 * POSSIBILITY OF SUCH DAMAGE.
34 */ 34 */
35 35
36#include <net/genetlink.h>
36#include "core.h" 37#include "core.h"
37#include "addr.h" 38#include "addr.h"
38#include "monitor.h" 39#include "monitor.h"
40#include "bearer.h"
39 41
40#define MAX_MON_DOMAIN 64 42#define MAX_MON_DOMAIN 64
41#define MON_TIMEOUT 120000 43#define MON_TIMEOUT 120000
@@ -649,3 +651,153 @@ void tipc_mon_delete(struct net *net, int bearer_id)
649 kfree(self); 651 kfree(self);
650 kfree(mon); 652 kfree(mon);
651} 653}
654
655int tipc_nl_monitor_set_threshold(struct net *net, u32 cluster_size)
656{
657 struct tipc_net *tn = tipc_net(net);
658
659 if (cluster_size > TIPC_CLUSTER_SIZE)
660 return -EINVAL;
661
662 tn->mon_threshold = cluster_size;
663
664 return 0;
665}
666
667int tipc_nl_monitor_get_threshold(struct net *net)
668{
669 struct tipc_net *tn = tipc_net(net);
670
671 return tn->mon_threshold;
672}
673
674int __tipc_nl_add_monitor_peer(struct tipc_peer *peer, struct tipc_nl_msg *msg)
675{
676 struct tipc_mon_domain *dom = peer->domain;
677 struct nlattr *attrs;
678 void *hdr;
679
680 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
681 NLM_F_MULTI, TIPC_NL_MON_PEER_GET);
682 if (!hdr)
683 return -EMSGSIZE;
684
685 attrs = nla_nest_start(msg->skb, TIPC_NLA_MON_PEER);
686 if (!attrs)
687 goto msg_full;
688
689 if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_ADDR, peer->addr))
690 goto attr_msg_full;
691 if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_APPLIED, peer->applied))
692 goto attr_msg_full;
693
694 if (peer->is_up)
695 if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_UP))
696 goto attr_msg_full;
697 if (peer->is_local)
698 if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_LOCAL))
699 goto attr_msg_full;
700 if (peer->is_head)
701 if (nla_put_flag(msg->skb, TIPC_NLA_MON_PEER_HEAD))
702 goto attr_msg_full;
703
704 if (dom) {
705 if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEER_DOMGEN, dom->gen))
706 goto attr_msg_full;
707 if (nla_put_u64_64bit(msg->skb, TIPC_NLA_MON_PEER_UPMAP,
708 dom->up_map, TIPC_NLA_MON_PEER_PAD))
709 goto attr_msg_full;
710 if (nla_put(msg->skb, TIPC_NLA_MON_PEER_MEMBERS,
711 dom->member_cnt * sizeof(u32), &dom->members))
712 goto attr_msg_full;
713 }
714
715 nla_nest_end(msg->skb, attrs);
716 genlmsg_end(msg->skb, hdr);
717 return 0;
718
719attr_msg_full:
720 nla_nest_cancel(msg->skb, attrs);
721msg_full:
722 genlmsg_cancel(msg->skb, hdr);
723
724 return -EMSGSIZE;
725}
726
727int tipc_nl_add_monitor_peer(struct net *net, struct tipc_nl_msg *msg,
728 u32 bearer_id, u32 *prev_node)
729{
730 struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
731 struct tipc_peer *peer = mon->self;
732
733 if (!mon)
734 return -EINVAL;
735
736 read_lock_bh(&mon->lock);
737 do {
738 if (*prev_node) {
739 if (peer->addr == *prev_node)
740 *prev_node = 0;
741 else
742 continue;
743 }
744 if (__tipc_nl_add_monitor_peer(peer, msg)) {
745 *prev_node = peer->addr;
746 read_unlock_bh(&mon->lock);
747 return -EMSGSIZE;
748 }
749 } while ((peer = peer_nxt(peer)) != mon->self);
750 read_unlock_bh(&mon->lock);
751
752 return 0;
753}
754
755int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg,
756 u32 bearer_id)
757{
758 struct tipc_monitor *mon = tipc_monitor(net, bearer_id);
759 char bearer_name[TIPC_MAX_BEARER_NAME];
760 struct nlattr *attrs;
761 void *hdr;
762 int ret;
763
764 ret = tipc_bearer_get_name(net, bearer_name, bearer_id);
765 if (ret || !mon)
766 return -EINVAL;
767
768 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
769 NLM_F_MULTI, TIPC_NL_MON_GET);
770 if (!hdr)
771 return -EMSGSIZE;
772
773 attrs = nla_nest_start(msg->skb, TIPC_NLA_MON);
774 if (!attrs)
775 goto msg_full;
776
777 read_lock_bh(&mon->lock);
778 if (nla_put_u32(msg->skb, TIPC_NLA_MON_REF, bearer_id))
779 goto attr_msg_full;
780 if (tipc_mon_is_active(net, mon))
781 if (nla_put_flag(msg->skb, TIPC_NLA_MON_ACTIVE))
782 goto attr_msg_full;
783 if (nla_put_string(msg->skb, TIPC_NLA_MON_BEARER_NAME, bearer_name))
784 goto attr_msg_full;
785 if (nla_put_u32(msg->skb, TIPC_NLA_MON_PEERCNT, mon->peer_cnt))
786 goto attr_msg_full;
787 if (nla_put_u32(msg->skb, TIPC_NLA_MON_LISTGEN, mon->list_gen))
788 goto attr_msg_full;
789
790 read_unlock_bh(&mon->lock);
791 nla_nest_end(msg->skb, attrs);
792 genlmsg_end(msg->skb, hdr);
793
794 return 0;
795
796attr_msg_full:
797 nla_nest_cancel(msg->skb, attrs);
798msg_full:
799 genlmsg_cancel(msg->skb, hdr);
800 read_unlock_bh(&mon->lock);
801
802 return -EMSGSIZE;
803}
diff --git a/net/tipc/monitor.h b/net/tipc/monitor.h
index 598459cbed5d..2a21b93e0d04 100644
--- a/net/tipc/monitor.h
+++ b/net/tipc/monitor.h
@@ -36,6 +36,8 @@
36#ifndef _TIPC_MONITOR_H 36#ifndef _TIPC_MONITOR_H
37#define _TIPC_MONITOR_H 37#define _TIPC_MONITOR_H
38 38
39#include "netlink.h"
40
39/* struct tipc_mon_state: link instance's cache of monitor list and domain state 41/* struct tipc_mon_state: link instance's cache of monitor list and domain state
40 * @list_gen: current generation of this node's monitor list 42 * @list_gen: current generation of this node's monitor list
41 * @gen: current generation of this node's local domain 43 * @gen: current generation of this node's local domain
@@ -69,5 +71,12 @@ void tipc_mon_get_state(struct net *net, u32 addr,
69 int bearer_id); 71 int bearer_id);
70void tipc_mon_remove_peer(struct net *net, u32 addr, int bearer_id); 72void tipc_mon_remove_peer(struct net *net, u32 addr, int bearer_id);
71 73
74int tipc_nl_monitor_set_threshold(struct net *net, u32 cluster_size);
75int tipc_nl_monitor_get_threshold(struct net *net);
76int __tipc_nl_add_monitor(struct net *net, struct tipc_nl_msg *msg,
77 u32 bearer_id);
78int tipc_nl_add_monitor_peer(struct net *net, struct tipc_nl_msg *msg,
79 u32 bearer_id, u32 *prev_node);
80
72extern const int tipc_max_domain_size; 81extern const int tipc_max_domain_size;
73#endif 82#endif
diff --git a/net/tipc/netlink.c b/net/tipc/netlink.c
index 56935df2167a..a84daec0afe9 100644
--- a/net/tipc/netlink.c
+++ b/net/tipc/netlink.c
@@ -52,7 +52,8 @@ static const struct nla_policy tipc_nl_policy[TIPC_NLA_MAX + 1] = {
52 [TIPC_NLA_MEDIA] = { .type = NLA_NESTED, }, 52 [TIPC_NLA_MEDIA] = { .type = NLA_NESTED, },
53 [TIPC_NLA_NODE] = { .type = NLA_NESTED, }, 53 [TIPC_NLA_NODE] = { .type = NLA_NESTED, },
54 [TIPC_NLA_NET] = { .type = NLA_NESTED, }, 54 [TIPC_NLA_NET] = { .type = NLA_NESTED, },
55 [TIPC_NLA_NAME_TABLE] = { .type = NLA_NESTED, } 55 [TIPC_NLA_NAME_TABLE] = { .type = NLA_NESTED, },
56 [TIPC_NLA_MON] = { .type = NLA_NESTED, },
56}; 57};
57 58
58const struct nla_policy 59const struct nla_policy
@@ -61,6 +62,12 @@ tipc_nl_name_table_policy[TIPC_NLA_NAME_TABLE_MAX + 1] = {
61 [TIPC_NLA_NAME_TABLE_PUBL] = { .type = NLA_NESTED } 62 [TIPC_NLA_NAME_TABLE_PUBL] = { .type = NLA_NESTED }
62}; 63};
63 64
65const struct nla_policy tipc_nl_monitor_policy[TIPC_NLA_MON_MAX + 1] = {
66 [TIPC_NLA_MON_UNSPEC] = { .type = NLA_UNSPEC },
67 [TIPC_NLA_MON_REF] = { .type = NLA_U32 },
68 [TIPC_NLA_MON_ACTIVATION_THRESHOLD] = { .type = NLA_U32 },
69};
70
64const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = { 71const struct nla_policy tipc_nl_sock_policy[TIPC_NLA_SOCK_MAX + 1] = {
65 [TIPC_NLA_SOCK_UNSPEC] = { .type = NLA_UNSPEC }, 72 [TIPC_NLA_SOCK_UNSPEC] = { .type = NLA_UNSPEC },
66 [TIPC_NLA_SOCK_ADDR] = { .type = NLA_U32 }, 73 [TIPC_NLA_SOCK_ADDR] = { .type = NLA_U32 },
@@ -214,7 +221,23 @@ static const struct genl_ops tipc_genl_v2_ops[] = {
214 .cmd = TIPC_NL_NAME_TABLE_GET, 221 .cmd = TIPC_NL_NAME_TABLE_GET,
215 .dumpit = tipc_nl_name_table_dump, 222 .dumpit = tipc_nl_name_table_dump,
216 .policy = tipc_nl_policy, 223 .policy = tipc_nl_policy,
217 } 224 },
225 {
226 .cmd = TIPC_NL_MON_SET,
227 .doit = tipc_nl_node_set_monitor,
228 .policy = tipc_nl_policy,
229 },
230 {
231 .cmd = TIPC_NL_MON_GET,
232 .doit = tipc_nl_node_get_monitor,
233 .dumpit = tipc_nl_node_dump_monitor,
234 .policy = tipc_nl_policy,
235 },
236 {
237 .cmd = TIPC_NL_MON_PEER_GET,
238 .dumpit = tipc_nl_node_dump_monitor_peer,
239 .policy = tipc_nl_policy,
240 },
218}; 241};
219 242
220int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr) 243int tipc_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr ***attr)
diff --git a/net/tipc/netlink.h b/net/tipc/netlink.h
index ed1dbcb4afbd..4ba0ad422110 100644
--- a/net/tipc/netlink.h
+++ b/net/tipc/netlink.h
@@ -55,6 +55,7 @@ extern const struct nla_policy tipc_nl_prop_policy[];
55extern const struct nla_policy tipc_nl_bearer_policy[]; 55extern const struct nla_policy tipc_nl_bearer_policy[];
56extern const struct nla_policy tipc_nl_media_policy[]; 56extern const struct nla_policy tipc_nl_media_policy[];
57extern const struct nla_policy tipc_nl_udp_policy[]; 57extern const struct nla_policy tipc_nl_udp_policy[];
58extern const struct nla_policy tipc_nl_monitor_policy[];
58 59
59int tipc_netlink_start(void); 60int tipc_netlink_start(void);
60int tipc_netlink_compat_start(void); 61int tipc_netlink_compat_start(void);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 95cc78b51532..21974191e425 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -1928,3 +1928,168 @@ out:
1928 1928
1929 return skb->len; 1929 return skb->len;
1930} 1930}
1931
1932int tipc_nl_node_set_monitor(struct sk_buff *skb, struct genl_info *info)
1933{
1934 struct nlattr *attrs[TIPC_NLA_MON_MAX + 1];
1935 struct net *net = sock_net(skb->sk);
1936 int err;
1937
1938 if (!info->attrs[TIPC_NLA_MON])
1939 return -EINVAL;
1940
1941 err = nla_parse_nested(attrs, TIPC_NLA_MON_MAX,
1942 info->attrs[TIPC_NLA_MON],
1943 tipc_nl_monitor_policy);
1944 if (err)
1945 return err;
1946
1947 if (attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD]) {
1948 u32 val;
1949
1950 val = nla_get_u32(attrs[TIPC_NLA_MON_ACTIVATION_THRESHOLD]);
1951 err = tipc_nl_monitor_set_threshold(net, val);
1952 if (err)
1953 return err;
1954 }
1955
1956 return 0;
1957}
1958
1959static int __tipc_nl_add_monitor_prop(struct net *net, struct tipc_nl_msg *msg)
1960{
1961 struct nlattr *attrs;
1962 void *hdr;
1963 u32 val;
1964
1965 hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family,
1966 0, TIPC_NL_MON_GET);
1967 if (!hdr)
1968 return -EMSGSIZE;
1969
1970 attrs = nla_nest_start(msg->skb, TIPC_NLA_MON);
1971 if (!attrs)
1972 goto msg_full;
1973
1974 val = tipc_nl_monitor_get_threshold(net);
1975
1976 if (nla_put_u32(msg->skb, TIPC_NLA_MON_ACTIVATION_THRESHOLD, val))
1977 goto attr_msg_full;
1978
1979 nla_nest_end(msg->skb, attrs);
1980 genlmsg_end(msg->skb, hdr);
1981
1982 return 0;
1983
1984attr_msg_full:
1985 nla_nest_cancel(msg->skb, attrs);
1986msg_full:
1987 genlmsg_cancel(msg->skb, hdr);
1988
1989 return -EMSGSIZE;
1990}
1991
1992int tipc_nl_node_get_monitor(struct sk_buff *skb, struct genl_info *info)
1993{
1994 struct net *net = sock_net(skb->sk);
1995 struct tipc_nl_msg msg;
1996 int err;
1997
1998 msg.skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1999 msg.portid = info->snd_portid;
2000 msg.seq = info->snd_seq;
2001
2002 err = __tipc_nl_add_monitor_prop(net, &msg);
2003 if (err) {
2004 nlmsg_free(msg.skb);
2005 return err;
2006 }
2007
2008 return genlmsg_reply(msg.skb, info);
2009}
2010
2011int tipc_nl_node_dump_monitor(struct sk_buff *skb, struct netlink_callback *cb)
2012{
2013 struct net *net = sock_net(skb->sk);
2014 u32 prev_bearer = cb->args[0];
2015 struct tipc_nl_msg msg;
2016 int err;
2017 int i;
2018
2019 if (prev_bearer == MAX_BEARERS)
2020 return 0;
2021
2022 msg.skb = skb;
2023 msg.portid = NETLINK_CB(cb->skb).portid;
2024 msg.seq = cb->nlh->nlmsg_seq;
2025
2026 rtnl_lock();
2027 for (i = prev_bearer; i < MAX_BEARERS; i++) {
2028 prev_bearer = i;
2029 err = __tipc_nl_add_monitor(net, &msg, prev_bearer);
2030 if (err)
2031 goto out;
2032 }
2033
2034out:
2035 rtnl_unlock();
2036 cb->args[0] = prev_bearer;
2037
2038 return skb->len;
2039}
2040
2041int tipc_nl_node_dump_monitor_peer(struct sk_buff *skb,
2042 struct netlink_callback *cb)
2043{
2044 struct net *net = sock_net(skb->sk);
2045 u32 prev_node = cb->args[1];
2046 u32 bearer_id = cb->args[2];
2047 int done = cb->args[0];
2048 struct tipc_nl_msg msg;
2049 int err;
2050
2051 if (!prev_node) {
2052 struct nlattr **attrs;
2053 struct nlattr *mon[TIPC_NLA_MON_MAX + 1];
2054
2055 err = tipc_nlmsg_parse(cb->nlh, &attrs);
2056 if (err)
2057 return err;
2058
2059 if (!attrs[TIPC_NLA_MON])
2060 return -EINVAL;
2061
2062 err = nla_parse_nested(mon, TIPC_NLA_MON_MAX,
2063 attrs[TIPC_NLA_MON],
2064 tipc_nl_monitor_policy);
2065 if (err)
2066 return err;
2067
2068 if (!mon[TIPC_NLA_MON_REF])
2069 return -EINVAL;
2070
2071 bearer_id = nla_get_u32(mon[TIPC_NLA_MON_REF]);
2072
2073 if (bearer_id >= MAX_BEARERS)
2074 return -EINVAL;
2075 }
2076
2077 if (done)
2078 return 0;
2079
2080 msg.skb = skb;
2081 msg.portid = NETLINK_CB(cb->skb).portid;
2082 msg.seq = cb->nlh->nlmsg_seq;
2083
2084 rtnl_lock();
2085 err = tipc_nl_add_monitor_peer(net, &msg, bearer_id, &prev_node);
2086 if (!err)
2087 done = 1;
2088
2089 rtnl_unlock();
2090 cb->args[0] = done;
2091 cb->args[1] = prev_node;
2092 cb->args[2] = bearer_id;
2093
2094 return skb->len;
2095}
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 8264b3d97dc4..d69fdfcc0ec9 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -78,4 +78,9 @@ int tipc_nl_node_reset_link_stats(struct sk_buff *skb, struct genl_info *info);
78int tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info); 78int tipc_nl_node_get_link(struct sk_buff *skb, struct genl_info *info);
79int tipc_nl_node_set_link(struct sk_buff *skb, struct genl_info *info); 79int tipc_nl_node_set_link(struct sk_buff *skb, struct genl_info *info);
80 80
81int tipc_nl_node_set_monitor(struct sk_buff *skb, struct genl_info *info);
82int tipc_nl_node_get_monitor(struct sk_buff *skb, struct genl_info *info);
83int tipc_nl_node_dump_monitor(struct sk_buff *skb, struct netlink_callback *cb);
84int tipc_nl_node_dump_monitor_peer(struct sk_buff *skb,
85 struct netlink_callback *cb);
81#endif 86#endif