Commit a3795208 authored by David S. Miller's avatar David S. Miller

Merge branch 'tipc-next'

Jon Maloy says:

====================
tipc: some optimizations and impovements

The commits in this series contain some relatively simple changes that
lead to better throughput across TIPC connections. We also make changes
to the implementation of link transmission queueing and priority
handling, in order to make the code more comprehensible and maintainable.

v2: Commit #2: Redesigned tipc_msg_validate() to use pskb_may_pull(),
               as per feedback from David Miller.
    Commit #3: Some cosmetic changes to tipc_msg_extract(). I tried to
               replace the unconditional skb_linearize() with calls to
               pskb_may_pull() at selected locations, but I gave up.
               First, skb_trim() requires a fully linearized buffer.
               Second, it doesn't make much sense; the whole buffer
               will end up linearized, one way or another.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 5f1764dd e3eea1eb
...@@ -135,9 +135,10 @@ static void bclink_set_last_sent(struct net *net) ...@@ -135,9 +135,10 @@ static void bclink_set_last_sent(struct net *net)
{ {
struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_net *tn = net_generic(net, tipc_net_id);
struct tipc_link *bcl = tn->bcl; struct tipc_link *bcl = tn->bcl;
struct sk_buff *skb = skb_peek(&bcl->backlogq);
if (bcl->next_out) if (skb)
bcl->fsm_msg_cnt = mod(buf_seqno(bcl->next_out) - 1); bcl->fsm_msg_cnt = mod(buf_seqno(skb) - 1);
else else
bcl->fsm_msg_cnt = mod(bcl->next_out_no - 1); bcl->fsm_msg_cnt = mod(bcl->next_out_no - 1);
} }
...@@ -180,7 +181,7 @@ static void bclink_retransmit_pkt(struct tipc_net *tn, u32 after, u32 to) ...@@ -180,7 +181,7 @@ static void bclink_retransmit_pkt(struct tipc_net *tn, u32 after, u32 to)
struct sk_buff *skb; struct sk_buff *skb;
struct tipc_link *bcl = tn->bcl; struct tipc_link *bcl = tn->bcl;
skb_queue_walk(&bcl->outqueue, skb) { skb_queue_walk(&bcl->transmq, skb) {
if (more(buf_seqno(skb), after)) { if (more(buf_seqno(skb), after)) {
tipc_link_retransmit(bcl, skb, mod(to - after)); tipc_link_retransmit(bcl, skb, mod(to - after));
break; break;
...@@ -210,14 +211,17 @@ void tipc_bclink_wakeup_users(struct net *net) ...@@ -210,14 +211,17 @@ void tipc_bclink_wakeup_users(struct net *net)
void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
{ {
struct sk_buff *skb, *tmp; struct sk_buff *skb, *tmp;
struct sk_buff *next;
unsigned int released = 0; unsigned int released = 0;
struct net *net = n_ptr->net; struct net *net = n_ptr->net;
struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_net *tn = net_generic(net, tipc_net_id);
if (unlikely(!n_ptr->bclink.recv_permitted))
return;
tipc_bclink_lock(net); tipc_bclink_lock(net);
/* Bail out if tx queue is empty (no clean up is required) */ /* Bail out if tx queue is empty (no clean up is required) */
skb = skb_peek(&tn->bcl->outqueue); skb = skb_peek(&tn->bcl->transmq);
if (!skb) if (!skb)
goto exit; goto exit;
...@@ -244,27 +248,19 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) ...@@ -244,27 +248,19 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
} }
/* Skip over packets that node has previously acknowledged */ /* Skip over packets that node has previously acknowledged */
skb_queue_walk(&tn->bcl->outqueue, skb) { skb_queue_walk(&tn->bcl->transmq, skb) {
if (more(buf_seqno(skb), n_ptr->bclink.acked)) if (more(buf_seqno(skb), n_ptr->bclink.acked))
break; break;
} }
/* Update packets that node is now acknowledging */ /* Update packets that node is now acknowledging */
skb_queue_walk_from_safe(&tn->bcl->outqueue, skb, tmp) { skb_queue_walk_from_safe(&tn->bcl->transmq, skb, tmp) {
if (more(buf_seqno(skb), acked)) if (more(buf_seqno(skb), acked))
break; break;
bcbuf_decr_acks(skb);
next = tipc_skb_queue_next(&tn->bcl->outqueue, skb); bclink_set_last_sent(net);
if (skb != tn->bcl->next_out) {
bcbuf_decr_acks(skb);
} else {
bcbuf_set_acks(skb, 0);
tn->bcl->next_out = next;
bclink_set_last_sent(net);
}
if (bcbuf_acks(skb) == 0) { if (bcbuf_acks(skb) == 0) {
__skb_unlink(skb, &tn->bcl->outqueue); __skb_unlink(skb, &tn->bcl->transmq);
kfree_skb(skb); kfree_skb(skb);
released = 1; released = 1;
} }
...@@ -272,7 +268,7 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) ...@@ -272,7 +268,7 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked)
n_ptr->bclink.acked = acked; n_ptr->bclink.acked = acked;
/* Try resolving broadcast link congestion, if necessary */ /* Try resolving broadcast link congestion, if necessary */
if (unlikely(tn->bcl->next_out)) { if (unlikely(skb_peek(&tn->bcl->backlogq))) {
tipc_link_push_packets(tn->bcl); tipc_link_push_packets(tn->bcl);
bclink_set_last_sent(net); bclink_set_last_sent(net);
} }
...@@ -319,7 +315,7 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, ...@@ -319,7 +315,7 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr,
buf = tipc_buf_acquire(INT_H_SIZE); buf = tipc_buf_acquire(INT_H_SIZE);
if (buf) { if (buf) {
struct tipc_msg *msg = buf_msg(buf); struct tipc_msg *msg = buf_msg(buf);
struct sk_buff *skb = skb_peek(&n_ptr->bclink.deferred_queue); struct sk_buff *skb = skb_peek(&n_ptr->bclink.deferdq);
u32 to = skb ? buf_seqno(skb) - 1 : n_ptr->bclink.last_sent; u32 to = skb ? buf_seqno(skb) - 1 : n_ptr->bclink.last_sent;
tipc_msg_init(tn->own_addr, msg, BCAST_PROTOCOL, STATE_MSG, tipc_msg_init(tn->own_addr, msg, BCAST_PROTOCOL, STATE_MSG,
...@@ -387,14 +383,13 @@ int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list) ...@@ -387,14 +383,13 @@ int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list)
__skb_queue_purge(list); __skb_queue_purge(list);
return -EHOSTUNREACH; return -EHOSTUNREACH;
} }
/* Broadcast to all nodes */ /* Broadcast to all nodes */
if (likely(bclink)) { if (likely(bclink)) {
tipc_bclink_lock(net); tipc_bclink_lock(net);
if (likely(bclink->bcast_nodes.count)) { if (likely(bclink->bcast_nodes.count)) {
rc = __tipc_link_xmit(net, bcl, list); rc = __tipc_link_xmit(net, bcl, list);
if (likely(!rc)) { if (likely(!rc)) {
u32 len = skb_queue_len(&bcl->outqueue); u32 len = skb_queue_len(&bcl->transmq);
bclink_set_last_sent(net); bclink_set_last_sent(net);
bcl->stats.queue_sz_counts++; bcl->stats.queue_sz_counts++;
...@@ -559,25 +554,25 @@ void tipc_bclink_rcv(struct net *net, struct sk_buff *buf) ...@@ -559,25 +554,25 @@ void tipc_bclink_rcv(struct net *net, struct sk_buff *buf)
if (node->bclink.last_in == node->bclink.last_sent) if (node->bclink.last_in == node->bclink.last_sent)
goto unlock; goto unlock;
if (skb_queue_empty(&node->bclink.deferred_queue)) { if (skb_queue_empty(&node->bclink.deferdq)) {
node->bclink.oos_state = 1; node->bclink.oos_state = 1;
goto unlock; goto unlock;
} }
msg = buf_msg(skb_peek(&node->bclink.deferred_queue)); msg = buf_msg(skb_peek(&node->bclink.deferdq));
seqno = msg_seqno(msg); seqno = msg_seqno(msg);
next_in = mod(next_in + 1); next_in = mod(next_in + 1);
if (seqno != next_in) if (seqno != next_in)
goto unlock; goto unlock;
/* Take in-sequence message from deferred queue & deliver it */ /* Take in-sequence message from deferred queue & deliver it */
buf = __skb_dequeue(&node->bclink.deferred_queue); buf = __skb_dequeue(&node->bclink.deferdq);
goto receive; goto receive;
} }
/* Handle out-of-sequence broadcast message */ /* Handle out-of-sequence broadcast message */
if (less(next_in, seqno)) { if (less(next_in, seqno)) {
deferred = tipc_link_defer_pkt(&node->bclink.deferred_queue, deferred = tipc_link_defer_pkt(&node->bclink.deferdq,
buf); buf);
bclink_update_last_sent(node, seqno); bclink_update_last_sent(node, seqno);
buf = NULL; buf = NULL;
...@@ -634,7 +629,6 @@ static int tipc_bcbearer_send(struct net *net, struct sk_buff *buf, ...@@ -634,7 +629,6 @@ static int tipc_bcbearer_send(struct net *net, struct sk_buff *buf,
msg_set_non_seq(msg, 1); msg_set_non_seq(msg, 1);
msg_set_mc_netid(msg, tn->net_id); msg_set_mc_netid(msg, tn->net_id);
tn->bcl->stats.sent_info++; tn->bcl->stats.sent_info++;
if (WARN_ON(!bclink->bcast_nodes.count)) { if (WARN_ON(!bclink->bcast_nodes.count)) {
dump_stack(); dump_stack();
return 0; return 0;
...@@ -913,8 +907,9 @@ int tipc_bclink_init(struct net *net) ...@@ -913,8 +907,9 @@ int tipc_bclink_init(struct net *net)
sprintf(bcbearer->media.name, "tipc-broadcast"); sprintf(bcbearer->media.name, "tipc-broadcast");
spin_lock_init(&bclink->lock); spin_lock_init(&bclink->lock);
__skb_queue_head_init(&bcl->outqueue); __skb_queue_head_init(&bcl->transmq);
__skb_queue_head_init(&bcl->deferred_queue); __skb_queue_head_init(&bcl->backlogq);
__skb_queue_head_init(&bcl->deferdq);
skb_queue_head_init(&bcl->wakeupq); skb_queue_head_init(&bcl->wakeupq);
bcl->next_out_no = 1; bcl->next_out_no = 1;
spin_lock_init(&bclink->node.lock); spin_lock_init(&bclink->node.lock);
......
...@@ -89,6 +89,7 @@ static void tipc_disc_init_msg(struct net *net, struct sk_buff *buf, u32 type, ...@@ -89,6 +89,7 @@ static void tipc_disc_init_msg(struct net *net, struct sk_buff *buf, u32 type,
MAX_H_SIZE, dest_domain); MAX_H_SIZE, dest_domain);
msg_set_non_seq(msg, 1); msg_set_non_seq(msg, 1);
msg_set_node_sig(msg, tn->random); msg_set_node_sig(msg, tn->random);
msg_set_node_capabilities(msg, 0);
msg_set_dest_domain(msg, dest_domain); msg_set_dest_domain(msg, dest_domain);
msg_set_bc_netid(msg, tn->net_id); msg_set_bc_netid(msg, tn->net_id);
b_ptr->media->addr2msg(msg_media_addr(msg), &b_ptr->addr); b_ptr->media->addr2msg(msg_media_addr(msg), &b_ptr->addr);
...@@ -133,6 +134,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, ...@@ -133,6 +134,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
u32 net_id = msg_bc_netid(msg); u32 net_id = msg_bc_netid(msg);
u32 mtyp = msg_type(msg); u32 mtyp = msg_type(msg);
u32 signature = msg_node_sig(msg); u32 signature = msg_node_sig(msg);
u16 caps = msg_node_capabilities(msg);
bool addr_match = false; bool addr_match = false;
bool sign_match = false; bool sign_match = false;
bool link_up = false; bool link_up = false;
...@@ -167,6 +169,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, ...@@ -167,6 +169,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf,
if (!node) if (!node)
return; return;
tipc_node_lock(node); tipc_node_lock(node);
node->capabilities = caps;
link = node->links[bearer->identity]; link = node->links[bearer->identity];
/* Prepare to validate requesting node's signature and media address */ /* Prepare to validate requesting node's signature and media address */
......
This diff is collapsed.
...@@ -124,7 +124,8 @@ struct tipc_stats { ...@@ -124,7 +124,8 @@ struct tipc_stats {
* @max_pkt: current maximum packet size for this link * @max_pkt: current maximum packet size for this link
* @max_pkt_target: desired maximum packet size for this link * @max_pkt_target: desired maximum packet size for this link
* @max_pkt_probes: # of probes based on current (max_pkt, max_pkt_target) * @max_pkt_probes: # of probes based on current (max_pkt, max_pkt_target)
* @outqueue: outbound message queue * @transmitq: queue for sent, non-acked messages
* @backlogq: queue for messages waiting to be sent
* @next_out_no: next sequence number to use for outbound messages * @next_out_no: next sequence number to use for outbound messages
* @last_retransmitted: sequence number of most recently retransmitted message * @last_retransmitted: sequence number of most recently retransmitted message
* @stale_count: # of identical retransmit requests made by peer * @stale_count: # of identical retransmit requests made by peer
...@@ -177,20 +178,21 @@ struct tipc_link { ...@@ -177,20 +178,21 @@ struct tipc_link {
u32 max_pkt_probes; u32 max_pkt_probes;
/* Sending */ /* Sending */
struct sk_buff_head outqueue; struct sk_buff_head transmq;
struct sk_buff_head backlogq;
u32 next_out_no; u32 next_out_no;
u32 window;
u32 last_retransmitted; u32 last_retransmitted;
u32 stale_count; u32 stale_count;
/* Reception */ /* Reception */
u32 next_in_no; u32 next_in_no;
struct sk_buff_head deferred_queue; u32 rcv_unacked;
u32 unacked_window; struct sk_buff_head deferdq;
struct sk_buff_head inputq; struct sk_buff_head inputq;
struct sk_buff_head namedq; struct sk_buff_head namedq;
/* Congestion handling */ /* Congestion handling */
struct sk_buff *next_out;
struct sk_buff_head wakeupq; struct sk_buff_head wakeupq;
/* Fragmentation/reassembly */ /* Fragmentation/reassembly */
...@@ -302,9 +304,4 @@ static inline int link_reset_reset(struct tipc_link *l_ptr) ...@@ -302,9 +304,4 @@ static inline int link_reset_reset(struct tipc_link *l_ptr)
return l_ptr->state == RESET_RESET; return l_ptr->state == RESET_RESET;
} }
static inline int link_congested(struct tipc_link *l_ptr)
{
return skb_queue_len(&l_ptr->outqueue) >= l_ptr->queue_limit[0];
}
#endif #endif
/* /*
* net/tipc/msg.c: TIPC message header routines * net/tipc/msg.c: TIPC message header routines
* *
* Copyright (c) 2000-2006, 2014, Ericsson AB * Copyright (c) 2000-2006, 2014-2015, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems * Copyright (c) 2005, 2010-2011, Wind River Systems
* All rights reserved. * All rights reserved.
* *
...@@ -165,6 +165,9 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) ...@@ -165,6 +165,9 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
} }
if (fragid == LAST_FRAGMENT) { if (fragid == LAST_FRAGMENT) {
TIPC_SKB_CB(head)->validated = false;
if (unlikely(!tipc_msg_validate(head)))
goto err;
*buf = head; *buf = head;
TIPC_SKB_CB(head)->tail = NULL; TIPC_SKB_CB(head)->tail = NULL;
*headbuf = NULL; *headbuf = NULL;
...@@ -172,7 +175,6 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) ...@@ -172,7 +175,6 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
} }
*buf = NULL; *buf = NULL;
return 0; return 0;
err: err:
pr_warn_ratelimited("Unable to build fragment list\n"); pr_warn_ratelimited("Unable to build fragment list\n");
kfree_skb(*buf); kfree_skb(*buf);
...@@ -181,6 +183,48 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) ...@@ -181,6 +183,48 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
return 0; return 0;
} }
/* tipc_msg_validate - validate basic format of received message
*
* This routine ensures a TIPC message has an acceptable header, and at least
* as much data as the header indicates it should. The routine also ensures
* that the entire message header is stored in the main fragment of the message
* buffer, to simplify future access to message header fields.
*
* Note: Having extra info present in the message header or data areas is OK.
* TIPC will ignore the excess, under the assumption that it is optional info
* introduced by a later release of the protocol.
*/
bool tipc_msg_validate(struct sk_buff *skb)
{
struct tipc_msg *msg;
int msz, hsz;
if (unlikely(TIPC_SKB_CB(skb)->validated))
return true;
if (unlikely(!pskb_may_pull(skb, MIN_H_SIZE)))
return false;
hsz = msg_hdr_sz(buf_msg(skb));
if (unlikely(hsz < MIN_H_SIZE) || (hsz > MAX_H_SIZE))
return false;
if (unlikely(!pskb_may_pull(skb, hsz)))
return false;
msg = buf_msg(skb);
if (unlikely(msg_version(msg) != TIPC_VERSION))
return false;
msz = msg_size(msg);
if (unlikely(msz < hsz))
return false;
if (unlikely((msz - hsz) > TIPC_MAX_USER_MSG_SIZE))
return false;
if (unlikely(skb->len < msz))
return false;
TIPC_SKB_CB(skb)->validated = true;
return true;
}
/** /**
* tipc_msg_build - create buffer chain containing specified header and data * tipc_msg_build - create buffer chain containing specified header and data
...@@ -228,6 +272,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, ...@@ -228,6 +272,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(mhdr)); FIRST_FRAGMENT, INT_H_SIZE, msg_destnode(mhdr));
msg_set_size(&pkthdr, pktmax); msg_set_size(&pkthdr, pktmax);
msg_set_fragm_no(&pkthdr, pktno); msg_set_fragm_no(&pkthdr, pktno);
msg_set_importance(&pkthdr, msg_importance(mhdr));
/* Prepare first fragment */ /* Prepare first fragment */
skb = tipc_buf_acquire(pktmax); skb = tipc_buf_acquire(pktmax);
...@@ -286,33 +331,36 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, ...@@ -286,33 +331,36 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
/** /**
* tipc_msg_bundle(): Append contents of a buffer to tail of an existing one * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one
* @list: the buffer chain of the existing buffer ("bundle") * @bskb: the buffer to append to ("bundle")
* @skb: buffer to be appended * @skb: buffer to be appended
* @mtu: max allowable size for the bundle buffer * @mtu: max allowable size for the bundle buffer
* Consumes buffer if successful * Consumes buffer if successful
* Returns true if bundling could be performed, otherwise false * Returns true if bundling could be performed, otherwise false
*/ */
bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu) bool tipc_msg_bundle(struct sk_buff *bskb, struct sk_buff *skb, u32 mtu)
{ {
struct sk_buff *bskb = skb_peek_tail(list); struct tipc_msg *bmsg;
struct tipc_msg *bmsg = buf_msg(bskb);
struct tipc_msg *msg = buf_msg(skb); struct tipc_msg *msg = buf_msg(skb);
unsigned int bsz = msg_size(bmsg); unsigned int bsz;
unsigned int msz = msg_size(msg); unsigned int msz = msg_size(msg);
u32 start = align(bsz); u32 start, pad;
u32 max = mtu - INT_H_SIZE; u32 max = mtu - INT_H_SIZE;
u32 pad = start - bsz;
if (likely(msg_user(msg) == MSG_FRAGMENTER)) if (likely(msg_user(msg) == MSG_FRAGMENTER))
return false; return false;
if (!bskb)
return false;
bmsg = buf_msg(bskb);
bsz = msg_size(bmsg);
start = align(bsz);
pad = start - bsz;
if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL)) if (unlikely(msg_user(msg) == CHANGEOVER_PROTOCOL))
return false; return false;
if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) if (unlikely(msg_user(msg) == BCAST_PROTOCOL))
return false; return false;
if (likely(msg_user(bmsg) != MSG_BUNDLER)) if (likely(msg_user(bmsg) != MSG_BUNDLER))
return false; return false;
if (likely(!TIPC_SKB_CB(bskb)->bundling))
return false;
if (unlikely(skb_tailroom(bskb) < (pad + msz))) if (unlikely(skb_tailroom(bskb) < (pad + msz)))
return false; return false;
if (unlikely(max < (start + msz))) if (unlikely(max < (start + msz)))
...@@ -328,34 +376,40 @@ bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu) ...@@ -328,34 +376,40 @@ bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu)
/** /**
* tipc_msg_extract(): extract bundled inner packet from buffer * tipc_msg_extract(): extract bundled inner packet from buffer
* @skb: linear outer buffer, to be extracted from. * @skb: buffer to be extracted from.
* @iskb: extracted inner buffer, to be returned * @iskb: extracted inner buffer, to be returned
* @pos: position of msg to be extracted. Returns with pointer of next msg * @pos: position in outer message of msg to be extracted.
* Returns position of next msg
* Consumes outer buffer when last packet extracted * Consumes outer buffer when last packet extracted
* Returns true when when there is an extracted buffer, otherwise false * Returns true when when there is an extracted buffer, otherwise false
*/ */
bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos) bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos)
{ {
struct tipc_msg *msg = buf_msg(skb); struct tipc_msg *msg;
int imsz; int imsz, offset;
struct tipc_msg *imsg = (struct tipc_msg *)(msg_data(msg) + *pos);
*iskb = NULL;
if (unlikely(skb_linearize(skb)))
goto none;
/* Is there space left for shortest possible message? */ msg = buf_msg(skb);
if (*pos > (msg_data_sz(msg) - SHORT_H_SIZE)) offset = msg_hdr_sz(msg) + *pos;
if (unlikely(offset > (msg_size(msg) - MIN_H_SIZE)))
goto none; goto none;
imsz = msg_size(imsg);
/* Is there space left for current message ? */ *iskb = skb_clone(skb, GFP_ATOMIC);
if ((*pos + imsz) > msg_data_sz(msg)) if (unlikely(!*iskb))
goto none; goto none;
*iskb = tipc_buf_acquire(imsz); skb_pull(*iskb, offset);
if (!*iskb) imsz = msg_size(buf_msg(*iskb));
skb_trim(*iskb, imsz);
if (unlikely(!tipc_msg_validate(*iskb)))
goto none; goto none;
skb_copy_to_linear_data(*iskb, imsg, imsz);
*pos += align(imsz); *pos += align(imsz);
return true; return true;
none: none:
kfree_skb(skb); kfree_skb(skb);
kfree_skb(*iskb);
*iskb = NULL; *iskb = NULL;
return false; return false;
} }
...@@ -369,12 +423,11 @@ bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos) ...@@ -369,12 +423,11 @@ bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos)
* Replaces buffer if successful * Replaces buffer if successful
* Returns true if success, otherwise false * Returns true if success, otherwise false
*/ */
bool tipc_msg_make_bundle(struct sk_buff_head *list, bool tipc_msg_make_bundle(struct sk_buff **skb, u32 mtu, u32 dnode)
struct sk_buff *skb, u32 mtu, u32 dnode)
{ {
struct sk_buff *bskb; struct sk_buff *bskb;
struct tipc_msg *bmsg; struct tipc_msg *bmsg;
struct tipc_msg *msg = buf_msg(skb); struct tipc_msg *msg = buf_msg(*skb);
u32 msz = msg_size(msg); u32 msz = msg_size(msg);
u32 max = mtu - INT_H_SIZE; u32 max = mtu - INT_H_SIZE;
...@@ -398,9 +451,9 @@ bool tipc_msg_make_bundle(struct sk_buff_head *list, ...@@ -398,9 +451,9 @@ bool tipc_msg_make_bundle(struct sk_buff_head *list,
msg_set_seqno(bmsg, msg_seqno(msg)); msg_set_seqno(bmsg, msg_seqno(msg));
msg_set_ack(bmsg, msg_ack(msg)); msg_set_ack(bmsg, msg_ack(msg));
msg_set_bcast_ack(bmsg, msg_bcast_ack(msg)); msg_set_bcast_ack(bmsg, msg_bcast_ack(msg));
TIPC_SKB_CB(bskb)->bundling = true; tipc_msg_bundle(bskb, *skb, mtu);
__skb_queue_tail(list, bskb); *skb = bskb;
return tipc_msg_bundle(list, skb, mtu); return true;
} }
/** /**
...@@ -415,21 +468,17 @@ bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode, ...@@ -415,21 +468,17 @@ bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode,
int err) int err)
{ {
struct tipc_msg *msg = buf_msg(buf); struct tipc_msg *msg = buf_msg(buf);
uint imp = msg_importance(msg);
struct tipc_msg ohdr; struct tipc_msg ohdr;
uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE); uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE);
if (skb_linearize(buf)) if (skb_linearize(buf))
goto exit; goto exit;
msg = buf_msg(buf);
if (msg_dest_droppable(msg)) if (msg_dest_droppable(msg))
goto exit; goto exit;
if (msg_errcode(msg)) if (msg_errcode(msg))
goto exit; goto exit;
memcpy(&ohdr, msg, msg_hdr_sz(msg)); memcpy(&ohdr, msg, msg_hdr_sz(msg));
imp = min_t(uint, imp + 1, TIPC_CRITICAL_IMPORTANCE);
if (msg_isdata(msg))
msg_set_importance(msg, imp);
msg_set_errcode(msg, err); msg_set_errcode(msg, err);
msg_set_origport(msg, msg_destport(&ohdr)); msg_set_origport(msg, msg_destport(&ohdr));
msg_set_destport(msg, msg_origport(&ohdr)); msg_set_destport(msg, msg_origport(&ohdr));
......
/* /*
* net/tipc/msg.h: Include file for TIPC message header routines * net/tipc/msg.h: Include file for TIPC message header routines
* *
* Copyright (c) 2000-2007, 2014, Ericsson AB * Copyright (c) 2000-2007, 2014-2015 Ericsson AB
* Copyright (c) 2005-2008, 2010-2011, Wind River Systems * Copyright (c) 2005-2008, 2010-2011, Wind River Systems
* All rights reserved. * All rights reserved.
* *
...@@ -54,6 +54,8 @@ struct plist; ...@@ -54,6 +54,8 @@ struct plist;
* - TIPC_HIGH_IMPORTANCE * - TIPC_HIGH_IMPORTANCE
* - TIPC_CRITICAL_IMPORTANCE * - TIPC_CRITICAL_IMPORTANCE
*/ */
#define TIPC_SYSTEM_IMPORTANCE 4
/* /*
* Payload message types * Payload message types
...@@ -63,6 +65,19 @@ struct plist; ...@@ -63,6 +65,19 @@ struct plist;
#define TIPC_NAMED_MSG 2 #define TIPC_NAMED_MSG 2
#define TIPC_DIRECT_MSG 3 #define TIPC_DIRECT_MSG 3
/*
* Internal message users
*/
#define BCAST_PROTOCOL 5
#define MSG_BUNDLER 6
#define LINK_PROTOCOL 7
#define CONN_MANAGER 8
#define CHANGEOVER_PROTOCOL 10
#define NAME_DISTRIBUTOR 11
#define MSG_FRAGMENTER 12
#define LINK_CONFIG 13
#define SOCK_WAKEUP 14 /* pseudo user */
/* /*
* Message header sizes * Message header sizes
*/ */
...@@ -92,7 +107,7 @@ struct plist; ...@@ -92,7 +107,7 @@ struct plist;
struct tipc_skb_cb { struct tipc_skb_cb {
void *handle; void *handle;
struct sk_buff *tail; struct sk_buff *tail;
bool deferred; bool validated;
bool wakeup_pending; bool wakeup_pending;
bool bundling; bool bundling;
u16 chain_sz; u16 chain_sz;
...@@ -170,16 +185,6 @@ static inline void msg_set_user(struct tipc_msg *m, u32 n) ...@@ -170,16 +185,6 @@ static inline void msg_set_user(struct tipc_msg *m, u32 n)
msg_set_bits(m, 0, 25, 0xf, n); msg_set_bits(m, 0, 25, 0xf, n);
} }
static inline u32 msg_importance(struct tipc_msg *m)
{
return msg_bits(m, 0, 25, 0xf);
}
static inline void msg_set_importance(struct tipc_msg *m, u32 i)
{
msg_set_user(m, i);
}
static inline u32 msg_hdr_sz(struct tipc_msg *m) static inline u32 msg_hdr_sz(struct tipc_msg *m)
{ {
return msg_bits(m, 0, 21, 0xf) << 2; return msg_bits(m, 0, 21, 0xf) << 2;
...@@ -336,6 +341,25 @@ static inline void msg_set_seqno(struct tipc_msg *m, u32 n) ...@@ -336,6 +341,25 @@ static inline void msg_set_seqno(struct tipc_msg *m, u32 n)
/* /*
* Words 3-10 * Words 3-10
*/ */
static inline u32 msg_importance(struct tipc_msg *m)
{
if (unlikely(msg_user(m) == MSG_FRAGMENTER))
return msg_bits(m, 5, 13, 0x7);
if (likely(msg_isdata(m) && !msg_errcode(m)))
return msg_user(m);
return TIPC_SYSTEM_IMPORTANCE;
}
static inline void msg_set_importance(struct tipc_msg *m, u32 i)
{
if (unlikely(msg_user(m) == MSG_FRAGMENTER))
msg_set_bits(m, 5, 13, 0x7, i);
else if (likely(i < TIPC_SYSTEM_IMPORTANCE))
msg_set_user(m, i);
else
pr_warn("Trying to set illegal importance in message\n");
}
static inline u32 msg_prevnode(struct tipc_msg *m) static inline u32 msg_prevnode(struct tipc_msg *m)
{ {
return msg_word(m, 3); return msg_word(m, 3);
...@@ -457,20 +481,6 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) ...@@ -457,20 +481,6 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
* Constants and routines used to read and write TIPC internal message headers * Constants and routines used to read and write TIPC internal message headers
*/ */
/*
* Internal message users
*/
#define BCAST_PROTOCOL 5
#define MSG_BUNDLER 6
#define LINK_PROTOCOL 7
#define CONN_MANAGER 8
#define ROUTE_DISTRIBUTOR 9 /* obsoleted */
#define CHANGEOVER_PROTOCOL 10
#define NAME_DISTRIBUTOR 11
#define MSG_FRAGMENTER 12
#define LINK_CONFIG 13
#define SOCK_WAKEUP 14 /* pseudo user */
/* /*
* Connection management protocol message types * Connection management protocol message types
*/ */
...@@ -510,7 +520,6 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) ...@@ -510,7 +520,6 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m)
#define DSC_REQ_MSG 0 #define DSC_REQ_MSG 0
#define DSC_RESP_MSG 1 #define DSC_RESP_MSG 1
/* /*
* Word 1 * Word 1
*/ */
...@@ -534,6 +543,16 @@ static inline void msg_set_node_sig(struct tipc_msg *m, u32 n) ...@@ -534,6 +543,16 @@ static inline void msg_set_node_sig(struct tipc_msg *m, u32 n)
msg_set_bits(m, 1, 0, 0xffff, n); msg_set_bits(m, 1, 0, 0xffff, n);
} }
static inline u32 msg_node_capabilities(struct tipc_msg *m)
{
return msg_bits(m, 1, 15, 0x1fff);
}
static inline void msg_set_node_capabilities(struct tipc_msg *m, u32 n)
{
msg_set_bits(m, 1, 15, 0x1fff, n);
}
/* /*
* Word 2 * Word 2
...@@ -734,13 +753,6 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) ...@@ -734,13 +753,6 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n)
msg_set_bits(m, 9, 0, 0xffff, n); msg_set_bits(m, 9, 0, 0xffff, n);
} }
static inline u32 tipc_msg_tot_importance(struct tipc_msg *m)
{
if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT))
return msg_importance(msg_get_wrapped(m));
return msg_importance(m);
}
static inline u32 msg_tot_origport(struct tipc_msg *m) static inline u32 msg_tot_origport(struct tipc_msg *m)
{ {
if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT)) if ((msg_user(m) == MSG_FRAGMENTER) && (msg_type(m) == FIRST_FRAGMENT))
...@@ -749,6 +761,7 @@ static inline u32 msg_tot_origport(struct tipc_msg *m) ...@@ -749,6 +761,7 @@ static inline u32 msg_tot_origport(struct tipc_msg *m)
} }
struct sk_buff *tipc_buf_acquire(u32 size); struct sk_buff *tipc_buf_acquire(u32 size);
bool tipc_msg_validate(struct sk_buff *skb);
bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode, bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode,
int err); int err);
void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type, void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type,
...@@ -757,9 +770,9 @@ struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz, ...@@ -757,9 +770,9 @@ struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz,
uint data_sz, u32 dnode, u32 onode, uint data_sz, u32 dnode, u32 onode,
u32 dport, u32 oport, int errcode); u32 dport, u32 oport, int errcode);
int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf); int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf);
bool tipc_msg_bundle(struct sk_buff_head *list, struct sk_buff *skb, u32 mtu); bool tipc_msg_bundle(struct sk_buff *bskb, struct sk_buff *skb, u32 mtu);
bool tipc_msg_make_bundle(struct sk_buff_head *list,
struct sk_buff *skb, u32 mtu, u32 dnode); bool tipc_msg_make_bundle(struct sk_buff **skb, u32 mtu, u32 dnode);
bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos); bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos);
int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m,
int offset, int dsz, int mtu, struct sk_buff_head *list); int offset, int dsz, int mtu, struct sk_buff_head *list);
......
...@@ -111,7 +111,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr) ...@@ -111,7 +111,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
INIT_LIST_HEAD(&n_ptr->list); INIT_LIST_HEAD(&n_ptr->list);
INIT_LIST_HEAD(&n_ptr->publ_list); INIT_LIST_HEAD(&n_ptr->publ_list);
INIT_LIST_HEAD(&n_ptr->conn_sks); INIT_LIST_HEAD(&n_ptr->conn_sks);
__skb_queue_head_init(&n_ptr->bclink.deferred_queue); __skb_queue_head_init(&n_ptr->bclink.deferdq);
hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]); hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
list_for_each_entry_rcu(temp_node, &tn->node_list, list) { list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
if (n_ptr->addr < temp_node->addr) if (n_ptr->addr < temp_node->addr)
...@@ -354,7 +354,7 @@ static void node_lost_contact(struct tipc_node *n_ptr) ...@@ -354,7 +354,7 @@ static void node_lost_contact(struct tipc_node *n_ptr)
/* Flush broadcast link info associated with lost node */ /* Flush broadcast link info associated with lost node */
if (n_ptr->bclink.recv_permitted) { if (n_ptr->bclink.recv_permitted) {
__skb_queue_purge(&n_ptr->bclink.deferred_queue); __skb_queue_purge(&n_ptr->bclink.deferdq);
if (n_ptr->bclink.reasm_buf) { if (n_ptr->bclink.reasm_buf) {
kfree_skb(n_ptr->bclink.reasm_buf); kfree_skb(n_ptr->bclink.reasm_buf);
......
...@@ -84,7 +84,7 @@ struct tipc_node_bclink { ...@@ -84,7 +84,7 @@ struct tipc_node_bclink {
u32 last_sent; u32 last_sent;
u32 oos_state; u32 oos_state;
u32 deferred_size; u32 deferred_size;
struct sk_buff_head deferred_queue; struct sk_buff_head deferdq;
struct sk_buff *reasm_buf; struct sk_buff *reasm_buf;
int inputq_map; int inputq_map;
bool recv_permitted; bool recv_permitted;
...@@ -106,6 +106,7 @@ struct tipc_node_bclink { ...@@ -106,6 +106,7 @@ struct tipc_node_bclink {
* @list: links to adjacent nodes in sorted list of cluster's nodes * @list: links to adjacent nodes in sorted list of cluster's nodes
* @working_links: number of working links to node (both active and standby) * @working_links: number of working links to node (both active and standby)
* @link_cnt: number of links to node * @link_cnt: number of links to node
* @capabilities: bitmap, indicating peer node's functional capabilities
* @signature: node instance identifier * @signature: node instance identifier
* @link_id: local and remote bearer ids of changing link, if any * @link_id: local and remote bearer ids of changing link, if any
* @publ_list: list of publications * @publ_list: list of publications
...@@ -125,7 +126,8 @@ struct tipc_node { ...@@ -125,7 +126,8 @@ struct tipc_node {
struct tipc_node_bclink bclink; struct tipc_node_bclink bclink;
struct list_head list; struct list_head list;
int link_cnt; int link_cnt;
int working_links; u16 working_links;
u16 capabilities;
u32 signature; u32 signature;
u32 link_id; u32 link_id;
struct list_head publ_list; struct list_head publ_list;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment