diff options
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r-- | net/tipc/link.c | 628 |
1 files changed, 316 insertions, 312 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index 9efbdbde2b08..0c2944fb9ae0 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -45,28 +45,156 @@ | |||
45 | 45 | ||
46 | #include <linux/pkt_sched.h> | 46 | #include <linux/pkt_sched.h> |
47 | 47 | ||
48 | struct tipc_stats { | ||
49 | u32 sent_info; /* used in counting # sent packets */ | ||
50 | u32 recv_info; /* used in counting # recv'd packets */ | ||
51 | u32 sent_states; | ||
52 | u32 recv_states; | ||
53 | u32 sent_probes; | ||
54 | u32 recv_probes; | ||
55 | u32 sent_nacks; | ||
56 | u32 recv_nacks; | ||
57 | u32 sent_acks; | ||
58 | u32 sent_bundled; | ||
59 | u32 sent_bundles; | ||
60 | u32 recv_bundled; | ||
61 | u32 recv_bundles; | ||
62 | u32 retransmitted; | ||
63 | u32 sent_fragmented; | ||
64 | u32 sent_fragments; | ||
65 | u32 recv_fragmented; | ||
66 | u32 recv_fragments; | ||
67 | u32 link_congs; /* # port sends blocked by congestion */ | ||
68 | u32 deferred_recv; | ||
69 | u32 duplicates; | ||
70 | u32 max_queue_sz; /* send queue size high water mark */ | ||
71 | u32 accu_queue_sz; /* used for send queue size profiling */ | ||
72 | u32 queue_sz_counts; /* used for send queue size profiling */ | ||
73 | u32 msg_length_counts; /* used for message length profiling */ | ||
74 | u32 msg_lengths_total; /* used for message length profiling */ | ||
75 | u32 msg_length_profile[7]; /* used for msg. length profiling */ | ||
76 | }; | ||
77 | |||
78 | /** | ||
79 | * struct tipc_link - TIPC link data structure | ||
80 | * @addr: network address of link's peer node | ||
81 | * @name: link name character string | ||
82 | * @media_addr: media address to use when sending messages over link | ||
83 | * @timer: link timer | ||
84 | * @net: pointer to namespace struct | ||
85 | * @refcnt: reference counter for permanent references (owner node & timer) | ||
86 | * @peer_session: link session # being used by peer end of link | ||
87 | * @peer_bearer_id: bearer id used by link's peer endpoint | ||
88 | * @bearer_id: local bearer id used by link | ||
89 | * @tolerance: minimum link continuity loss needed to reset link [in ms] | ||
90 | * @keepalive_intv: link keepalive timer interval | ||
91 | * @abort_limit: # of unacknowledged continuity probes needed to reset link | ||
92 | * @state: current state of link FSM | ||
93 | * @peer_caps: bitmap describing capabilities of peer node | ||
94 | * @silent_intv_cnt: # of timer intervals without any reception from peer | ||
95 | * @proto_msg: template for control messages generated by link | ||
96 | * @pmsg: convenience pointer to "proto_msg" field | ||
97 | * @priority: current link priority | ||
98 | * @net_plane: current link network plane ('A' through 'H') | ||
99 | * @backlog_limit: backlog queue congestion thresholds (indexed by importance) | ||
100 | * @exp_msg_count: # of tunnelled messages expected during link changeover | ||
101 | * @reset_rcv_checkpt: seq # of last acknowledged message at time of link reset | ||
102 | * @mtu: current maximum packet size for this link | ||
103 | * @advertised_mtu: advertised own mtu when link is being established | ||
104 | * @transmitq: queue for sent, non-acked messages | ||
105 | * @backlogq: queue for messages waiting to be sent | ||
106 | * @snt_nxt: next sequence number to use for outbound messages | ||
107 | * @last_retransmitted: sequence number of most recently retransmitted message | ||
108 | * @stale_count: # of identical retransmit requests made by peer | ||
109 | * @ackers: # of peers that needs to ack each packet before it can be released | ||
110 | * @acked: # last packet acked by a certain peer. Used for broadcast. | ||
111 | * @rcv_nxt: next sequence number to expect for inbound messages | ||
112 | * @deferred_queue: deferred queue saved OOS b'cast message received from node | ||
113 | * @unacked_window: # of inbound messages rx'd without ack'ing back to peer | ||
114 | * @inputq: buffer queue for messages to be delivered upwards | ||
115 | * @namedq: buffer queue for name table messages to be delivered upwards | ||
116 | * @next_out: ptr to first unsent outbound message in queue | ||
117 | * @wakeupq: linked list of wakeup msgs waiting for link congestion to abate | ||
118 | * @long_msg_seq_no: next identifier to use for outbound fragmented messages | ||
119 | * @reasm_buf: head of partially reassembled inbound message fragments | ||
120 | * @bc_rcvr: marks that this is a broadcast receiver link | ||
121 | * @stats: collects statistics regarding link activity | ||
122 | */ | ||
123 | struct tipc_link { | ||
124 | u32 addr; | ||
125 | char name[TIPC_MAX_LINK_NAME]; | ||
126 | struct tipc_media_addr *media_addr; | ||
127 | struct net *net; | ||
128 | |||
129 | /* Management and link supervision data */ | ||
130 | u32 peer_session; | ||
131 | u32 peer_bearer_id; | ||
132 | u32 bearer_id; | ||
133 | u32 tolerance; | ||
134 | unsigned long keepalive_intv; | ||
135 | u32 abort_limit; | ||
136 | u32 state; | ||
137 | u16 peer_caps; | ||
138 | bool active; | ||
139 | u32 silent_intv_cnt; | ||
140 | struct { | ||
141 | unchar hdr[INT_H_SIZE]; | ||
142 | unchar body[TIPC_MAX_IF_NAME]; | ||
143 | } proto_msg; | ||
144 | struct tipc_msg *pmsg; | ||
145 | u32 priority; | ||
146 | char net_plane; | ||
147 | |||
148 | /* Failover/synch */ | ||
149 | u16 drop_point; | ||
150 | struct sk_buff *failover_reasm_skb; | ||
151 | |||
152 | /* Max packet negotiation */ | ||
153 | u16 mtu; | ||
154 | u16 advertised_mtu; | ||
155 | |||
156 | /* Sending */ | ||
157 | struct sk_buff_head transmq; | ||
158 | struct sk_buff_head backlogq; | ||
159 | struct { | ||
160 | u16 len; | ||
161 | u16 limit; | ||
162 | } backlog[5]; | ||
163 | u16 snd_nxt; | ||
164 | u16 last_retransm; | ||
165 | u16 window; | ||
166 | u32 stale_count; | ||
167 | |||
168 | /* Reception */ | ||
169 | u16 rcv_nxt; | ||
170 | u32 rcv_unacked; | ||
171 | struct sk_buff_head deferdq; | ||
172 | struct sk_buff_head *inputq; | ||
173 | struct sk_buff_head *namedq; | ||
174 | |||
175 | /* Congestion handling */ | ||
176 | struct sk_buff_head wakeupq; | ||
177 | |||
178 | /* Fragmentation/reassembly */ | ||
179 | struct sk_buff *reasm_buf; | ||
180 | |||
181 | /* Broadcast */ | ||
182 | u16 ackers; | ||
183 | u16 acked; | ||
184 | struct tipc_link *bc_rcvlink; | ||
185 | struct tipc_link *bc_sndlink; | ||
186 | int nack_state; | ||
187 | bool bc_peer_is_up; | ||
188 | |||
189 | /* Statistics */ | ||
190 | struct tipc_stats stats; | ||
191 | }; | ||
192 | |||
48 | /* | 193 | /* |
49 | * Error message prefixes | 194 | * Error message prefixes |
50 | */ | 195 | */ |
51 | static const char *link_co_err = "Link tunneling error, "; | 196 | static const char *link_co_err = "Link tunneling error, "; |
52 | static const char *link_rst_msg = "Resetting link "; | 197 | static const char *link_rst_msg = "Resetting link "; |
53 | static const char tipc_bclink_name[] = "broadcast-link"; | ||
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 | 198 | ||
71 | /* Properties valid for media, bearar and link */ | 199 | /* Properties valid for media, bearar and link */ |
72 | static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { | 200 | static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { |
@@ -117,8 +245,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, | |||
117 | static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, | 245 | static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, |
118 | u16 rcvgap, int tolerance, int priority, | 246 | u16 rcvgap, int tolerance, int priority, |
119 | struct sk_buff_head *xmitq); | 247 | struct sk_buff_head *xmitq); |
120 | static void link_reset_statistics(struct tipc_link *l_ptr); | 248 | static void link_print(struct tipc_link *l, const char *str); |
121 | static void link_print(struct tipc_link *l_ptr, const char *str); | ||
122 | static void tipc_link_build_nack_msg(struct tipc_link *l, | 249 | static void tipc_link_build_nack_msg(struct tipc_link *l, |
123 | struct sk_buff_head *xmitq); | 250 | struct sk_buff_head *xmitq); |
124 | static void tipc_link_build_bc_init_msg(struct tipc_link *l, | 251 | static void tipc_link_build_bc_init_msg(struct tipc_link *l, |
@@ -183,6 +310,36 @@ void tipc_link_set_active(struct tipc_link *l, bool active) | |||
183 | l->active = active; | 310 | l->active = active; |
184 | } | 311 | } |
185 | 312 | ||
313 | u32 tipc_link_id(struct tipc_link *l) | ||
314 | { | ||
315 | return l->peer_bearer_id << 16 | l->bearer_id; | ||
316 | } | ||
317 | |||
318 | int tipc_link_window(struct tipc_link *l) | ||
319 | { | ||
320 | return l->window; | ||
321 | } | ||
322 | |||
323 | int tipc_link_prio(struct tipc_link *l) | ||
324 | { | ||
325 | return l->priority; | ||
326 | } | ||
327 | |||
328 | unsigned long tipc_link_tolerance(struct tipc_link *l) | ||
329 | { | ||
330 | return l->tolerance; | ||
331 | } | ||
332 | |||
333 | struct sk_buff_head *tipc_link_inputq(struct tipc_link *l) | ||
334 | { | ||
335 | return l->inputq; | ||
336 | } | ||
337 | |||
338 | char tipc_link_plane(struct tipc_link *l) | ||
339 | { | ||
340 | return l->net_plane; | ||
341 | } | ||
342 | |||
186 | void tipc_link_add_bc_peer(struct tipc_link *snd_l, | 343 | void tipc_link_add_bc_peer(struct tipc_link *snd_l, |
187 | struct tipc_link *uc_l, | 344 | struct tipc_link *uc_l, |
188 | struct sk_buff_head *xmitq) | 345 | struct sk_buff_head *xmitq) |
@@ -191,6 +348,7 @@ void tipc_link_add_bc_peer(struct tipc_link *snd_l, | |||
191 | 348 | ||
192 | snd_l->ackers++; | 349 | snd_l->ackers++; |
193 | rcv_l->acked = snd_l->snd_nxt - 1; | 350 | rcv_l->acked = snd_l->snd_nxt - 1; |
351 | snd_l->state = LINK_ESTABLISHED; | ||
194 | tipc_link_build_bc_init_msg(uc_l, xmitq); | 352 | tipc_link_build_bc_init_msg(uc_l, xmitq); |
195 | } | 353 | } |
196 | 354 | ||
@@ -206,6 +364,7 @@ void tipc_link_remove_bc_peer(struct tipc_link *snd_l, | |||
206 | rcv_l->state = LINK_RESET; | 364 | rcv_l->state = LINK_RESET; |
207 | if (!snd_l->ackers) { | 365 | if (!snd_l->ackers) { |
208 | tipc_link_reset(snd_l); | 366 | tipc_link_reset(snd_l); |
367 | snd_l->state = LINK_RESET; | ||
209 | __skb_queue_purge(xmitq); | 368 | __skb_queue_purge(xmitq); |
210 | } | 369 | } |
211 | } | 370 | } |
@@ -225,11 +384,31 @@ int tipc_link_mtu(struct tipc_link *l) | |||
225 | return l->mtu; | 384 | return l->mtu; |
226 | } | 385 | } |
227 | 386 | ||
387 | u16 tipc_link_rcv_nxt(struct tipc_link *l) | ||
388 | { | ||
389 | return l->rcv_nxt; | ||
390 | } | ||
391 | |||
392 | u16 tipc_link_acked(struct tipc_link *l) | ||
393 | { | ||
394 | return l->acked; | ||
395 | } | ||
396 | |||
397 | char *tipc_link_name(struct tipc_link *l) | ||
398 | { | ||
399 | return l->name; | ||
400 | } | ||
401 | |||
228 | static u32 link_own_addr(struct tipc_link *l) | 402 | static u32 link_own_addr(struct tipc_link *l) |
229 | { | 403 | { |
230 | return msg_prevnode(l->pmsg); | 404 | return msg_prevnode(l->pmsg); |
231 | } | 405 | } |
232 | 406 | ||
407 | void tipc_link_reinit(struct tipc_link *l, u32 addr) | ||
408 | { | ||
409 | msg_set_prevnode(l->pmsg, addr); | ||
410 | } | ||
411 | |||
233 | /** | 412 | /** |
234 | * tipc_link_create - create a new link | 413 | * tipc_link_create - create a new link |
235 | * @n: pointer to associated node | 414 | * @n: pointer to associated node |
@@ -692,7 +871,7 @@ void tipc_link_reset(struct tipc_link *l) | |||
692 | l->stats.recv_info = 0; | 871 | l->stats.recv_info = 0; |
693 | l->stale_count = 0; | 872 | l->stale_count = 0; |
694 | l->bc_peer_is_up = false; | 873 | l->bc_peer_is_up = false; |
695 | link_reset_statistics(l); | 874 | tipc_link_reset_stats(l); |
696 | } | 875 | } |
697 | 876 | ||
698 | /** | 877 | /** |
@@ -1085,8 +1264,9 @@ drop: | |||
1085 | /* | 1264 | /* |
1086 | * Send protocol message to the other endpoint. | 1265 | * Send protocol message to the other endpoint. |
1087 | */ | 1266 | */ |
1088 | void tipc_link_proto_xmit(struct tipc_link *l, u32 msg_typ, int probe_msg, | 1267 | static void tipc_link_proto_xmit(struct tipc_link *l, u32 msg_typ, |
1089 | u32 gap, u32 tolerance, u32 priority) | 1268 | int probe_msg, u32 gap, u32 tolerance, |
1269 | u32 priority) | ||
1090 | { | 1270 | { |
1091 | struct sk_buff *skb = NULL; | 1271 | struct sk_buff *skb = NULL; |
1092 | struct sk_buff_head xmitq; | 1272 | struct sk_buff_head xmitq; |
@@ -1260,6 +1440,8 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, | |||
1260 | /* fall thru' */ | 1440 | /* fall thru' */ |
1261 | 1441 | ||
1262 | case ACTIVATE_MSG: | 1442 | case ACTIVATE_MSG: |
1443 | skb_linearize(skb); | ||
1444 | hdr = buf_msg(skb); | ||
1263 | 1445 | ||
1264 | /* Complete own link name with peer's interface name */ | 1446 | /* Complete own link name with peer's interface name */ |
1265 | if_name = strrchr(l->name, ':') + 1; | 1447 | if_name = strrchr(l->name, ':') + 1; |
@@ -1525,53 +1707,17 @@ void tipc_link_set_queue_limits(struct tipc_link *l, u32 win) | |||
1525 | l->backlog[TIPC_SYSTEM_IMPORTANCE].limit = max_bulk; | 1707 | l->backlog[TIPC_SYSTEM_IMPORTANCE].limit = max_bulk; |
1526 | } | 1708 | } |
1527 | 1709 | ||
1528 | /* tipc_link_find_owner - locate owner node of link by link's name | ||
1529 | * @net: the applicable net namespace | ||
1530 | * @name: pointer to link name string | ||
1531 | * @bearer_id: pointer to index in 'node->links' array where the link was found. | ||
1532 | * | ||
1533 | * Returns pointer to node owning the link, or 0 if no matching link is found. | ||
1534 | */ | ||
1535 | static struct tipc_node *tipc_link_find_owner(struct net *net, | ||
1536 | const char *link_name, | ||
1537 | unsigned int *bearer_id) | ||
1538 | { | ||
1539 | struct tipc_net *tn = net_generic(net, tipc_net_id); | ||
1540 | struct tipc_link *l_ptr; | ||
1541 | struct tipc_node *n_ptr; | ||
1542 | struct tipc_node *found_node = NULL; | ||
1543 | int i; | ||
1544 | |||
1545 | *bearer_id = 0; | ||
1546 | rcu_read_lock(); | ||
1547 | list_for_each_entry_rcu(n_ptr, &tn->node_list, list) { | ||
1548 | tipc_node_lock(n_ptr); | ||
1549 | for (i = 0; i < MAX_BEARERS; i++) { | ||
1550 | l_ptr = n_ptr->links[i].link; | ||
1551 | if (l_ptr && !strcmp(l_ptr->name, link_name)) { | ||
1552 | *bearer_id = i; | ||
1553 | found_node = n_ptr; | ||
1554 | break; | ||
1555 | } | ||
1556 | } | ||
1557 | tipc_node_unlock(n_ptr); | ||
1558 | if (found_node) | ||
1559 | break; | ||
1560 | } | ||
1561 | rcu_read_unlock(); | ||
1562 | |||
1563 | return found_node; | ||
1564 | } | ||
1565 | |||
1566 | /** | 1710 | /** |
1567 | * link_reset_statistics - reset link statistics | 1711 | * link_reset_stats - reset link statistics |
1568 | * @l_ptr: pointer to link | 1712 | * @l: pointer to link |
1569 | */ | 1713 | */ |
1570 | static void link_reset_statistics(struct tipc_link *l_ptr) | 1714 | void tipc_link_reset_stats(struct tipc_link *l) |
1571 | { | 1715 | { |
1572 | memset(&l_ptr->stats, 0, sizeof(l_ptr->stats)); | 1716 | memset(&l->stats, 0, sizeof(l->stats)); |
1573 | l_ptr->stats.sent_info = l_ptr->snd_nxt; | 1717 | if (!link_is_bc_sndlink(l)) { |
1574 | l_ptr->stats.recv_info = l_ptr->rcv_nxt; | 1718 | l->stats.sent_info = l->snd_nxt; |
1719 | l->stats.recv_info = l->rcv_nxt; | ||
1720 | } | ||
1575 | } | 1721 | } |
1576 | 1722 | ||
1577 | static void link_print(struct tipc_link *l, const char *str) | 1723 | static void link_print(struct tipc_link *l, const char *str) |
@@ -1624,84 +1770,6 @@ int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]) | |||
1624 | return 0; | 1770 | return 0; |
1625 | } | 1771 | } |
1626 | 1772 | ||
1627 | int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info) | ||
1628 | { | ||
1629 | int err; | ||
1630 | int res = 0; | ||
1631 | int bearer_id; | ||
1632 | char *name; | ||
1633 | struct tipc_link *link; | ||
1634 | struct tipc_node *node; | ||
1635 | struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; | ||
1636 | struct net *net = sock_net(skb->sk); | ||
1637 | |||
1638 | if (!info->attrs[TIPC_NLA_LINK]) | ||
1639 | return -EINVAL; | ||
1640 | |||
1641 | err = nla_parse_nested(attrs, TIPC_NLA_LINK_MAX, | ||
1642 | info->attrs[TIPC_NLA_LINK], | ||
1643 | tipc_nl_link_policy); | ||
1644 | if (err) | ||
1645 | return err; | ||
1646 | |||
1647 | if (!attrs[TIPC_NLA_LINK_NAME]) | ||
1648 | return -EINVAL; | ||
1649 | |||
1650 | name = nla_data(attrs[TIPC_NLA_LINK_NAME]); | ||
1651 | |||
1652 | if (strcmp(name, tipc_bclink_name) == 0) | ||
1653 | return tipc_nl_bc_link_set(net, attrs); | ||
1654 | |||
1655 | node = tipc_link_find_owner(net, name, &bearer_id); | ||
1656 | if (!node) | ||
1657 | return -EINVAL; | ||
1658 | |||
1659 | tipc_node_lock(node); | ||
1660 | |||
1661 | link = node->links[bearer_id].link; | ||
1662 | if (!link) { | ||
1663 | res = -EINVAL; | ||
1664 | goto out; | ||
1665 | } | ||
1666 | |||
1667 | if (attrs[TIPC_NLA_LINK_PROP]) { | ||
1668 | struct nlattr *props[TIPC_NLA_PROP_MAX + 1]; | ||
1669 | |||
1670 | err = tipc_nl_parse_link_prop(attrs[TIPC_NLA_LINK_PROP], | ||
1671 | props); | ||
1672 | if (err) { | ||
1673 | res = err; | ||
1674 | goto out; | ||
1675 | } | ||
1676 | |||
1677 | if (props[TIPC_NLA_PROP_TOL]) { | ||
1678 | u32 tol; | ||
1679 | |||
1680 | tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]); | ||
1681 | link->tolerance = tol; | ||
1682 | tipc_link_proto_xmit(link, STATE_MSG, 0, 0, tol, 0); | ||
1683 | } | ||
1684 | if (props[TIPC_NLA_PROP_PRIO]) { | ||
1685 | u32 prio; | ||
1686 | |||
1687 | prio = nla_get_u32(props[TIPC_NLA_PROP_PRIO]); | ||
1688 | link->priority = prio; | ||
1689 | tipc_link_proto_xmit(link, STATE_MSG, 0, 0, 0, prio); | ||
1690 | } | ||
1691 | if (props[TIPC_NLA_PROP_WIN]) { | ||
1692 | u32 win; | ||
1693 | |||
1694 | win = nla_get_u32(props[TIPC_NLA_PROP_WIN]); | ||
1695 | tipc_link_set_queue_limits(link, win); | ||
1696 | } | ||
1697 | } | ||
1698 | |||
1699 | out: | ||
1700 | tipc_node_unlock(node); | ||
1701 | |||
1702 | return res; | ||
1703 | } | ||
1704 | |||
1705 | static int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s) | 1773 | static int __tipc_nl_add_stats(struct sk_buff *skb, struct tipc_stats *s) |
1706 | { | 1774 | { |
1707 | int i; | 1775 | int i; |
@@ -1768,8 +1836,8 @@ msg_full: | |||
1768 | } | 1836 | } |
1769 | 1837 | ||
1770 | /* Caller should hold appropriate locks to protect the link */ | 1838 | /* Caller should hold appropriate locks to protect the link */ |
1771 | static int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg, | 1839 | int __tipc_nl_add_link(struct net *net, struct tipc_nl_msg *msg, |
1772 | struct tipc_link *link, int nlflags) | 1840 | struct tipc_link *link, int nlflags) |
1773 | { | 1841 | { |
1774 | int err; | 1842 | int err; |
1775 | void *hdr; | 1843 | void *hdr; |
@@ -1838,198 +1906,134 @@ msg_full: | |||
1838 | return -EMSGSIZE; | 1906 | return -EMSGSIZE; |
1839 | } | 1907 | } |
1840 | 1908 | ||
1841 | /* Caller should hold node lock */ | 1909 | static int __tipc_nl_add_bc_link_stat(struct sk_buff *skb, |
1842 | static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg, | 1910 | struct tipc_stats *stats) |
1843 | struct tipc_node *node, u32 *prev_link) | ||
1844 | { | 1911 | { |
1845 | u32 i; | 1912 | int i; |
1846 | int err; | 1913 | struct nlattr *nest; |
1847 | |||
1848 | for (i = *prev_link; i < MAX_BEARERS; i++) { | ||
1849 | *prev_link = i; | ||
1850 | |||
1851 | if (!node->links[i].link) | ||
1852 | continue; | ||
1853 | 1914 | ||
1854 | err = __tipc_nl_add_link(net, msg, | 1915 | struct nla_map { |
1855 | node->links[i].link, NLM_F_MULTI); | 1916 | __u32 key; |
1856 | if (err) | 1917 | __u32 val; |
1857 | return err; | 1918 | }; |
1858 | } | ||
1859 | *prev_link = 0; | ||
1860 | 1919 | ||
1861 | return 0; | 1920 | struct nla_map map[] = { |
1862 | } | 1921 | {TIPC_NLA_STATS_RX_INFO, stats->recv_info}, |
1922 | {TIPC_NLA_STATS_RX_FRAGMENTS, stats->recv_fragments}, | ||
1923 | {TIPC_NLA_STATS_RX_FRAGMENTED, stats->recv_fragmented}, | ||
1924 | {TIPC_NLA_STATS_RX_BUNDLES, stats->recv_bundles}, | ||
1925 | {TIPC_NLA_STATS_RX_BUNDLED, stats->recv_bundled}, | ||
1926 | {TIPC_NLA_STATS_TX_INFO, stats->sent_info}, | ||
1927 | {TIPC_NLA_STATS_TX_FRAGMENTS, stats->sent_fragments}, | ||
1928 | {TIPC_NLA_STATS_TX_FRAGMENTED, stats->sent_fragmented}, | ||
1929 | {TIPC_NLA_STATS_TX_BUNDLES, stats->sent_bundles}, | ||
1930 | {TIPC_NLA_STATS_TX_BUNDLED, stats->sent_bundled}, | ||
1931 | {TIPC_NLA_STATS_RX_NACKS, stats->recv_nacks}, | ||
1932 | {TIPC_NLA_STATS_RX_DEFERRED, stats->deferred_recv}, | ||
1933 | {TIPC_NLA_STATS_TX_NACKS, stats->sent_nacks}, | ||
1934 | {TIPC_NLA_STATS_TX_ACKS, stats->sent_acks}, | ||
1935 | {TIPC_NLA_STATS_RETRANSMITTED, stats->retransmitted}, | ||
1936 | {TIPC_NLA_STATS_DUPLICATES, stats->duplicates}, | ||
1937 | {TIPC_NLA_STATS_LINK_CONGS, stats->link_congs}, | ||
1938 | {TIPC_NLA_STATS_MAX_QUEUE, stats->max_queue_sz}, | ||
1939 | {TIPC_NLA_STATS_AVG_QUEUE, stats->queue_sz_counts ? | ||
1940 | (stats->accu_queue_sz / stats->queue_sz_counts) : 0} | ||
1941 | }; | ||
1863 | 1942 | ||
1864 | int tipc_nl_link_dump(struct sk_buff *skb, struct netlink_callback *cb) | 1943 | nest = nla_nest_start(skb, TIPC_NLA_LINK_STATS); |
1865 | { | 1944 | if (!nest) |
1866 | struct net *net = sock_net(skb->sk); | 1945 | return -EMSGSIZE; |
1867 | struct tipc_net *tn = net_generic(net, tipc_net_id); | ||
1868 | struct tipc_node *node; | ||
1869 | struct tipc_nl_msg msg; | ||
1870 | u32 prev_node = cb->args[0]; | ||
1871 | u32 prev_link = cb->args[1]; | ||
1872 | int done = cb->args[2]; | ||
1873 | int err; | ||
1874 | 1946 | ||
1875 | if (done) | 1947 | for (i = 0; i < ARRAY_SIZE(map); i++) |
1876 | return 0; | 1948 | if (nla_put_u32(skb, map[i].key, map[i].val)) |
1949 | goto msg_full; | ||
1877 | 1950 | ||
1878 | msg.skb = skb; | 1951 | nla_nest_end(skb, nest); |
1879 | msg.portid = NETLINK_CB(cb->skb).portid; | ||
1880 | msg.seq = cb->nlh->nlmsg_seq; | ||
1881 | |||
1882 | rcu_read_lock(); | ||
1883 | if (prev_node) { | ||
1884 | node = tipc_node_find(net, prev_node); | ||
1885 | if (!node) { | ||
1886 | /* We never set seq or call nl_dump_check_consistent() | ||
1887 | * this means that setting prev_seq here will cause the | ||
1888 | * consistence check to fail in the netlink callback | ||
1889 | * handler. Resulting in the last NLMSG_DONE message | ||
1890 | * having the NLM_F_DUMP_INTR flag set. | ||
1891 | */ | ||
1892 | cb->prev_seq = 1; | ||
1893 | goto out; | ||
1894 | } | ||
1895 | tipc_node_put(node); | ||
1896 | |||
1897 | list_for_each_entry_continue_rcu(node, &tn->node_list, | ||
1898 | list) { | ||
1899 | tipc_node_lock(node); | ||
1900 | err = __tipc_nl_add_node_links(net, &msg, node, | ||
1901 | &prev_link); | ||
1902 | tipc_node_unlock(node); | ||
1903 | if (err) | ||
1904 | goto out; | ||
1905 | |||
1906 | prev_node = node->addr; | ||
1907 | } | ||
1908 | } else { | ||
1909 | err = tipc_nl_add_bc_link(net, &msg); | ||
1910 | if (err) | ||
1911 | goto out; | ||
1912 | |||
1913 | list_for_each_entry_rcu(node, &tn->node_list, list) { | ||
1914 | tipc_node_lock(node); | ||
1915 | err = __tipc_nl_add_node_links(net, &msg, node, | ||
1916 | &prev_link); | ||
1917 | tipc_node_unlock(node); | ||
1918 | if (err) | ||
1919 | goto out; | ||
1920 | |||
1921 | prev_node = node->addr; | ||
1922 | } | ||
1923 | } | ||
1924 | done = 1; | ||
1925 | out: | ||
1926 | rcu_read_unlock(); | ||
1927 | 1952 | ||
1928 | cb->args[0] = prev_node; | 1953 | return 0; |
1929 | cb->args[1] = prev_link; | 1954 | msg_full: |
1930 | cb->args[2] = done; | 1955 | nla_nest_cancel(skb, nest); |
1931 | 1956 | ||
1932 | return skb->len; | 1957 | return -EMSGSIZE; |
1933 | } | 1958 | } |
1934 | 1959 | ||
1935 | int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info) | 1960 | int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg) |
1936 | { | 1961 | { |
1937 | struct net *net = genl_info_net(info); | ||
1938 | struct tipc_nl_msg msg; | ||
1939 | char *name; | ||
1940 | int err; | 1962 | int err; |
1963 | void *hdr; | ||
1964 | struct nlattr *attrs; | ||
1965 | struct nlattr *prop; | ||
1966 | struct tipc_net *tn = net_generic(net, tipc_net_id); | ||
1967 | struct tipc_link *bcl = tn->bcl; | ||
1941 | 1968 | ||
1942 | msg.portid = info->snd_portid; | 1969 | if (!bcl) |
1943 | msg.seq = info->snd_seq; | 1970 | return 0; |
1944 | |||
1945 | if (!info->attrs[TIPC_NLA_LINK_NAME]) | ||
1946 | return -EINVAL; | ||
1947 | name = nla_data(info->attrs[TIPC_NLA_LINK_NAME]); | ||
1948 | 1971 | ||
1949 | msg.skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); | 1972 | tipc_bcast_lock(net); |
1950 | if (!msg.skb) | ||
1951 | return -ENOMEM; | ||
1952 | 1973 | ||
1953 | if (strcmp(name, tipc_bclink_name) == 0) { | 1974 | hdr = genlmsg_put(msg->skb, msg->portid, msg->seq, &tipc_genl_family, |
1954 | err = tipc_nl_add_bc_link(net, &msg); | 1975 | NLM_F_MULTI, TIPC_NL_LINK_GET); |
1955 | if (err) { | 1976 | if (!hdr) |
1956 | nlmsg_free(msg.skb); | 1977 | return -EMSGSIZE; |
1957 | return err; | ||
1958 | } | ||
1959 | } else { | ||
1960 | int bearer_id; | ||
1961 | struct tipc_node *node; | ||
1962 | struct tipc_link *link; | ||
1963 | 1978 | ||
1964 | node = tipc_link_find_owner(net, name, &bearer_id); | 1979 | attrs = nla_nest_start(msg->skb, TIPC_NLA_LINK); |
1965 | if (!node) | 1980 | if (!attrs) |
1966 | return -EINVAL; | 1981 | goto msg_full; |
1967 | 1982 | ||
1968 | tipc_node_lock(node); | 1983 | /* The broadcast link is always up */ |
1969 | link = node->links[bearer_id].link; | 1984 | if (nla_put_flag(msg->skb, TIPC_NLA_LINK_UP)) |
1970 | if (!link) { | 1985 | goto attr_msg_full; |
1971 | tipc_node_unlock(node); | ||
1972 | nlmsg_free(msg.skb); | ||
1973 | return -EINVAL; | ||
1974 | } | ||
1975 | 1986 | ||
1976 | err = __tipc_nl_add_link(net, &msg, link, 0); | 1987 | if (nla_put_flag(msg->skb, TIPC_NLA_LINK_BROADCAST)) |
1977 | tipc_node_unlock(node); | 1988 | goto attr_msg_full; |
1978 | if (err) { | 1989 | if (nla_put_string(msg->skb, TIPC_NLA_LINK_NAME, bcl->name)) |
1979 | nlmsg_free(msg.skb); | 1990 | goto attr_msg_full; |
1980 | return err; | 1991 | if (nla_put_u32(msg->skb, TIPC_NLA_LINK_RX, bcl->rcv_nxt)) |
1981 | } | 1992 | goto attr_msg_full; |
1982 | } | 1993 | if (nla_put_u32(msg->skb, TIPC_NLA_LINK_TX, bcl->snd_nxt)) |
1994 | goto attr_msg_full; | ||
1983 | 1995 | ||
1984 | return genlmsg_reply(msg.skb, info); | 1996 | prop = nla_nest_start(msg->skb, TIPC_NLA_LINK_PROP); |
1985 | } | 1997 | if (!prop) |
1998 | goto attr_msg_full; | ||
1999 | if (nla_put_u32(msg->skb, TIPC_NLA_PROP_WIN, bcl->window)) | ||
2000 | goto prop_msg_full; | ||
2001 | nla_nest_end(msg->skb, prop); | ||
1986 | 2002 | ||
1987 | int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info) | 2003 | err = __tipc_nl_add_bc_link_stat(msg->skb, &bcl->stats); |
1988 | { | ||
1989 | int err; | ||
1990 | char *link_name; | ||
1991 | unsigned int bearer_id; | ||
1992 | struct tipc_link *link; | ||
1993 | struct tipc_node *node; | ||
1994 | struct nlattr *attrs[TIPC_NLA_LINK_MAX + 1]; | ||
1995 | struct net *net = sock_net(skb->sk); | ||
1996 | |||
1997 | if (!info->attrs[TIPC_NLA_LINK]) | ||
1998 | return -EINVAL; | ||
1999 | |||
2000 | err = nla_parse_nested(attrs, TIPC_NLA_LINK_MAX, | ||
2001 | info->attrs[TIPC_NLA_LINK], | ||
2002 | tipc_nl_link_policy); | ||
2003 | if (err) | 2004 | if (err) |
2004 | return err; | 2005 | goto attr_msg_full; |
2005 | |||
2006 | if (!attrs[TIPC_NLA_LINK_NAME]) | ||
2007 | return -EINVAL; | ||
2008 | |||
2009 | link_name = nla_data(attrs[TIPC_NLA_LINK_NAME]); | ||
2010 | 2006 | ||
2011 | if (strcmp(link_name, tipc_bclink_name) == 0) { | 2007 | tipc_bcast_unlock(net); |
2012 | err = tipc_bclink_reset_stats(net); | 2008 | nla_nest_end(msg->skb, attrs); |
2013 | if (err) | 2009 | genlmsg_end(msg->skb, hdr); |
2014 | return err; | ||
2015 | return 0; | ||
2016 | } | ||
2017 | 2010 | ||
2018 | node = tipc_link_find_owner(net, link_name, &bearer_id); | 2011 | return 0; |
2019 | if (!node) | ||
2020 | return -EINVAL; | ||
2021 | 2012 | ||
2022 | tipc_node_lock(node); | 2013 | prop_msg_full: |
2014 | nla_nest_cancel(msg->skb, prop); | ||
2015 | attr_msg_full: | ||
2016 | nla_nest_cancel(msg->skb, attrs); | ||
2017 | msg_full: | ||
2018 | tipc_bcast_unlock(net); | ||
2019 | genlmsg_cancel(msg->skb, hdr); | ||
2023 | 2020 | ||
2024 | link = node->links[bearer_id].link; | 2021 | return -EMSGSIZE; |
2025 | if (!link) { | 2022 | } |
2026 | tipc_node_unlock(node); | ||
2027 | return -EINVAL; | ||
2028 | } | ||
2029 | 2023 | ||
2030 | link_reset_statistics(link); | 2024 | void tipc_link_set_tolerance(struct tipc_link *l, u32 tol) |
2025 | { | ||
2026 | l->tolerance = tol; | ||
2027 | tipc_link_proto_xmit(l, STATE_MSG, 0, 0, tol, 0); | ||
2028 | } | ||
2031 | 2029 | ||
2032 | tipc_node_unlock(node); | 2030 | void tipc_link_set_prio(struct tipc_link *l, u32 prio) |
2031 | { | ||
2032 | l->priority = prio; | ||
2033 | tipc_link_proto_xmit(l, STATE_MSG, 0, 0, 0, prio); | ||
2034 | } | ||
2033 | 2035 | ||
2034 | return 0; | 2036 | void tipc_link_set_abort_limit(struct tipc_link *l, u32 limit) |
2037 | { | ||
2038 | l->abort_limit = limit; | ||
2035 | } | 2039 | } |