aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-02 05:21:03 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-05 04:03:06 -0400
commit5110effee8fde2edfacac9cd12a9960ab2dc39ea (patch)
treef74fff97af20ffdf805fedc56f0c8f88bbef2df7
parent60d354ebebd9d0f760cb6c3b9f53a7ade0f8cd0e (diff)
net: Do delayed neigh confirmation.
When a dst_confirm() happens, mark the confirmation as pending in the dst. Then on the next packet out, when we have the neigh in-hand, do the update. This removes the dependency in dst_confirm() of dst's having an attached neigh. While we're here, remove the explicit 'dst' NULL check, all except 2 or 3 call sites ensure it's not NULL. So just fix those cases up. Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/dst.h29
-rw-r--r--include/net/neighbour.h15
-rw-r--r--net/core/dst.c3
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv4/tcp_input.c19
-rw-r--r--net/ipv6/ip6_output.c2
6 files changed, 38 insertions, 32 deletions
diff --git a/include/net/dst.h b/include/net/dst.h
index f0bf3b8d5911..84e7a3ff968d 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -51,7 +51,7 @@ struct dst_entry {
51 int (*input)(struct sk_buff *); 51 int (*input)(struct sk_buff *);
52 int (*output)(struct sk_buff *); 52 int (*output)(struct sk_buff *);
53 53
54 int flags; 54 unsigned short flags;
55#define DST_HOST 0x0001 55#define DST_HOST 0x0001
56#define DST_NOXFRM 0x0002 56#define DST_NOXFRM 0x0002
57#define DST_NOPOLICY 0x0004 57#define DST_NOPOLICY 0x0004
@@ -62,6 +62,8 @@ struct dst_entry {
62#define DST_FAKE_RTABLE 0x0080 62#define DST_FAKE_RTABLE 0x0080
63#define DST_XFRM_TUNNEL 0x0100 63#define DST_XFRM_TUNNEL 0x0100
64 64
65 unsigned short pending_confirm;
66
65 short error; 67 short error;
66 short obsolete; 68 short obsolete;
67 unsigned short header_len; /* more space at head required */ 69 unsigned short header_len; /* more space at head required */
@@ -371,7 +373,8 @@ static inline struct dst_entry *skb_dst_pop(struct sk_buff *skb)
371 373
372extern int dst_discard(struct sk_buff *skb); 374extern int dst_discard(struct sk_buff *skb);
373extern void *dst_alloc(struct dst_ops *ops, struct net_device *dev, 375extern void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
374 int initial_ref, int initial_obsolete, int flags); 376 int initial_ref, int initial_obsolete,
377 unsigned short flags);
375extern void __dst_free(struct dst_entry *dst); 378extern void __dst_free(struct dst_entry *dst);
376extern struct dst_entry *dst_destroy(struct dst_entry *dst); 379extern struct dst_entry *dst_destroy(struct dst_entry *dst);
377 380
@@ -395,14 +398,24 @@ static inline void dst_rcu_free(struct rcu_head *head)
395 398
396static inline void dst_confirm(struct dst_entry *dst) 399static inline void dst_confirm(struct dst_entry *dst)
397{ 400{
398 if (dst) { 401 dst->pending_confirm = 1;
399 struct neighbour *n; 402}
400 403
401 rcu_read_lock(); 404static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
402 n = dst_get_neighbour_noref(dst); 405 struct sk_buff *skb)
403 neigh_confirm(n); 406{
404 rcu_read_unlock(); 407 struct hh_cache *hh;
408
409 if (unlikely(dst->pending_confirm)) {
410 n->confirmed = jiffies;
411 dst->pending_confirm = 0;
405 } 412 }
413
414 hh = &n->hh;
415 if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
416 return neigh_hh_output(hh, skb);
417 else
418 return n->output(n, skb);
406} 419}
407 420
408static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr) 421static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr)
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index e1d18bdeebb8..344d8988842a 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -309,12 +309,6 @@ static inline struct neighbour * neigh_clone(struct neighbour *neigh)
309 309
310#define neigh_hold(n) atomic_inc(&(n)->refcnt) 310#define neigh_hold(n) atomic_inc(&(n)->refcnt)
311 311
312static inline void neigh_confirm(struct neighbour *neigh)
313{
314 if (neigh)
315 neigh->confirmed = jiffies;
316}
317
318static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) 312static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
319{ 313{
320 unsigned long now = jiffies; 314 unsigned long now = jiffies;
@@ -358,15 +352,6 @@ static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
358 return dev_queue_xmit(skb); 352 return dev_queue_xmit(skb);
359} 353}
360 354
361static inline int neigh_output(struct neighbour *n, struct sk_buff *skb)
362{
363 struct hh_cache *hh = &n->hh;
364 if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
365 return neigh_hh_output(hh, skb);
366 else
367 return n->output(n, skb);
368}
369
370static inline struct neighbour * 355static inline struct neighbour *
371__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) 356__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
372{ 357{
diff --git a/net/core/dst.c b/net/core/dst.c
index 43d94cedbf7c..a6e19a23a745 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -152,7 +152,7 @@ EXPORT_SYMBOL(dst_discard);
152const u32 dst_default_metrics[RTAX_MAX]; 152const u32 dst_default_metrics[RTAX_MAX];
153 153
154void *dst_alloc(struct dst_ops *ops, struct net_device *dev, 154void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
155 int initial_ref, int initial_obsolete, int flags) 155 int initial_ref, int initial_obsolete, unsigned short flags)
156{ 156{
157 struct dst_entry *dst; 157 struct dst_entry *dst;
158 158
@@ -188,6 +188,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
188 dst->__use = 0; 188 dst->__use = 0;
189 dst->lastuse = jiffies; 189 dst->lastuse = jiffies;
190 dst->flags = flags; 190 dst->flags = flags;
191 dst->pending_confirm = 0;
191 dst->next = NULL; 192 dst->next = NULL;
192 if (!(flags & DST_NOCOUNT)) 193 if (!(flags & DST_NOCOUNT))
193 dst_entries_add(ops, 1); 194 dst_entries_add(ops, 1);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 6e9a266a0535..cc52679790b2 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -198,7 +198,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
198 if (unlikely(!neigh)) 198 if (unlikely(!neigh))
199 neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); 199 neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
200 if (neigh) { 200 if (neigh) {
201 int res = neigh_output(neigh, skb); 201 int res = dst_neigh_output(dst, neigh, skb);
202 202
203 rcu_read_unlock_bh(); 203 rcu_read_unlock_bh();
204 return res; 204 return res;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 8416f8a68e65..ca0d0e7c9778 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -740,13 +740,13 @@ void tcp_update_metrics(struct sock *sk)
740 if (sysctl_tcp_nometrics_save) 740 if (sysctl_tcp_nometrics_save)
741 return; 741 return;
742 742
743 dst_confirm(dst);
744
745 if (dst && (dst->flags & DST_HOST)) { 743 if (dst && (dst->flags & DST_HOST)) {
746 const struct inet_connection_sock *icsk = inet_csk(sk); 744 const struct inet_connection_sock *icsk = inet_csk(sk);
747 int m; 745 int m;
748 unsigned long rtt; 746 unsigned long rtt;
749 747
748 dst_confirm(dst);
749
750 if (icsk->icsk_backoff || !tp->srtt) { 750 if (icsk->icsk_backoff || !tp->srtt) {
751 /* This session failed to estimate rtt. Why? 751 /* This session failed to estimate rtt. Why?
752 * Probably, no packets returned in time. 752 * Probably, no packets returned in time.
@@ -3869,9 +3869,11 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
3869 tcp_cong_avoid(sk, ack, prior_in_flight); 3869 tcp_cong_avoid(sk, ack, prior_in_flight);
3870 } 3870 }
3871 3871
3872 if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) 3872 if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) {
3873 dst_confirm(__sk_dst_get(sk)); 3873 struct dst_entry *dst = __sk_dst_get(sk);
3874 3874 if (dst)
3875 dst_confirm(dst);
3876 }
3875 return 1; 3877 return 1;
3876 3878
3877no_queue: 3879no_queue:
@@ -6140,9 +6142,14 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
6140 6142
6141 case TCP_FIN_WAIT1: 6143 case TCP_FIN_WAIT1:
6142 if (tp->snd_una == tp->write_seq) { 6144 if (tp->snd_una == tp->write_seq) {
6145 struct dst_entry *dst;
6146
6143 tcp_set_state(sk, TCP_FIN_WAIT2); 6147 tcp_set_state(sk, TCP_FIN_WAIT2);
6144 sk->sk_shutdown |= SEND_SHUTDOWN; 6148 sk->sk_shutdown |= SEND_SHUTDOWN;
6145 dst_confirm(__sk_dst_get(sk)); 6149
6150 dst = __sk_dst_get(sk);
6151 if (dst)
6152 dst_confirm(dst);
6146 6153
6147 if (!sock_flag(sk, SOCK_DEAD)) 6154 if (!sock_flag(sk, SOCK_DEAD))
6148 /* Wake up lingering close() */ 6155 /* Wake up lingering close() */
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index a233a7ccbc3a..c94e4aabe11b 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -125,7 +125,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
125 rcu_read_lock(); 125 rcu_read_lock();
126 neigh = dst_get_neighbour_noref(dst); 126 neigh = dst_get_neighbour_noref(dst);
127 if (neigh) { 127 if (neigh) {
128 int res = neigh_output(neigh, skb); 128 int res = dst_neigh_output(dst, neigh, skb);
129 129
130 rcu_read_unlock(); 130 rcu_read_unlock();
131 return res; 131 return res;