From 5adeb17c936d2dca155e4c93e2c6ea70419a6033 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 5 Apr 2011 09:48:52 -0400 Subject: [PATCH 01/28] tipc: Remove obsolete manipulation of message re-route count field Eliminates code that increments and validates the re-route count field of payload messages, since the elimination of multi-cluster support means that it is no longer necessary for TIPC to forward incoming messages to another node. (The obsolete code was incorrect anyway, since it incorrectly incremented the re-route count field of messages that originated on the node that forwarded the message.) Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/net.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/net/tipc/net.c b/net/tipc/net.c index 68b3dd637291..fafef6c3c0f6 100644 --- a/net/tipc/net.c +++ b/net/tipc/net.c @@ -141,17 +141,6 @@ void tipc_net_route_msg(struct sk_buff *buf) return; msg = buf_msg(buf); - msg_incr_reroute_cnt(msg); - if (msg_reroute_cnt(msg) > 6) { - if (msg_errcode(msg)) { - buf_discard(buf); - } else { - tipc_reject_msg(buf, msg_destport(msg) ? - TIPC_ERR_NO_PORT : TIPC_ERR_NO_NAME); - } - return; - } - /* Handle message for this node */ dnode = msg_short(msg) ? tipc_own_addr : msg_destnode(msg); if (tipc_in_scope(dnode, tipc_own_addr)) { From ed33a9c4e354b08630bcf4cea70596f690487108 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 5 Apr 2011 15:15:04 -0400 Subject: [PATCH 02/28] tipc: Eliminate obsolete filter for unexpected unicast messages Removes a test that ensures unicast link endpoints discard an incoming message if it will not be consumed by the node itself and cannot be forwarded to another node, since the preceding test already ensures that the message is destined for this node and single-cluster TIPC no longer performs message forwarding. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index f89570c54f54..933764cdfe9a 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1658,19 +1658,12 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) continue; } + /* Discard unicast link messages destined for another node */ + if (unlikely(!msg_short(msg) && (msg_destnode(msg) != tipc_own_addr))) goto cont; - /* Discard non-routeable messages destined for another node */ - - if (unlikely(!msg_isdata(msg) && - (msg_destnode(msg) != tipc_own_addr))) { - if ((msg_user(msg) != CONN_MANAGER) && - (msg_user(msg) != MSG_FRAGMENTER)) - goto cont; - } - /* Locate neighboring node that sent message */ n_ptr = tipc_node_find(msg_prevnode(msg)); From 062b4c99fe70f95e07e8af15617750d2a6fb6789 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 09:28:47 -0400 Subject: [PATCH 03/28] tipc: Display meaningful peer interface name during link creation Sets the peer interface portion of the name of a newly created link endpoint to "unknown". This ensures that state and statistics information can be properly displayed during the time between the link endpoint's creation and the time handshaking with its peer is completed. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 933764cdfe9a..4cb500b53cf1 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -332,12 +332,12 @@ struct link *tipc_link_create(struct tipc_node *n_ptr, l_ptr->addr = peer; if_name = strchr(b_ptr->name, ':') + 1; - sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:", + sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown", tipc_zone(tipc_own_addr), tipc_cluster(tipc_own_addr), tipc_node(tipc_own_addr), if_name, tipc_zone(peer), tipc_cluster(peer), tipc_node(peer)); - /* note: peer i/f is appended to link name by reset/activate */ + /* note: peer i/f name is updated by reset/activate message */ memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr)); l_ptr->owner = n_ptr; l_ptr->checkpoint = 1; From f882cb7684cf54d4f5d3e25443a80a039e1b4bd7 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 09:43:27 -0400 Subject: [PATCH 04/28] tipc: Initialize peer session field of newly created link endpoint Initializes the peer session number field of a newly created link endpoint to an invalid value. This eliminates the remote possibility that it will accidentally match the session number used by the peer the first time the link is activated, and cause the link to ignore a valid RESET message. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/tipc/link.c b/net/tipc/link.c index 4cb500b53cf1..e0bf6d5f1668 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -341,6 +341,7 @@ struct link *tipc_link_create(struct tipc_node *n_ptr, memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr)); l_ptr->owner = n_ptr; l_ptr->checkpoint = 1; + l_ptr->peer_session = INVALID_SESSION; l_ptr->b_ptr = b_ptr; link_set_supervision_props(l_ptr, b_ptr->media->tolerance); l_ptr->state = RESET_UNKNOWN; From 641c218d120b03bdea4f658ab44930587cff9158 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 09:54:43 -0400 Subject: [PATCH 05/28] tipc: Enhance filtering of out-dated link reset messages Ensure TIPC ignores an out-dated link reset message whose session number predates the current session number. (Previously, TIPC only ignored an out-date reset message whose session number was equal to the current link session number.) Out-dated link reset messages should not occur under normal circumstances; however, they can be generated if a link endpoint is unable to send a link reset message right away and queues it for later delivery, but the queued message is not sent until after the link is established. Thanks to Laser [gotolaser@gmail.com] for diagnosing the problem and contributing a prototype patch. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index e0bf6d5f1668..b43beea54108 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -2045,8 +2045,8 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) case RESET_MSG: if (!link_working_unknown(l_ptr) && (l_ptr->peer_session != INVALID_SESSION)) { - if (msg_session(msg) == l_ptr->peer_session) - break; /* duplicate: ignore */ + if (less_eq(msg_session(msg), l_ptr->peer_session)) + break; /* duplicate or old reset: ignore */ } /* fall thru' */ case ACTIVATE_MSG: From 2e2d9be8454e295374dfbddd7ceaba2e4fc01c76 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 10:22:31 -0400 Subject: [PATCH 06/28] tipc: Update obsolete references to multicast link Updates TIPC's broadcast link in a couple of places that were missed during the transition from its former name ("multicast-link") to its current name ("broadcast-link"). These changes are essentially cosmetic and do not affect the overall operation of TIPC. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 759b318b5ffb..411c54b152f0 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -764,7 +764,7 @@ int tipc_bclink_init(void) bcbearer = kzalloc(sizeof(*bcbearer), GFP_ATOMIC); bclink = kzalloc(sizeof(*bclink), GFP_ATOMIC); if (!bcbearer || !bclink) { - warn("Multicast link creation failed, no memory\n"); + warn("Broadcast link creation failed, no memory\n"); kfree(bcbearer); bcbearer = NULL; kfree(bclink); @@ -775,7 +775,7 @@ int tipc_bclink_init(void) INIT_LIST_HEAD(&bcbearer->bearer.cong_links); bcbearer->bearer.media = &bcbearer->media; bcbearer->media.send_msg = tipc_bcbearer_send; - sprintf(bcbearer->media.name, "tipc-multicast"); + sprintf(bcbearer->media.name, "tipc-broadcast"); bcl = &bclink->link; INIT_LIST_HEAD(&bcl->waiting_ports); From 2ff9f924a565aa22c06169c89fcd2133d820a9d2 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 10:44:54 -0400 Subject: [PATCH 07/28] tipc: Cosmetic changes to broadcast bearer send routine Updates the comments in the broadcast bearer send routine to more accurately describe the processing done by the routine. Also replaces the improper use of a TIPC payload message error status symbol (in a place that has nothing to do with such errors) with its numeric equivalent. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 411c54b152f0..7abdca0de281 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -535,10 +535,11 @@ u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr) /** * tipc_bcbearer_send - send a packet through the broadcast pseudo-bearer * - * Send through as many bearers as necessary to reach all nodes - * that support TIPC multicasting. + * Send packet over as many bearers as necessary to reach all nodes + * that have joined the broadcast link. * - * Returns 0 if packet sent successfully, non-zero if not + * Returns 0 (packet sent successfully) under all circumstances, + * since the broadcast link's pseudo-bearer never blocks */ static int tipc_bcbearer_send(struct sk_buff *buf, @@ -547,7 +548,12 @@ static int tipc_bcbearer_send(struct sk_buff *buf, { int bp_index; - /* Prepare buffer for broadcasting (if first time trying to send it) */ + /* + * Prepare broadcast link message for reliable transmission, + * if first time trying to send it; + * preparation is skipped for broadcast link protocol messages + * since they are sent in an unreliable manner and don't need it + */ if (likely(!msg_non_seq(buf_msg(buf)))) { struct tipc_msg *msg; @@ -596,18 +602,12 @@ static int tipc_bcbearer_send(struct sk_buff *buf, } if (bcbearer->remains_new.count == 0) - return 0; + break; /* all targets reached */ bcbearer->remains = bcbearer->remains_new; } - /* - * Unable to reach all targets (indicate success, since currently - * there isn't code in place to properly block & unblock the - * pseudo-bearer used by the broadcast link) - */ - - return TIPC_OK; + return 0; } /** From 23f0ff906af93be6edb579824474117b232c7cc0 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 11:25:26 -0400 Subject: [PATCH 08/28] tipc: Remove non-executable code to handle broadcast bearer congestion Eliminates code associated with the sending of unsent broadcast link traffic when the broadcast pseudo-bearer becomes unblocked following a temporary congestion situation. This code is non-executable because the broadcast pseudo-bearer never becomes blocked [see tipc_bcbearer_send()]. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 21 --------------------- net/tipc/bcast.h | 1 - net/tipc/bearer.c | 6 +----- 3 files changed, 1 insertion(+), 27 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 7abdca0de281..5200457eaeb4 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -667,27 +667,6 @@ void tipc_bcbearer_sort(void) spin_unlock_bh(&bc_lock); } -/** - * tipc_bcbearer_push - resolve bearer congestion - * - * Forces bclink to push out any unsent packets, until all packets are gone - * or congestion reoccurs. - * No locks set when function called - */ - -void tipc_bcbearer_push(void) -{ - struct tipc_bearer *b_ptr; - - spin_lock_bh(&bc_lock); - b_ptr = &bcbearer->bearer; - if (b_ptr->blocked) { - b_ptr->blocked = 0; - tipc_bearer_lock_push(b_ptr); - } - spin_unlock_bh(&bc_lock); -} - int tipc_bclink_stats(char *buf, const u32 buf_size) { diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 500c97f1c859..06740da5ae61 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -101,6 +101,5 @@ int tipc_bclink_stats(char *stats_buf, const u32 buf_size); int tipc_bclink_reset_stats(void); int tipc_bclink_set_queue_limits(u32 limit); void tipc_bcbearer_sort(void); -void tipc_bcbearer_push(void); #endif diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 85eba9c08ee9..e465a92a4f9c 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -385,13 +385,9 @@ static int bearer_push(struct tipc_bearer *b_ptr) void tipc_bearer_lock_push(struct tipc_bearer *b_ptr) { - int res; - spin_lock_bh(&b_ptr->lock); - res = bearer_push(b_ptr); + bearer_push(b_ptr); spin_unlock_bh(&b_ptr->lock); - if (res) - tipc_bcbearer_push(); } From c5bd4d85d356199ebdbc2c8bbfff86a292c65a9f Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 11:58:08 -0400 Subject: [PATCH 09/28] tipc: Enhance cleanup of broadcast link when contact with node is lost Enhances cleanup of broadcast link-related information when contact with a node is lost. 1) All broadcast link-related cleanup now occurs only if the lost node was capable of communicating over the broadcast link. 2) Following cleanup, the lost node is marked as no longer supporting the broadcast link, ensuring that any remaining broadcast messages received from that node prior to the re-establishment of a normal communication link are ignored. Thanks to Surya [Suryanarayana.Garlapati@emerson.com] for contributing a prototype version of this patch. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/node.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 2d106ef4fa4c..810b39545264 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -331,28 +331,32 @@ static void node_lost_contact(struct tipc_node *n_ptr) char addr_string[16]; u32 i; - /* Clean up broadcast reception remains */ - n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0; - while (n_ptr->bclink.deferred_head) { - struct sk_buff *buf = n_ptr->bclink.deferred_head; - n_ptr->bclink.deferred_head = buf->next; - buf_discard(buf); - } - if (n_ptr->bclink.defragm) { - buf_discard(n_ptr->bclink.defragm); - n_ptr->bclink.defragm = NULL; - } + info("Lost contact with %s\n", + tipc_addr_string_fill(addr_string, n_ptr->addr)); + + /* Flush broadcast link info associated with lost node */ if (n_ptr->bclink.supported) { + n_ptr->bclink.gap_after = n_ptr->bclink.gap_to = 0; + while (n_ptr->bclink.deferred_head) { + struct sk_buff *buf = n_ptr->bclink.deferred_head; + n_ptr->bclink.deferred_head = buf->next; + buf_discard(buf); + } + + if (n_ptr->bclink.defragm) { + buf_discard(n_ptr->bclink.defragm); + n_ptr->bclink.defragm = NULL; + } + tipc_bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000)); tipc_nmap_remove(&tipc_bcast_nmap, n_ptr->addr); if (n_ptr->addr < tipc_own_addr) tipc_own_tag--; - } - info("Lost contact with %s\n", - tipc_addr_string_fill(addr_string, n_ptr->addr)); + n_ptr->bclink.supported = 0; + } /* Abort link changeover */ for (i = 0; i < MAX_BEARERS; i++) { From 169073db442cb9e5aa2b70a2e4158d4f35a3b810 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 13:05:25 -0400 Subject: [PATCH 10/28] tipc: Prevent broadcast link stalling when another node fails Ensure that broadcast link messages that have not been acknowledged by a newly failed node do not get an implied acknowledgement until the failed node is removed from the broadcast link's map of reachable nodes. Previously, a race condition allowed a new broadcast link message to be sent after the implicit acknowledgement processing was completed, but before the map of reachable nodes was updated, resulting in the message having an expected acknowledgement count that required the failed node to explicitly acknowledge the message. Since this would never occur the new message would remain in the broadcast link's transmit queue forever, eventually causing the link to become congested and "stall". Delaying the implicit acknowledgement processing until after the update of the map of reachable nodes eliminates this race condition and prevents stalling. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/node.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 810b39545264..d75432f5e726 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -349,9 +349,9 @@ static void node_lost_contact(struct tipc_node *n_ptr) n_ptr->bclink.defragm = NULL; } + tipc_nmap_remove(&tipc_bcast_nmap, n_ptr->addr); tipc_bclink_acknowledge(n_ptr, mod(n_ptr->bclink.acked + 10000)); - tipc_nmap_remove(&tipc_bcast_nmap, n_ptr->addr); if (n_ptr->addr < tipc_own_addr) tipc_own_tag--; From 5d3c488dfe5f797d9f3cee2e8928aad8a2f6e44f Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 13:57:25 -0400 Subject: [PATCH 11/28] tipc: Fix node lock problems during broadcast message reception Modifies TIPC's incoming broadcast packet handler to ensure that the node lock associated with the sender of the packet is held whenever node-related data structure fields are accessed. The routine is also restructured with a single exit point, making it easier to ensure the node lock is properly released and the incoming packet is properly disposed of. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 5200457eaeb4..bc01ca6891e4 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -426,20 +426,26 @@ int tipc_bclink_send_msg(struct sk_buff *buf) void tipc_bclink_recv_pkt(struct sk_buff *buf) { struct tipc_msg *msg = buf_msg(buf); - struct tipc_node *node = tipc_node_find(msg_prevnode(msg)); + struct tipc_node *node; u32 next_in; u32 seqno; struct sk_buff *deferred; - if (unlikely(!node || !tipc_node_is_up(node) || !node->bclink.supported || - (msg_mc_netid(msg) != tipc_net_id))) { - buf_discard(buf); - return; - } + /* Screen out unwanted broadcast messages */ + + if (msg_mc_netid(msg) != tipc_net_id) + goto exit; + + node = tipc_node_find(msg_prevnode(msg)); + if (unlikely(!node)) + goto exit; + + tipc_node_lock(node); + if (unlikely(!node->bclink.supported)) + goto unlock; if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) { if (msg_destnode(msg) == tipc_own_addr) { - tipc_node_lock(node); tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); tipc_node_unlock(node); spin_lock_bh(&bc_lock); @@ -449,16 +455,17 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) msg_bcgap_to(msg)); spin_unlock_bh(&bc_lock); } else { + tipc_node_unlock(node); tipc_bclink_peek_nack(msg_destnode(msg), msg_bcast_tag(msg), msg_bcgap_after(msg), msg_bcgap_to(msg)); } - buf_discard(buf); - return; + goto exit; } - tipc_node_lock(node); + /* Handle in-sequence broadcast message */ + receive: deferred = node->bclink.deferred_head; next_in = mod(node->bclink.last_in + 1); @@ -491,14 +498,14 @@ receive: tipc_node_unlock(node); tipc_net_route_msg(buf); } + buf = NULL; + tipc_node_lock(node); if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) { - tipc_node_lock(node); buf = deferred; msg = buf_msg(buf); node->bclink.deferred_head = deferred->next; goto receive; } - return; } else if (less(next_in, seqno)) { u32 gap_after = node->bclink.gap_after; u32 gap_to = node->bclink.gap_to; @@ -513,6 +520,7 @@ receive: else if (less(gap_after, seqno) && less(seqno, gap_to)) node->bclink.gap_to = seqno; } + buf = NULL; if (bclink_ack_allowed(node->bclink.nack_sync)) { if (gap_to != gap_after) bclink_send_nack(node); @@ -520,9 +528,11 @@ receive: } } else { bcl->stats.duplicates++; - buf_discard(buf); } +unlock: tipc_node_unlock(node); +exit: + buf_discard(buf); } u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr) From 693d03ae3c2bafd7caca1cf4ade9f23f107e33c1 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 14:20:45 -0400 Subject: [PATCH 12/28] tipc: Remove deferred queue head caching during broadcast message reception Modifies TIPC's incoming broadcast packet handler so that it no longer pre-reads information about the deferred packet queue, since the cached value is unreliable once the associated node lock has been released. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index bc01ca6891e4..8d298526a5c1 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -467,7 +467,6 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) /* Handle in-sequence broadcast message */ receive: - deferred = node->bclink.deferred_head; next_in = mod(node->bclink.last_in + 1); seqno = msg_seqno(msg); @@ -500,6 +499,7 @@ receive: } buf = NULL; tipc_node_lock(node); + deferred = node->bclink.deferred_head; if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) { buf = deferred; msg = buf_msg(buf); From 9f6bdcd4286145e812058e4111e906e9830514d8 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 14:57:53 -0400 Subject: [PATCH 13/28] tipc: Discard incoming broadcast messages that are unexpected Modifies TIPC's incoming broadcast packet handler to discard messages that cannot legally be sent over the broadcast link, including: - broadcast protocol messages that do no contain state information - payload messages that are not named multicast messages - any other form of message except for bundled messages, fragmented messages, and name distribution messages. These checks are needed to prevent TIPC from handing an unexpected message to a routine that isn't prepared to handle it, which could lead to incorrect processing (up to and including invalid memory references caused by attempts to access message fields that aren't present in the message). Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 8d298526a5c1..bead28b5efff 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -39,6 +39,7 @@ #include "link.h" #include "port.h" #include "bcast.h" +#include "name_distr.h" #define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */ @@ -445,6 +446,8 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) goto unlock; if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) { + if (msg_type(msg) != STATE_MSG) + goto unlock; if (msg_destnode(msg) == tipc_own_addr) { tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); tipc_node_unlock(node); @@ -480,7 +483,10 @@ receive: } if (likely(msg_isdata(msg))) { tipc_node_unlock(node); - tipc_port_recv_mcast(buf, NULL); + if (likely(msg_mcast(msg))) + tipc_port_recv_mcast(buf, NULL); + else + buf_discard(buf); } else if (msg_user(msg) == MSG_BUNDLER) { bcl->stats.recv_bundles++; bcl->stats.recv_bundled += msg_msgcnt(msg); @@ -493,9 +499,12 @@ receive: bcl->stats.recv_fragmented++; tipc_node_unlock(node); tipc_net_route_msg(buf); + } else if (msg_user(msg) == NAME_DISTRIBUTOR) { + tipc_node_unlock(node); + tipc_named_recv(buf); } else { tipc_node_unlock(node); - tipc_net_route_msg(buf); + buf_discard(buf); } buf = NULL; tipc_node_lock(node); From 0f38513d22e14f607fc791364856b08cac9f91c9 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 7 Apr 2011 15:47:48 -0400 Subject: [PATCH 14/28] tipc: Remove obsolete congestion handling when sending a broadcast NACK Eliminates obsolete code that handles broadcast bearer congestion when the broadast link sends a NACK message, since the broadcast pseudo-bearer never becomes blocked. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bcast.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index bead28b5efff..28908f54459e 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -299,14 +299,9 @@ static void bclink_send_nack(struct tipc_node *n_ptr) msg_set_bcgap_to(msg, n_ptr->bclink.gap_to); msg_set_bcast_tag(msg, tipc_own_tag); - if (tipc_bearer_send(&bcbearer->bearer, buf, NULL)) { - bcl->stats.sent_nacks++; - buf_discard(buf); - } else { - tipc_bearer_schedule(bcl->b_ptr, bcl); - bcl->proto_msg_queue = buf; - bcl->stats.bearer_congs++; - } + tipc_bearer_send(&bcbearer->bearer, buf, NULL); + bcl->stats.sent_nacks++; + buf_discard(buf); /* * Ensure we doesn't send another NACK msg to the node From ff60af8c16aa3b8ee51a0a6b4c4ea42342d1607d Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 26 May 2011 13:24:24 -0400 Subject: [PATCH 15/28] tipc: Eliminate redundant check when sending messages Eliminates code in tipc_send_buf_fast() that handles messages sent to a destination on the current node, since the only caller of the routine only passes in messages destined for other nodes. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index b43beea54108..bc655f456495 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1032,9 +1032,6 @@ int tipc_send_buf_fast(struct sk_buff *buf, u32 destnode) u32 selector = msg_origport(buf_msg(buf)) & 1; u32 dummy; - if (destnode == tipc_own_addr) - return tipc_port_recv_msg(buf); - read_lock_bh(&tipc_net_lock); n_ptr = tipc_node_find(destnode); if (likely(n_ptr)) { From a0f40f02ef0783688233caf737a17f1f56283e2b Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 26 May 2011 13:44:34 -0400 Subject: [PATCH 16/28] tipc: Prevent rounding issues when saving connect timeout option Saves a socket's TIPC_CONN_TIMEOUT socket option value in its original form (milliseconds), rather than jiffies. This ensures that the exact value set using setsockopt() is always returned by getsockopt(), without being subject to rounding issues introduced by a ms->jiffies->ms conversion sequence. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/socket.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index adb2eff4a102..fc3c281c127d 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -49,7 +49,7 @@ struct tipc_sock { struct sock sk; struct tipc_port *p; struct tipc_portid peer_name; - long conn_timeout; + unsigned int conn_timeout; }; #define tipc_sk(sk) ((struct tipc_sock *)(sk)) @@ -231,7 +231,7 @@ static int tipc_create(struct net *net, struct socket *sock, int protocol, sock_init_data(sock, sk); sk->sk_backlog_rcv = backlog_rcv; tipc_sk(sk)->p = tp_ptr; - tipc_sk(sk)->conn_timeout = msecs_to_jiffies(CONN_TIMEOUT_DEFAULT); + tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT; spin_unlock_bh(tp_ptr->lock); @@ -1369,7 +1369,7 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, struct msghdr m = {NULL,}; struct sk_buff *buf; struct tipc_msg *msg; - long timeout; + unsigned int timeout; int res; lock_sock(sk); @@ -1434,7 +1434,8 @@ static int connect(struct socket *sock, struct sockaddr *dest, int destlen, res = wait_event_interruptible_timeout(*sk_sleep(sk), (!skb_queue_empty(&sk->sk_receive_queue) || (sock->state != SS_CONNECTING)), - timeout ? timeout : MAX_SCHEDULE_TIMEOUT); + timeout ? (long)msecs_to_jiffies(timeout) + : MAX_SCHEDULE_TIMEOUT); lock_sock(sk); if (res > 0) { @@ -1696,7 +1697,7 @@ static int setsockopt(struct socket *sock, res = tipc_set_portunreturnable(tport->ref, value); break; case TIPC_CONN_TIMEOUT: - tipc_sk(sk)->conn_timeout = msecs_to_jiffies(value); + tipc_sk(sk)->conn_timeout = value; /* no need to set "res", since already 0 at this point */ break; default: @@ -1752,7 +1753,7 @@ static int getsockopt(struct socket *sock, res = tipc_portunreturnable(tport->ref, &value); break; case TIPC_CONN_TIMEOUT: - value = jiffies_to_msecs(tipc_sk(sk)->conn_timeout); + value = tipc_sk(sk)->conn_timeout; /* no need to set "res", since already 0 at this point */ break; case TIPC_NODE_RECVQ_DEPTH: From 4b3743ef2ca67e1f8ef7e9d4c551d6ba6ee85584 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Thu, 26 May 2011 13:59:17 -0400 Subject: [PATCH 17/28] tipc: Ensure congested links receive bearer status updates Modifies code that disables a bearer to ensure that all of its links are deleted, not just its uncongested links. Similarly, modifies code that blocks a bearer to ensure that all of its links are reset, not just its uncongested links. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bearer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index e465a92a4f9c..e2202de3d93e 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -604,6 +604,7 @@ int tipc_block_bearer(const char *name) info("Blocking bearer <%s>\n", name); spin_lock_bh(&b_ptr->lock); b_ptr->blocked = 1; + list_splice_init(&b_ptr->cong_links, &b_ptr->links); list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { struct tipc_node *n_ptr = l_ptr->owner; @@ -631,6 +632,7 @@ static void bearer_disable(struct tipc_bearer *b_ptr) spin_lock_bh(&b_ptr->lock); b_ptr->blocked = 1; b_ptr->media->disable_bearer(b_ptr); + list_splice_init(&b_ptr->cong_links, &b_ptr->links); list_for_each_entry_safe(l_ptr, temp_l_ptr, &b_ptr->links, link_list) { tipc_link_delete(l_ptr); } From b4b5610223f17790419b03eaa962b0e3ecf930d7 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 27 May 2011 11:00:51 -0400 Subject: [PATCH 18/28] tipc: Ensure both nodes recognize loss of contact between them Enhances TIPC to ensure that a node that loses contact with a neighboring node does not allow contact to be re-established until it sees that its peer has also recognized the loss of contact. Previously, nodes that were connected by two or more links could encounter a situation in which node A would lose contact with node B on all of its links, purge its name table of names published by B, and then fail to repopulate those names once contact with B was restored. This would happen because B was able to re-establish one or more links so quickly that it never reached a point where it had no links to A -- meaning that B never saw a loss of contact with A, and consequently didn't re-publish its names to A. This problem is now prevented by enhancing the cleanup done by TIPC following a loss of contact with a neighboring node to ensure that node A ignores all messages sent by B until it receives a LINK_PROTOCOL message that indicates B has lost contact with A, thereby preventing the (re)establishment of links between the nodes. The loss of contact is recognized when a RESET or ACTIVATE message is received that has a "redundant link exists" field of 0, indicating that B's sending link endpoint is in a reset state and that B has no other working links. Additionally, TIPC now suppresses the sending of (most) link protocol messages to a neighboring node while it is cleaning up after an earlier loss of contact with that node. This stops the peer node from prematurely activating its link endpoint, which would prevent TIPC from later activating its own end. TIPC still allows outgoing RESET messages to occur during cleanup, to avoid problems if its own node recognizes the loss of contact first and tries to notify the peer of the situation. Finally, TIPC now recognizes an impending loss of contact with a peer node as soon as it receives a RESET message on a working link that is the peer's only link to the node, and ensures that the link protocol suppression mentioned above goes into effect right away -- that is, even before its own link endpoints have failed. This is necessary to ensure correct operation when there are redundant links between the nodes, since otherwise TIPC would send an ACTIVATE message upon receiving a RESET on its first link and only begin suppressing when a RESET on its second link was received, instead of initiating suppression with the first RESET message as it needs to. Note: The reworked cleanup code also eliminates a check that prevented a link endpoint's discovery object from responding to incoming messages while stale name table entries are being purged. This check is now unnecessary and would have slowed down re-establishment of communication between the nodes in some situations. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/discover.c | 6 ------ net/tipc/link.c | 37 ++++++++++++++++++++++++++++++------- net/tipc/node.c | 11 ++++++----- net/tipc/node.h | 10 ++++++++-- 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 0987933155b9..f2fb96e86ee8 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -159,12 +159,6 @@ void tipc_disc_recv_msg(struct sk_buff *buf, struct tipc_bearer *b_ptr) } tipc_node_lock(n_ptr); - /* Don't talk to neighbor during cleanup after last session */ - if (n_ptr->cleanup_required) { - tipc_node_unlock(n_ptr); - return; - } - link = n_ptr->links[b_ptr->identity]; /* Create a link endpoint for this bearer, if necessary */ diff --git a/net/tipc/link.c b/net/tipc/link.c index bc655f456495..74126db45972 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1669,13 +1669,6 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) goto cont; tipc_node_lock(n_ptr); - /* Don't talk to neighbor during cleanup after last session */ - - if (n_ptr->cleanup_required) { - tipc_node_unlock(n_ptr); - goto cont; - } - /* Locate unicast link endpoint that should handle message */ l_ptr = n_ptr->links[b_ptr->identity]; @@ -1684,6 +1677,20 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr) goto cont; } + /* Verify that communication with node is currently allowed */ + + if ((n_ptr->block_setup & WAIT_PEER_DOWN) && + msg_user(msg) == LINK_PROTOCOL && + (msg_type(msg) == RESET_MSG || + msg_type(msg) == ACTIVATE_MSG) && + !msg_redundant_link(msg)) + n_ptr->block_setup &= ~WAIT_PEER_DOWN; + + if (n_ptr->block_setup) { + tipc_node_unlock(n_ptr); + goto cont; + } + /* Validate message sequence number info */ seq_no = msg_seqno(msg); @@ -1914,6 +1921,12 @@ void tipc_link_send_proto_msg(struct link *l_ptr, u32 msg_typ, int probe_msg, if (link_blocked(l_ptr)) return; + + /* Abort non-RESET send if communication with node is prohibited */ + + if ((l_ptr->owner->block_setup) && (msg_typ != RESET_MSG)) + return; + msg_set_type(msg, msg_typ); msg_set_net_plane(msg, l_ptr->b_ptr->net_plane); msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in)); @@ -2045,6 +2058,16 @@ static void link_recv_proto_msg(struct link *l_ptr, struct sk_buff *buf) if (less_eq(msg_session(msg), l_ptr->peer_session)) break; /* duplicate or old reset: ignore */ } + + if (!msg_redundant_link(msg) && (link_working_working(l_ptr) || + link_working_unknown(l_ptr))) { + /* + * peer has lost contact -- don't allow peer's links + * to reactivate before we recognize loss & clean up + */ + l_ptr->owner->block_setup = WAIT_NODE_DOWN; + } + /* fall thru' */ case ACTIVATE_MSG: /* Update link settings according other endpoint's values */ diff --git a/net/tipc/node.c b/net/tipc/node.c index d75432f5e726..27b4bb0cca6c 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -112,6 +112,7 @@ struct tipc_node *tipc_node_create(u32 addr) break; } list_add_tail(&n_ptr->list, &temp_node->list); + n_ptr->block_setup = WAIT_PEER_DOWN; tipc_num_nodes++; @@ -312,7 +313,7 @@ static void node_established_contact(struct tipc_node *n_ptr) } } -static void node_cleanup_finished(unsigned long node_addr) +static void node_name_purge_complete(unsigned long node_addr) { struct tipc_node *n_ptr; @@ -320,7 +321,7 @@ static void node_cleanup_finished(unsigned long node_addr) n_ptr = tipc_node_find(node_addr); if (n_ptr) { tipc_node_lock(n_ptr); - n_ptr->cleanup_required = 0; + n_ptr->block_setup &= ~WAIT_NAMES_GONE; tipc_node_unlock(n_ptr); } read_unlock_bh(&tipc_net_lock); @@ -371,10 +372,10 @@ static void node_lost_contact(struct tipc_node *n_ptr) /* Notify subscribers */ tipc_nodesub_notify(n_ptr); - /* Prevent re-contact with node until all cleanup is done */ + /* Prevent re-contact with node until cleanup is done */ - n_ptr->cleanup_required = 1; - tipc_k_signal((Handler)node_cleanup_finished, n_ptr->addr); + n_ptr->block_setup = WAIT_PEER_DOWN | WAIT_NAMES_GONE; + tipc_k_signal((Handler)node_name_purge_complete, n_ptr->addr); } struct sk_buff *tipc_node_get_nodes(const void *req_tlv_area, int req_tlv_space) diff --git a/net/tipc/node.h b/net/tipc/node.h index 5c61afc7a0b9..4f15cb40aaa4 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -42,6 +42,12 @@ #include "net.h" #include "bearer.h" +/* Flags used to block (re)establishment of contact with a neighboring node */ + +#define WAIT_PEER_DOWN 0x0001 /* wait to see that peer's links are down */ +#define WAIT_NAMES_GONE 0x0002 /* wait for peer's publications to be purged */ +#define WAIT_NODE_DOWN 0x0004 /* wait until peer node is declared down */ + /** * struct tipc_node - TIPC node structure * @addr: network address of node @@ -52,7 +58,7 @@ * @active_links: pointers to active links to node * @links: pointers to all links to node * @working_links: number of working links to node (both active and standby) - * @cleanup_required: non-zero if cleaning up after a prior loss of contact + * @block_setup: bit mask of conditions preventing link establishment to node * @link_cnt: number of links to node * @permit_changeover: non-zero if node has redundant links to this system * @bclink: broadcast-related info @@ -77,7 +83,7 @@ struct tipc_node { struct link *links[MAX_BEARERS]; int link_cnt; int working_links; - int cleanup_required; + int block_setup; int permit_changeover; struct { int supported; From bcd326e844c46e0533a79f91e75dea160469cf86 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 27 May 2011 13:59:17 -0400 Subject: [PATCH 19/28] tipc: Fix unsafe device list search when enabling bearer Ensures that the device list lock is held while trying to locate the Ethernet device used by a newly enabled bearer, so that the addition or removal of a device does not cause problems. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/eth_media.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index b69092eb95d8..69bedd8a297b 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -2,7 +2,7 @@ * net/tipc/eth_media.c: Ethernet bearer support for TIPC * * Copyright (c) 2001-2007, Ericsson AB - * Copyright (c) 2005-2007, Wind River Systems + * Copyright (c) 2005-2008, 2011, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -144,12 +144,15 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) /* Find device with specified name */ + read_lock(&dev_base_lock); for_each_netdev(&init_net, pdev) { if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) { dev = pdev; + dev_hold(dev); break; } } + read_unlock(&dev_base_lock); if (!dev) return -ENODEV; @@ -166,7 +169,6 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) eb_ptr->tipc_packet_type.func = recv_msg; eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); - dev_hold(dev); dev_add_pack(&eb_ptr->tipc_packet_type); } From 18abf0fb6b8f05be2a289abbbc054d4869281476 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 27 May 2011 14:02:48 -0400 Subject: [PATCH 20/28] tipc: Remove redundant search when enabling bearer Removes obsolete code that searches for an Ethernet bearer structure entry to use for a newly enabled bearer, since this search is now performed at the start of the enabling algorithm. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/eth_media.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 69bedd8a297b..413b33742a99 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -156,21 +156,15 @@ static int enable_bearer(struct tipc_bearer *tb_ptr) if (!dev) return -ENODEV; - /* Find Ethernet bearer for device (or create one) */ + /* Create Ethernet bearer for device */ - while ((eb_ptr != stop) && eb_ptr->dev && (eb_ptr->dev != dev)) - eb_ptr++; - if (eb_ptr == stop) - return -EDQUOT; - if (!eb_ptr->dev) { - eb_ptr->dev = dev; - eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); - eb_ptr->tipc_packet_type.dev = dev; - eb_ptr->tipc_packet_type.func = recv_msg; - eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; - INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); - dev_add_pack(&eb_ptr->tipc_packet_type); - } + eb_ptr->dev = dev; + eb_ptr->tipc_packet_type.type = htons(ETH_P_TIPC); + eb_ptr->tipc_packet_type.dev = dev; + eb_ptr->tipc_packet_type.func = recv_msg; + eb_ptr->tipc_packet_type.af_packet_priv = eb_ptr; + INIT_LIST_HEAD(&(eb_ptr->tipc_packet_type.list)); + dev_add_pack(&eb_ptr->tipc_packet_type); /* Associate TIPC bearer with Ethernet bearer */ From 909234cdd2b5954374e346c105b648f6c2800f55 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Fri, 27 May 2011 15:09:40 -0400 Subject: [PATCH 21/28] tipc: Lower limits for number of bearers and media types Reduces the number of bearers a node can support to 2, which can use identical or non-identical media. This change won't impact users, since they are currently limited to a maximum of 2 Ethernet bearers, and will save memory by eliminating a number of unused entries in TIPC's media and bearer arrays. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/bearer.h | 4 ++-- net/tipc/eth_media.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index 5ad70eff1ebf..d696f9e414e3 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -39,8 +39,8 @@ #include "bcast.h" -#define MAX_BEARERS 8 -#define MAX_MEDIA 4 +#define MAX_BEARERS 2 +#define MAX_MEDIA 2 /* * Identifiers of supported TIPC media types diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index 413b33742a99..e728d4ce2a1b 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -37,7 +37,7 @@ #include "core.h" #include "bearer.h" -#define MAX_ETH_BEARERS 2 +#define MAX_ETH_BEARERS MAX_BEARERS #define ETH_LINK_PRIORITY TIPC_DEF_LINK_PRI #define ETH_LINK_TOLERANCE TIPC_DEF_LINK_TOL #define ETH_LINK_WINDOW TIPC_DEF_LINK_WIN From 149ce37c8de72c64fc4f66c1b4cf7a0fb66b7ee9 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 31 May 2011 11:05:02 -0400 Subject: [PATCH 22/28] tipc: Prevent fragmented messages during initial name table exchange Reduces the maximum size of messages sent during the initial exchange of name table information between two nodes to be no larger than the MTU of the first link established between the nodes. This ensures that messages will never need to be fragmented, which would add unnecessary overhead to the name table synchronization mechanism. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/name_distr.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index cd356e504332..21bc0281ec89 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -175,16 +175,32 @@ void tipc_named_withdraw(struct publication *publ) void tipc_named_node_up(unsigned long node) { + struct tipc_node *n_ptr; + struct link *l_ptr; struct publication *publ; struct distr_item *item = NULL; struct sk_buff *buf = NULL; u32 left = 0; u32 rest; - u32 max_item_buf; + u32 max_item_buf = 0; + + /* compute maximum amount of publication data to send per message */ + + read_lock_bh(&tipc_net_lock); + n_ptr = tipc_node_find((u32)node); + if (n_ptr) { + tipc_node_lock(n_ptr); + l_ptr = n_ptr->active_links[0]; + if (l_ptr) + max_item_buf = ((l_ptr->max_pkt - INT_H_SIZE) / + ITEM_SIZE) * ITEM_SIZE; + tipc_node_unlock(n_ptr); + } + read_unlock_bh(&tipc_net_lock); + if (!max_item_buf) + return; read_lock_bh(&tipc_nametbl_lock); - max_item_buf = TIPC_MAX_USER_MSG_SIZE / ITEM_SIZE; - max_item_buf *= ITEM_SIZE; rest = publ_cnt * ITEM_SIZE; list_for_each_entry(publ, &publ_root, local_list) { From 1c553bb52eb4c58333a843c0a5888d2329909f62 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Fri, 2 Sep 2011 13:45:34 -0400 Subject: [PATCH 23/28] tipc: relocate/coalesce node cast in tipc_named_node_up Functions like this are called using unsigned longs from function pointers. In this case, the function is passed in a node which is normally internally treated as a u32 by TIPC. Rather than add more casts into this function in the future for each added use of node within, move the cast to a single place on a local. Signed-off-by: Paul Gortmaker --- net/tipc/name_distr.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 21bc0281ec89..97546f07938c 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -173,13 +173,14 @@ void tipc_named_withdraw(struct publication *publ) * tipc_named_node_up - tell specified node about all publications by this node */ -void tipc_named_node_up(unsigned long node) +void tipc_named_node_up(unsigned long nodearg) { struct tipc_node *n_ptr; struct link *l_ptr; struct publication *publ; struct distr_item *item = NULL; struct sk_buff *buf = NULL; + u32 node = (u32)nodearg; u32 left = 0; u32 rest; u32 max_item_buf = 0; @@ -187,7 +188,7 @@ void tipc_named_node_up(unsigned long node) /* compute maximum amount of publication data to send per message */ read_lock_bh(&tipc_net_lock); - n_ptr = tipc_node_find((u32)node); + n_ptr = tipc_node_find(node); if (n_ptr) { tipc_node_lock(n_ptr); l_ptr = n_ptr->active_links[0]; From 9aa88c2a509e11e6efc466c88b386e0e01bef731 Mon Sep 17 00:00:00 2001 From: Allan Stephens Date: Tue, 31 May 2011 13:38:02 -0400 Subject: [PATCH 24/28] tipc: Enhance sending of bulk name table messages Modifies the initial transfer of name table entries to a new neighboring node so that the messages are enqueued as a unit, rather than individually. The revised algorithm now locates the link carrying the message only once, and eliminates unnecessary checks for link congestion, message fragmentation, and message bundling that are not required when sending these messages. Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/link.c | 45 +++++++++++++++++++++++++++++++++++++++++++ net/tipc/link.h | 1 + net/tipc/name_distr.c | 10 ++++++++-- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 74126db45972..2ea3f22b7986 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -985,6 +985,51 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector) return res; } +/* + * tipc_link_send_names - send name table entries to new neighbor + * + * Send routine for bulk delivery of name table messages when contact + * with a new neighbor occurs. No link congestion checking is performed + * because name table messages *must* be delivered. The messages must be + * small enough not to require fragmentation. + * Called without any locks held. + */ + +void tipc_link_send_names(struct list_head *message_list, u32 dest) +{ + struct tipc_node *n_ptr; + struct link *l_ptr; + struct sk_buff *buf; + struct sk_buff *temp_buf; + + if (list_empty(message_list)) + return; + + read_lock_bh(&tipc_net_lock); + n_ptr = tipc_node_find(dest); + if (n_ptr) { + tipc_node_lock(n_ptr); + l_ptr = n_ptr->active_links[0]; + if (l_ptr) { + /* convert circular list to linear list */ + ((struct sk_buff *)message_list->prev)->next = NULL; + link_add_chain_to_outqueue(l_ptr, + (struct sk_buff *)message_list->next, 0); + tipc_link_push_queue(l_ptr); + INIT_LIST_HEAD(message_list); + } + tipc_node_unlock(n_ptr); + } + read_unlock_bh(&tipc_net_lock); + + /* discard the messages if they couldn't be sent */ + + list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) { + list_del((struct list_head *)buf); + buf_discard(buf); + } +} + /* * link_send_buf_fast: Entry for data messages where the * destination link is known and the header is complete, diff --git a/net/tipc/link.h b/net/tipc/link.h index 74fbecab1ea0..e56cb532913e 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -223,6 +223,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_s struct sk_buff *tipc_link_cmd_reset_stats(const void *req_tlv_area, int req_tlv_space); void tipc_link_reset(struct link *l_ptr); int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector); +void tipc_link_send_names(struct list_head *message_list, u32 dest); int tipc_link_send_buf(struct link *l_ptr, struct sk_buff *buf); u32 tipc_link_get_max_pkt(u32 dest, u32 selector); int tipc_link_send_sections_fast(struct tipc_port *sender, diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 97546f07938c..b7ca1bd7b151 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -180,6 +180,7 @@ void tipc_named_node_up(unsigned long nodearg) struct publication *publ; struct distr_item *item = NULL; struct sk_buff *buf = NULL; + struct list_head message_list; u32 node = (u32)nodearg; u32 left = 0; u32 rest; @@ -201,6 +202,10 @@ void tipc_named_node_up(unsigned long nodearg) if (!max_item_buf) return; + /* create list of publication messages, then send them as a unit */ + + INIT_LIST_HEAD(&message_list); + read_lock_bh(&tipc_nametbl_lock); rest = publ_cnt * ITEM_SIZE; @@ -219,13 +224,14 @@ void tipc_named_node_up(unsigned long nodearg) item++; left -= ITEM_SIZE; if (!left) { - msg_set_link_selector(buf_msg(buf), node); - tipc_link_send(buf, node, node); + list_add_tail((struct list_head *)buf, &message_list); buf = NULL; } } exit: read_unlock_bh(&tipc_nametbl_lock); + + tipc_link_send_names(&message_list, (u32)node); } /** From 1d835874af143a5c8273268d09e2f259b4c1ba89 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Wed, 6 Jul 2011 05:53:15 -0400 Subject: [PATCH 25/28] tipc: Add support for SO_SNDTIMEO socket option Adds support for the SO_SNDTIMEO socket option. (This complements the existing support for SO_RCVTIMEO that is already present.) Signed-off-by: Ying Xue Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/socket.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index fc3c281c127d..2f90beba282b 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -525,6 +525,7 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, struct tipc_port *tport = tipc_sk_port(sk); struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; int needs_conn; + long timeout_val; int res = -EINVAL; if (unlikely(!dest)) @@ -564,6 +565,8 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, reject_rx_queue(sk); } + timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); + do { if (dest->addrtype == TIPC_ADDR_NAME) { res = dest_name_check(dest, m); @@ -600,16 +603,14 @@ static int send_msg(struct kiocb *iocb, struct socket *sock, sock->state = SS_CONNECTING; break; } - if (m->msg_flags & MSG_DONTWAIT) { - res = -EWOULDBLOCK; + if (timeout_val <= 0L) { + res = timeout_val ? timeout_val : -EWOULDBLOCK; break; } release_sock(sk); - res = wait_event_interruptible(*sk_sleep(sk), - !tport->congested); + timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), + !tport->congested, timeout_val); lock_sock(sk); - if (res) - break; } while (1); exit: @@ -636,6 +637,7 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, struct sock *sk = sock->sk; struct tipc_port *tport = tipc_sk_port(sk); struct sockaddr_tipc *dest = (struct sockaddr_tipc *)m->msg_name; + long timeout_val; int res; /* Handle implied connection establishment */ @@ -650,6 +652,8 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, if (iocb) lock_sock(sk); + timeout_val = sock_sndtimeo(sk, m->msg_flags & MSG_DONTWAIT); + do { if (unlikely(sock->state != SS_CONNECTED)) { if (sock->state == SS_DISCONNECTING) @@ -663,16 +667,14 @@ static int send_packet(struct kiocb *iocb, struct socket *sock, total_len); if (likely(res != -ELINKCONG)) break; - if (m->msg_flags & MSG_DONTWAIT) { - res = -EWOULDBLOCK; + if (timeout_val <= 0L) { + res = timeout_val ? timeout_val : -EWOULDBLOCK; break; } release_sock(sk); - res = wait_event_interruptible(*sk_sleep(sk), - (!tport->congested || !tport->connected)); + timeout_val = wait_event_interruptible_timeout(*sk_sleep(sk), + (!tport->congested || !tport->connected), timeout_val); lock_sock(sk); - if (res) - break; } while (1); if (iocb) From 245f3d342dccad293d0cd0bbe231051b2daa695f Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Wed, 6 Jul 2011 06:01:13 -0400 Subject: [PATCH 26/28] tipc: Simplify prohibition of listen and accept for connectionless sockets Modifies the proto_ops structure used by TIPC DGRAM and RDM sockets so that calls to listen() and accept() are handled by existing kernel "unsupported operation" routines, and eliminates the related checks in the listen and accept routines used by SEQPACKET and STREAM sockets that are no longer needed. Signed-off-by: Ying Xue Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/socket.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 2f90beba282b..9440a3d48ca0 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1483,9 +1483,7 @@ static int listen(struct socket *sock, int len) lock_sock(sk); - if (sock->state == SS_READY) - res = -EOPNOTSUPP; - else if (sock->state != SS_UNCONNECTED) + if (sock->state != SS_UNCONNECTED) res = -EINVAL; else { sock->state = SS_LISTENING; @@ -1513,10 +1511,6 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) lock_sock(sk); - if (sock->state == SS_READY) { - res = -EOPNOTSUPP; - goto exit; - } if (sock->state != SS_LISTENING) { res = -EINVAL; goto exit; @@ -1793,11 +1787,11 @@ static const struct proto_ops msg_ops = { .bind = bind, .connect = connect, .socketpair = sock_no_socketpair, - .accept = accept, + .accept = sock_no_accept, .getname = get_name, .poll = poll, .ioctl = sock_no_ioctl, - .listen = listen, + .listen = sock_no_listen, .shutdown = shutdown, .setsockopt = setsockopt, .getsockopt = getsockopt, From 7e2447763c28b8b67af67e757508c1a05c2c85b9 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Tue, 19 Jul 2011 04:21:56 -0400 Subject: [PATCH 27/28] tipc: Remove callback field from subscription structure Eliminate the "event_cb" member from TIPC's "subscription" structure since the function pointer it holds always points to subscr_send_event(). Signed-off-by: Ying Xue Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/subscr.c | 3 +-- net/tipc/subscr.h | 6 ------ 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c index 6cf726863485..198371723b41 100644 --- a/net/tipc/subscr.c +++ b/net/tipc/subscr.c @@ -151,7 +151,7 @@ void tipc_subscr_report_overlap(struct subscription *sub, if (!must && !(sub->filter & TIPC_SUB_PORTS)) return; - sub->event_cb(sub, found_lower, found_upper, event, port_ref, node); + subscr_send_event(sub, found_lower, found_upper, event, port_ref, node); } /** @@ -365,7 +365,6 @@ static struct subscription *subscr_subscribe(struct tipc_subscr *s, subscr_terminate(subscriber); return NULL; } - sub->event_cb = subscr_send_event; INIT_LIST_HEAD(&sub->nameseq_list); list_add(&sub->subscription_list, &subscriber->subscription_list); sub->server_ref = subscriber->port_ref; diff --git a/net/tipc/subscr.h b/net/tipc/subscr.h index 45d89bf4d202..4b06ef6f8401 100644 --- a/net/tipc/subscr.h +++ b/net/tipc/subscr.h @@ -39,16 +39,11 @@ struct subscription; -typedef void (*tipc_subscr_event) (struct subscription *sub, - u32 found_lower, u32 found_upper, - u32 event, u32 port_ref, u32 node); - /** * struct subscription - TIPC network topology subscription object * @seq: name sequence associated with subscription * @timeout: duration of subscription (in ms) * @filter: event filtering to be done for subscription - * @event_cb: routine invoked when a subscription event is detected * @timer: timer governing subscription duration (optional) * @nameseq_list: adjacent subscriptions in name sequence's subscription list * @subscription_list: adjacent subscriptions in subscriber's subscription list @@ -61,7 +56,6 @@ struct subscription { struct tipc_name_seq seq; u32 timeout; u32 filter; - tipc_subscr_event event_cb; struct timer_list timer; struct list_head nameseq_list; struct list_head subscription_list; From 94362c7e49b2eccf9fe86112b8090939aa2f5355 Mon Sep 17 00:00:00 2001 From: Ying Xue Date: Mon, 8 Aug 2011 22:45:27 -0400 Subject: [PATCH 28/28] tipc: Remove unused link event tracking code Elimintes prototype link event tracking functionality that has never been fleshed out and doesn't do anything useful at the current time. Signed-off-by: Ying Xue Signed-off-by: Allan Stephens Signed-off-by: Paul Gortmaker --- net/tipc/config.h | 1 - net/tipc/link.c | 10 ---------- 2 files changed, 11 deletions(-) diff --git a/net/tipc/config.h b/net/tipc/config.h index 443159a166fd..80da6ebc2785 100644 --- a/net/tipc/config.h +++ b/net/tipc/config.h @@ -65,7 +65,6 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *req_tlv_area, int req_tlv_space, int headroom); -void tipc_cfg_link_event(u32 addr, char *name, int up); int tipc_cfg_init(void); void tipc_cfg_stop(void); diff --git a/net/tipc/link.c b/net/tipc/link.c index 2ea3f22b7986..ae98a72da11a 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -537,9 +537,6 @@ void tipc_link_stop(struct link *l_ptr) l_ptr->proto_msg_queue = NULL; } -/* LINK EVENT CODE IS NOT SUPPORTED AT PRESENT */ -#define link_send_event(fcn, l_ptr, up) do { } while (0) - void tipc_link_reset(struct link *l_ptr) { struct sk_buff *buf; @@ -597,10 +594,6 @@ void tipc_link_reset(struct link *l_ptr) l_ptr->fsm_msg_cnt = 0; l_ptr->stale_count = 0; link_reset_statistics(l_ptr); - - link_send_event(tipc_cfg_link_event, l_ptr, 0); - if (!in_own_cluster(l_ptr->addr)) - link_send_event(tipc_disc_link_event, l_ptr, 0); } @@ -609,9 +602,6 @@ static void link_activate(struct link *l_ptr) l_ptr->next_in_no = l_ptr->stats.recv_info = 1; tipc_node_link_up(l_ptr->owner, l_ptr); tipc_bearer_add_dest(l_ptr->b_ptr, l_ptr->addr); - link_send_event(tipc_cfg_link_event, l_ptr, 1); - if (!in_own_cluster(l_ptr->addr)) - link_send_event(tipc_disc_link_event, l_ptr, 1); } /**