diff mbox

neigh: error out pending skbs if netlink invalidates incomplete neigh

Message ID 1244104855-2129-1-git-send-email-timo.teras@iki.fi
State Rejected, archived
Delegated to: David Miller
Headers show

Commit Message

Timo Teras June 4, 2009, 8:40 a.m. UTC
The state transition code from incomplete to invalid via neigh_update()
is missing the proper clean up of skb queue. Separate the clean up
code from neigh_timer_handler() to a new function and make neigh_update()
is it also.

Signed-off-by: Timo Teras <timo.teras@iki.fi>
---
 net/core/neighbour.c |   46 ++++++++++++++++++++++++++++------------------
 1 files changed, 28 insertions(+), 18 deletions(-)

Comments

David Miller June 11, 2009, 10:02 a.m. UTC | #1
From: Timo Teras <timo.teras@iki.fi>
Date: Thu,  4 Jun 2009 11:40:55 +0300

> The state transition code from incomplete to invalid via neigh_update()
> is missing the proper clean up of skb queue. Separate the clean up
> code from neigh_timer_handler() to a new function and make neigh_update()
> is it also.
> 
> Signed-off-by: Timo Teras <timo.teras@iki.fi>

We don't error out pending SKBs on the state transition alone, we do
it when we have the state transition _AND_ the number of probes
exceeds the limit.

And it seems that behavior is very much intentional.

I'm not going to apply this.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Timo Teras June 11, 2009, 10:08 a.m. UTC | #2
David Miller wrote:
> From: Timo Teras <timo.teras@iki.fi>
> Date: Thu,  4 Jun 2009 11:40:55 +0300
> 
>> The state transition code from incomplete to invalid via neigh_update()
>> is missing the proper clean up of skb queue. Separate the clean up
>> code from neigh_timer_handler() to a new function and make neigh_update()
>> is it also.
>>
>> Signed-off-by: Timo Teras <timo.teras@iki.fi>
> 
> We don't error out pending SKBs on the state transition alone, we do
> it when we have the state transition _AND_ the number of probes
> exceeds the limit.
> 
> And it seems that behavior is very much intentional.
> 
> I'm not going to apply this.

When the state is changed to FAILED by netlink, the timer is stopped
and further probes are not tried anymore. This results in that the
skb's are not errored. The neigh entry is left stale.

The behaviour is flawed currently. Either we need to prevent state
change from INCOMPLETE -> FAILED via netlink and keep on sending probes,
or flush the queue when userland replies with FAILED. Otherwise the
neigh entry state is left bad.

- Timo

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller June 11, 2009, 10:12 a.m. UTC | #3
From: Timo Teräs <timo.teras@iki.fi>
Date: Thu, 11 Jun 2009 13:08:01 +0300

> When the state is changed to FAILED by netlink, the timer is stopped
> and further probes are not tried anymore. This results in that the
> skb's are not errored. The neigh entry is left stale.
> 
> The behaviour is flawed currently. Either we need to prevent state
> change from INCOMPLETE -> FAILED via netlink and keep on sending
> probes,
> or flush the queue when userland replies with FAILED. Otherwise the
> neigh entry state is left bad.

Thanks for the explanation, yes this is a problem.

Can you add a little bit more verbosity to your commit message
so that this issue is clearly explained and resubmit your patch?

Thank you!
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index a1cbce7..a17cb9d 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -771,6 +771,28 @@  static __inline__ int neigh_max_probes(struct neighbour *n)
 		p->ucast_probes + p->app_probes + p->mcast_probes);
 }
 
+static void neigh_invalidate(struct neighbour *neigh)
+{
+	struct sk_buff *skb;
+
+	NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
+	NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
+	neigh->updated = jiffies;
+
+	/* It is very thin place. report_unreachable is very complicated
+	   routine. Particularly, it can hit the same neighbour entry!
+
+	   So that, we try to be accurate and avoid dead loop. --ANK
+	 */
+	while (neigh->nud_state == NUD_FAILED &&
+	       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
+		write_unlock(&neigh->lock);
+		neigh->ops->error_report(neigh, skb);
+		write_lock(&neigh->lock);
+	}
+	skb_queue_purge(&neigh->arp_queue);
+}
+
 /* Called when a timer expires for a neighbour entry. */
 
 static void neigh_timer_handler(unsigned long arg)
@@ -835,26 +857,9 @@  static void neigh_timer_handler(unsigned long arg)
 
 	if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) &&
 	    atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) {
-		struct sk_buff *skb;
-
 		neigh->nud_state = NUD_FAILED;
-		neigh->updated = jiffies;
 		notify = 1;
-		NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed);
-		NEIGH_PRINTK2("neigh %p is failed.\n", neigh);
-
-		/* It is very thin place. report_unreachable is very complicated
-		   routine. Particularly, it can hit the same neighbour entry!
-
-		   So that, we try to be accurate and avoid dead loop. --ANK
-		 */
-		while (neigh->nud_state == NUD_FAILED &&
-		       (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
-			write_unlock(&neigh->lock);
-			neigh->ops->error_report(neigh, skb);
-			write_lock(&neigh->lock);
-		}
-		skb_queue_purge(&neigh->arp_queue);
+		neigh_invalidate(neigh);
 	}
 
 	if (neigh->nud_state & NUD_IN_TIMER) {
@@ -1001,6 +1006,11 @@  int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new,
 		neigh->nud_state = new;
 		err = 0;
 		notify = old & NUD_VALID;
+		if ((old & (NUD_INCOMPLETE | NUD_PROBE)) &&
+		    (new & NUD_FAILED)) {
+			neigh_invalidate(neigh);
+			notify = 1;
+		}
 		goto out;
 	}