diff options
author | David S. Miller <davem@davemloft.net> | 2012-07-02 05:21:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-05 04:03:06 -0400 |
commit | 5110effee8fde2edfacac9cd12a9960ab2dc39ea (patch) | |
tree | f74fff97af20ffdf805fedc56f0c8f88bbef2df7 | |
parent | 60d354ebebd9d0f760cb6c3b9f53a7ade0f8cd0e (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.h | 29 | ||||
-rw-r--r-- | include/net/neighbour.h | 15 | ||||
-rw-r--r-- | net/core/dst.c | 3 | ||||
-rw-r--r-- | net/ipv4/ip_output.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 19 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 2 |
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 | ||
372 | extern int dst_discard(struct sk_buff *skb); | 374 | extern int dst_discard(struct sk_buff *skb); |
373 | extern void *dst_alloc(struct dst_ops *ops, struct net_device *dev, | 375 | extern 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); | ||
375 | extern void __dst_free(struct dst_entry *dst); | 378 | extern void __dst_free(struct dst_entry *dst); |
376 | extern struct dst_entry *dst_destroy(struct dst_entry *dst); | 379 | extern 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 | ||
396 | static inline void dst_confirm(struct dst_entry *dst) | 399 | static 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(); | 404 | static 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 | ||
408 | static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr) | 421 | static 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 | ||
312 | static inline void neigh_confirm(struct neighbour *neigh) | ||
313 | { | ||
314 | if (neigh) | ||
315 | neigh->confirmed = jiffies; | ||
316 | } | ||
317 | |||
318 | static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) | 312 | static 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 | ||
361 | static 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 | |||
370 | static inline struct neighbour * | 355 | static 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); | |||
152 | const u32 dst_default_metrics[RTAX_MAX]; | 152 | const u32 dst_default_metrics[RTAX_MAX]; |
153 | 153 | ||
154 | void *dst_alloc(struct dst_ops *ops, struct net_device *dev, | 154 | void *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 | ||
3877 | no_queue: | 3879 | no_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; |