Commit d356eeba authored by Allan Stephens's avatar Allan Stephens Committed by David S. Miller

[TIPC]: Multicast link failure now resets all links to "nacking" node.

This fix prevents node from crashing.
Signed-off-by: default avatarAllan Stephens <allan.stephens@windriver.com>
Signed-off-by: default avatarPer Liden <per.liden@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 26008247
...@@ -49,13 +49,19 @@ ...@@ -49,13 +49,19 @@
#include "name_table.h" #include "name_table.h"
#include "bcast.h" #include "bcast.h"
#define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */ #define MAX_PKT_DEFAULT_MCAST 1500 /* bcast link max packet size (fixed) */
#define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */ #define BCLINK_WIN_DEFAULT 20 /* bcast link window size (default) */
#define BCLINK_LOG_BUF_SIZE 0 #define BCLINK_LOG_BUF_SIZE 0
/*
* Loss rate for incoming broadcast frames; used to test retransmission code.
* Set to N to cause every N'th frame to be discarded; 0 => don't discard any.
*/
#define TIPC_BCAST_LOSS_RATE 0
/** /**
* struct bcbearer_pair - a pair of bearers used by broadcast link * struct bcbearer_pair - a pair of bearers used by broadcast link
* @primary: pointer to primary bearer * @primary: pointer to primary bearer
...@@ -165,21 +171,18 @@ static int bclink_ack_allowed(u32 n) ...@@ -165,21 +171,18 @@ static int bclink_ack_allowed(u32 n)
* @after: sequence number of last packet to *not* retransmit * @after: sequence number of last packet to *not* retransmit
* @to: sequence number of last packet to retransmit * @to: sequence number of last packet to retransmit
* *
* Called with 'node' locked, bc_lock unlocked * Called with bc_lock locked
*/ */
static void bclink_retransmit_pkt(u32 after, u32 to) static void bclink_retransmit_pkt(u32 after, u32 to)
{ {
struct sk_buff *buf; struct sk_buff *buf;
spin_lock_bh(&bc_lock);
buf = bcl->first_out; buf = bcl->first_out;
while (buf && less_eq(buf_seqno(buf), after)) { while (buf && less_eq(buf_seqno(buf), after)) {
buf = buf->next; buf = buf->next;
} }
if (buf != NULL)
tipc_link_retransmit(bcl, buf, mod(to - after)); tipc_link_retransmit(bcl, buf, mod(to - after));
spin_unlock_bh(&bc_lock);
} }
/** /**
...@@ -400,6 +403,9 @@ int tipc_bclink_send_msg(struct sk_buff *buf) ...@@ -400,6 +403,9 @@ int tipc_bclink_send_msg(struct sk_buff *buf)
void tipc_bclink_recv_pkt(struct sk_buff *buf) void tipc_bclink_recv_pkt(struct sk_buff *buf)
{ {
#if (TIPC_BCAST_LOSS_RATE)
static int rx_count = 0;
#endif
struct tipc_msg *msg = buf_msg(buf); struct tipc_msg *msg = buf_msg(buf);
struct node* node = tipc_node_find(msg_prevnode(msg)); struct node* node = tipc_node_find(msg_prevnode(msg));
u32 next_in; u32 next_in;
...@@ -420,9 +426,13 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) ...@@ -420,9 +426,13 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
tipc_node_lock(node); tipc_node_lock(node);
tipc_bclink_acknowledge(node, msg_bcast_ack(msg)); tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
tipc_node_unlock(node); tipc_node_unlock(node);
spin_lock_bh(&bc_lock);
bcl->stats.recv_nacks++; bcl->stats.recv_nacks++;
bcl->owner->next = node; /* remember requestor */
bclink_retransmit_pkt(msg_bcgap_after(msg), bclink_retransmit_pkt(msg_bcgap_after(msg),
msg_bcgap_to(msg)); msg_bcgap_to(msg));
bcl->owner->next = NULL;
spin_unlock_bh(&bc_lock);
} else { } else {
tipc_bclink_peek_nack(msg_destnode(msg), tipc_bclink_peek_nack(msg_destnode(msg),
msg_bcast_tag(msg), msg_bcast_tag(msg),
...@@ -433,6 +443,14 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf) ...@@ -433,6 +443,14 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
return; return;
} }
#if (TIPC_BCAST_LOSS_RATE)
if (++rx_count == TIPC_BCAST_LOSS_RATE) {
rx_count = 0;
buf_discard(buf);
return;
}
#endif
tipc_node_lock(node); tipc_node_lock(node);
receive: receive:
deferred = node->bclink.deferred_head; deferred = node->bclink.deferred_head;
......
...@@ -1604,40 +1604,121 @@ void tipc_link_push_queue(struct link *l_ptr) ...@@ -1604,40 +1604,121 @@ void tipc_link_push_queue(struct link *l_ptr)
tipc_bearer_schedule(l_ptr->b_ptr, l_ptr); tipc_bearer_schedule(l_ptr->b_ptr, l_ptr);
} }
static void link_reset_all(unsigned long addr)
{
struct node *n_ptr;
char addr_string[16];
u32 i;
read_lock_bh(&tipc_net_lock);
n_ptr = tipc_node_find((u32)addr);
if (!n_ptr) {
read_unlock_bh(&tipc_net_lock);
return; /* node no longer exists */
}
tipc_node_lock(n_ptr);
warn("Resetting all links to %s\n",
addr_string_fill(addr_string, n_ptr->addr));
for (i = 0; i < MAX_BEARERS; i++) {
if (n_ptr->links[i]) {
link_print(n_ptr->links[i], TIPC_OUTPUT,
"Resetting link\n");
tipc_link_reset(n_ptr->links[i]);
}
}
tipc_node_unlock(n_ptr);
read_unlock_bh(&tipc_net_lock);
}
static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
warn("Retransmission failure on link <%s>\n", l_ptr->name);
tipc_msg_print(TIPC_OUTPUT, msg, ">RETR-FAIL>");
if (l_ptr->addr) {
/* Handle failure on standard link */
link_print(l_ptr, TIPC_OUTPUT, "Resetting link\n");
tipc_link_reset(l_ptr);
} else {
/* Handle failure on broadcast link */
struct node *n_ptr;
char addr_string[16];
tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg));
tipc_printf(TIPC_OUTPUT, "Outstanding acks: %u\n", (u32)TIPC_SKB_CB(buf)->handle);
n_ptr = l_ptr->owner->next;
tipc_node_lock(n_ptr);
addr_string_fill(addr_string, n_ptr->addr);
tipc_printf(TIPC_OUTPUT, "Multicast link info for %s\n", addr_string);
tipc_printf(TIPC_OUTPUT, "Supported: %d, ", n_ptr->bclink.supported);
tipc_printf(TIPC_OUTPUT, "Acked: %u\n", n_ptr->bclink.acked);
tipc_printf(TIPC_OUTPUT, "Last in: %u, ", n_ptr->bclink.last_in);
tipc_printf(TIPC_OUTPUT, "Gap after: %u, ", n_ptr->bclink.gap_after);
tipc_printf(TIPC_OUTPUT, "Gap to: %u\n", n_ptr->bclink.gap_to);
tipc_printf(TIPC_OUTPUT, "Nack sync: %u\n\n", n_ptr->bclink.nack_sync);
tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr);
tipc_node_unlock(n_ptr);
l_ptr->stale_count = 0;
}
}
void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf, void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
u32 retransmits) u32 retransmits)
{ {
struct tipc_msg *msg; struct tipc_msg *msg;
if (!buf)
return;
msg = buf_msg(buf);
dbg("Retransmitting %u in link %x\n", retransmits, l_ptr); dbg("Retransmitting %u in link %x\n", retransmits, l_ptr);
if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr) && buf && !skb_cloned(buf)) { if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) {
msg_dbg(buf_msg(buf), ">NO_RETR->BCONG>"); if (!skb_cloned(buf)) {
msg_dbg(msg, ">NO_RETR->BCONG>");
dbg_print_link(l_ptr, " "); dbg_print_link(l_ptr, " ");
l_ptr->retransm_queue_head = msg_seqno(buf_msg(buf)); l_ptr->retransm_queue_head = msg_seqno(msg);
l_ptr->retransm_queue_size = retransmits; l_ptr->retransm_queue_size = retransmits;
return; return;
} else {
/* Don't retransmit if driver already has the buffer */
} }
while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) { } else {
msg = buf_msg(buf); /* Detect repeated retransmit failures on uncongested bearer */
msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
/* Catch if retransmissions fail repeatedly: */
if (l_ptr->last_retransmitted == msg_seqno(msg)) { if (l_ptr->last_retransmitted == msg_seqno(msg)) {
if (++l_ptr->stale_count > 100) { if (++l_ptr->stale_count > 100) {
tipc_msg_print(TIPC_CONS, buf_msg(buf), ">RETR>"); link_retransmit_failure(l_ptr, buf);
info("...Retransmitted %u times\n", return;
l_ptr->stale_count);
link_print(l_ptr, TIPC_CONS, "Resetting Link\n");
tipc_link_reset(l_ptr);
break;
} }
} else { } else {
l_ptr->stale_count = 0;
}
l_ptr->last_retransmitted = msg_seqno(msg); l_ptr->last_retransmitted = msg_seqno(msg);
l_ptr->stale_count = 1;
}
}
while (retransmits && (buf != l_ptr->next_out) && buf && !skb_cloned(buf)) {
msg = buf_msg(buf);
msg_set_ack(msg, mod(l_ptr->next_in_no - 1));
msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);
if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {
msg_dbg(buf_msg(buf), ">RETR>"); msg_dbg(buf_msg(buf), ">RETR>");
buf = buf->next; buf = buf->next;
retransmits--; retransmits--;
...@@ -1650,6 +1731,7 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf, ...@@ -1650,6 +1731,7 @@ void tipc_link_retransmit(struct link *l_ptr, struct sk_buff *buf,
return; return;
} }
} }
l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0; l_ptr->retransm_queue_head = l_ptr->retransm_queue_size = 0;
} }
......
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