summaryrefslogtreecommitdiffstats
path: root/net/tipc/bcast.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2014-11-26 12:30:23 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-26 12:30:23 -0500
commit8b7f8a99906fc21c287ad63ad3a89cf662b0293e (patch)
tree82658ff3ecd103abdad794b9b0833e45160b235e /net/tipc/bcast.c
parent73cf0e923d685a6a1b7754c7d29cc14944f271d9 (diff)
parenta6ca109443842e7251c68451f8137ae68ae6d8a6 (diff)
Merge branch 'tipc-next'
Ying Xue says: ==================== standardize TIPC SKB queue operations Now the following SKB queues are created and maintained within internal TIPC stack: - link transmission queue - link deferred queue - link receive queue - socket outgoing packet chain - name table outgoing packet chain In order to manage above queues, TIPC stack declares a sk_buff pointer for each queue to record its head, and directly modifies "prev" and "next" SKB pointers of SKB structure when inserting or deleting a SKB to or from the queue. As these operations are pretty complex, they easily involve fatal mistakes. If these sk_buff pointers are replaced with sk_buff_head instances as queue heads and corresponding generic SKB list APIs are used to manage them, the entire TIPC code would become quite clean and readable. But before make the change, we need to clean up below redundant functionalities: - remove node subscribe infrastructure - remove protocol message queue - remove retransmission queue - clean up process of pushing packets in link layer ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/bcast.c')
-rw-r--r--net/tipc/bcast.c109
1 files changed, 48 insertions, 61 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c
index 556b26ad4b1..f0761c77173 100644
--- a/net/tipc/bcast.c
+++ b/net/tipc/bcast.c
@@ -217,12 +217,13 @@ struct tipc_node *tipc_bclink_retransmit_to(void)
*/
static void bclink_retransmit_pkt(u32 after, u32 to)
{
- struct sk_buff *buf;
+ struct sk_buff *skb;
- buf = bcl->first_out;
- while (buf && less_eq(buf_seqno(buf), after))
- buf = buf->next;
- tipc_link_retransmit(bcl, buf, mod(to - after));
+ skb_queue_walk(&bcl->outqueue, skb) {
+ if (more(buf_seqno(skb), after))
+ break;
+ }
+ tipc_link_retransmit(bcl, skb, mod(to - after));
}
/**
@@ -245,14 +246,14 @@ void tipc_bclink_wakeup_users(void)
*/
void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
{
- struct sk_buff *crs;
+ struct sk_buff *skb, *tmp;
struct sk_buff *next;
unsigned int released = 0;
tipc_bclink_lock();
/* Bail out if tx queue is empty (no clean up is required) */
- crs = bcl->first_out;
- if (!crs)
+ skb = skb_peek(&bcl->outqueue);
+ if (!skb)
goto exit;
/* Determine which messages need to be acknowledged */
@@ -271,43 +272,43 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
* Bail out if specified sequence number does not correspond
* to a message that has been sent and not yet acknowledged
*/
- if (less(acked, buf_seqno(crs)) ||
+ if (less(acked, buf_seqno(skb)) ||
less(bcl->fsm_msg_cnt, acked) ||
less_eq(acked, n_ptr->bclink.acked))
goto exit;
}
/* Skip over packets that node has previously acknowledged */
- while (crs && less_eq(buf_seqno(crs), n_ptr->bclink.acked))
- crs = crs->next;
+ skb_queue_walk(&bcl->outqueue, skb) {
+ if (more(buf_seqno(skb), n_ptr->bclink.acked))
+ break;
+ }
/* Update packets that node is now acknowledging */
+ skb_queue_walk_from_safe(&bcl->outqueue, skb, tmp) {
+ if (more(buf_seqno(skb), acked))
+ break;
- while (crs && less_eq(buf_seqno(crs), acked)) {
- next = crs->next;
-
- if (crs != bcl->next_out)
- bcbuf_decr_acks(crs);
- else {
- bcbuf_set_acks(crs, 0);
+ next = tipc_skb_queue_next(&bcl->outqueue, skb);
+ if (skb != bcl->next_out) {
+ bcbuf_decr_acks(skb);
+ } else {
+ bcbuf_set_acks(skb, 0);
bcl->next_out = next;
bclink_set_last_sent();
}
- if (bcbuf_acks(crs) == 0) {
- bcl->first_out = next;
- bcl->out_queue_size--;
- kfree_skb(crs);
+ if (bcbuf_acks(skb) == 0) {
+ __skb_unlink(skb, &bcl->outqueue);
+ kfree_skb(skb);
released = 1;
}
- crs = next;
}
n_ptr->bclink.acked = acked;
/* Try resolving broadcast link congestion, if necessary */
-
if (unlikely(bcl->next_out)) {
- tipc_link_push_queue(bcl);
+ tipc_link_push_packets(bcl);
bclink_set_last_sent();
}
if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks)))
@@ -327,19 +328,16 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
struct sk_buff *buf;
/* Ignore "stale" link state info */
-
if (less_eq(last_sent, n_ptr->bclink.last_in))
return;
/* Update link synchronization state; quit if in sync */
-
bclink_update_last_sent(n_ptr, last_sent);
if (n_ptr->bclink.last_sent == n_ptr->bclink.last_in)
return;
/* Update out-of-sync state; quit if loss is still unconfirmed */
-
if ((++n_ptr->bclink.oos_state) == 1) {
if (n_ptr->bclink.deferred_size < (TIPC_MIN_LINK_WIN / 2))
return;
@@ -347,15 +345,15 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
}
/* Don't NACK if one has been recently sent (or seen) */
-
if (n_ptr->bclink.oos_state & 0x1)
return;
/* Send NACK */
-
buf = tipc_buf_acquire(INT_H_SIZE);
if (buf) {
struct tipc_msg *msg = buf_msg(buf);
+ struct sk_buff *skb = skb_peek(&n_ptr->bclink.deferred_queue);
+ u32 to = skb ? buf_seqno(skb) - 1 : n_ptr->bclink.last_sent;
tipc_msg_init(msg, BCAST_PROTOCOL, STATE_MSG,
INT_H_SIZE, n_ptr->addr);
@@ -363,9 +361,7 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, u32 last_sent)
msg_set_mc_netid(msg, tipc_net_id);
msg_set_bcast_ack(msg, n_ptr->bclink.last_in);
msg_set_bcgap_after(msg, n_ptr->bclink.last_in);
- msg_set_bcgap_to(msg, n_ptr->bclink.deferred_head
- ? buf_seqno(n_ptr->bclink.deferred_head) - 1
- : n_ptr->bclink.last_sent);
+ msg_set_bcgap_to(msg, to);
tipc_bclink_lock();
tipc_bearer_send(MAX_BEARERS, buf, NULL);
@@ -402,20 +398,20 @@ static void bclink_peek_nack(struct tipc_msg *msg)
/* tipc_bclink_xmit - broadcast buffer chain to all nodes in cluster
* and to identified node local sockets
- * @buf: chain of buffers containing message
+ * @list: chain of buffers containing message
* Consumes the buffer chain, except when returning -ELINKCONG
* Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
*/
-int tipc_bclink_xmit(struct sk_buff *buf)
+int tipc_bclink_xmit(struct sk_buff_head *list)
{
int rc = 0;
int bc = 0;
- struct sk_buff *clbuf;
+ struct sk_buff *skb;
/* Prepare clone of message for local node */
- clbuf = tipc_msg_reassemble(buf);
- if (unlikely(!clbuf)) {
- kfree_skb_list(buf);
+ skb = tipc_msg_reassemble(list);
+ if (unlikely(!skb)) {
+ __skb_queue_purge(list);
return -EHOSTUNREACH;
}
@@ -423,11 +419,13 @@ int tipc_bclink_xmit(struct sk_buff *buf)
if (likely(bclink)) {
tipc_bclink_lock();
if (likely(bclink->bcast_nodes.count)) {
- rc = __tipc_link_xmit(bcl, buf);
+ rc = __tipc_link_xmit(bcl, list);
if (likely(!rc)) {
+ u32 len = skb_queue_len(&bcl->outqueue);
+
bclink_set_last_sent();
bcl->stats.queue_sz_counts++;
- bcl->stats.accu_queue_sz += bcl->out_queue_size;
+ bcl->stats.accu_queue_sz += len;
}
bc = 1;
}
@@ -435,13 +433,13 @@ int tipc_bclink_xmit(struct sk_buff *buf)
}
if (unlikely(!bc))
- kfree_skb_list(buf);
+ __skb_queue_purge(list);
/* Deliver message clone */
if (likely(!rc))
- tipc_sk_mcast_rcv(clbuf);
+ tipc_sk_mcast_rcv(skb);
else
- kfree_skb(clbuf);
+ kfree_skb(skb);
return rc;
}
@@ -462,7 +460,6 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno)
* Unicast an ACK periodically, ensuring that
* all nodes in the cluster don't ACK at the same time
*/
-
if (((seqno - tipc_own_addr) % TIPC_MIN_LINK_WIN) == 0) {
tipc_link_proto_xmit(node->active_links[node->addr & 1],
STATE_MSG, 0, 0, 0, 0, 0);
@@ -484,7 +481,6 @@ void tipc_bclink_rcv(struct sk_buff *buf)
int deferred = 0;
/* Screen out unwanted broadcast messages */
-
if (msg_mc_netid(msg) != tipc_net_id)
goto exit;
@@ -497,7 +493,6 @@ void tipc_bclink_rcv(struct sk_buff *buf)
goto unlock;
/* Handle broadcast protocol message */
-
if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
if (msg_type(msg) != STATE_MSG)
goto unlock;
@@ -518,14 +513,12 @@ void tipc_bclink_rcv(struct sk_buff *buf)
}
/* Handle in-sequence broadcast message */
-
seqno = msg_seqno(msg);
next_in = mod(node->bclink.last_in + 1);
if (likely(seqno == next_in)) {
receive:
/* Deliver message to destination */
-
if (likely(msg_isdata(msg))) {
tipc_bclink_lock();
bclink_accept_pkt(node, seqno);
@@ -574,7 +567,6 @@ receive:
buf = NULL;
/* Determine new synchronization state */
-
tipc_node_lock(node);
if (unlikely(!tipc_node_is_up(node)))
goto unlock;
@@ -582,33 +574,26 @@ receive:
if (node->bclink.last_in == node->bclink.last_sent)
goto unlock;
- if (!node->bclink.deferred_head) {
+ if (skb_queue_empty(&node->bclink.deferred_queue)) {
node->bclink.oos_state = 1;
goto unlock;
}
- msg = buf_msg(node->bclink.deferred_head);
+ msg = buf_msg(skb_peek(&node->bclink.deferred_queue));
seqno = msg_seqno(msg);
next_in = mod(next_in + 1);
if (seqno != next_in)
goto unlock;
/* Take in-sequence message from deferred queue & deliver it */
-
- buf = node->bclink.deferred_head;
- node->bclink.deferred_head = buf->next;
- buf->next = NULL;
- node->bclink.deferred_size--;
+ buf = __skb_dequeue(&node->bclink.deferred_queue);
goto receive;
}
/* Handle out-of-sequence broadcast message */
-
if (less(next_in, seqno)) {
- deferred = tipc_link_defer_pkt(&node->bclink.deferred_head,
- &node->bclink.deferred_tail,
+ deferred = tipc_link_defer_pkt(&node->bclink.deferred_queue,
buf);
- node->bclink.deferred_size += deferred;
bclink_update_last_sent(node, seqno);
buf = NULL;
}
@@ -963,6 +948,8 @@ int tipc_bclink_init(void)
sprintf(bcbearer->media.name, "tipc-broadcast");
spin_lock_init(&bclink->lock);
+ __skb_queue_head_init(&bcl->outqueue);
+ __skb_queue_head_init(&bcl->deferred_queue);
__skb_queue_head_init(&bcl->waiting_sks);
bcl->next_out_no = 1;
spin_lock_init(&bclink->node.lock);