Skip to content

Commit 5110eff

Browse files
committed
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 <[email protected]>
1 parent 60d354e commit 5110eff

File tree

6 files changed

+38
-32
lines changed

6 files changed

+38
-32
lines changed

include/net/dst.h

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ struct dst_entry {
5151
int (*input)(struct sk_buff *);
5252
int (*output)(struct sk_buff *);
5353

54-
int flags;
54+
unsigned short flags;
5555
#define DST_HOST 0x0001
5656
#define DST_NOXFRM 0x0002
5757
#define DST_NOPOLICY 0x0004
@@ -62,6 +62,8 @@ struct dst_entry {
6262
#define DST_FAKE_RTABLE 0x0080
6363
#define DST_XFRM_TUNNEL 0x0100
6464

65+
unsigned short pending_confirm;
66+
6567
short error;
6668
short obsolete;
6769
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)
371373

372374
extern int dst_discard(struct sk_buff *skb);
373375
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);
375378
extern void __dst_free(struct dst_entry *dst);
376379
extern struct dst_entry *dst_destroy(struct dst_entry *dst);
377380

@@ -395,14 +398,24 @@ static inline void dst_rcu_free(struct rcu_head *head)
395398

396399
static inline void dst_confirm(struct dst_entry *dst)
397400
{
398-
if (dst) {
399-
struct neighbour *n;
401+
dst->pending_confirm = 1;
402+
}
400403

401-
rcu_read_lock();
402-
n = dst_get_neighbour_noref(dst);
403-
neigh_confirm(n);
404-
rcu_read_unlock();
404+
static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
405+
struct sk_buff *skb)
406+
{
407+
struct hh_cache *hh;
408+
409+
if (unlikely(dst->pending_confirm)) {
410+
n->confirmed = jiffies;
411+
dst->pending_confirm = 0;
405412
}
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);
406419
}
407420

408421
static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr)

include/net/neighbour.h

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -309,12 +309,6 @@ static inline struct neighbour * neigh_clone(struct neighbour *neigh)
309309

310310
#define neigh_hold(n) atomic_inc(&(n)->refcnt)
311311

312-
static inline void neigh_confirm(struct neighbour *neigh)
313-
{
314-
if (neigh)
315-
neigh->confirmed = jiffies;
316-
}
317-
318312
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
319313
{
320314
unsigned long now = jiffies;
@@ -358,15 +352,6 @@ static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
358352
return dev_queue_xmit(skb);
359353
}
360354

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-
370355
static inline struct neighbour *
371356
__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
372357
{

net/core/dst.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ EXPORT_SYMBOL(dst_discard);
152152
const u32 dst_default_metrics[RTAX_MAX];
153153

154154
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)
156156
{
157157
struct dst_entry *dst;
158158

@@ -188,6 +188,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
188188
dst->__use = 0;
189189
dst->lastuse = jiffies;
190190
dst->flags = flags;
191+
dst->pending_confirm = 0;
191192
dst->next = NULL;
192193
if (!(flags & DST_NOCOUNT))
193194
dst_entries_add(ops, 1);

net/ipv4/ip_output.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
198198
if (unlikely(!neigh))
199199
neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
200200
if (neigh) {
201-
int res = neigh_output(neigh, skb);
201+
int res = dst_neigh_output(dst, neigh, skb);
202202

203203
rcu_read_unlock_bh();
204204
return res;

net/ipv4/tcp_input.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -740,13 +740,13 @@ void tcp_update_metrics(struct sock *sk)
740740
if (sysctl_tcp_nometrics_save)
741741
return;
742742

743-
dst_confirm(dst);
744-
745743
if (dst && (dst->flags & DST_HOST)) {
746744
const struct inet_connection_sock *icsk = inet_csk(sk);
747745
int m;
748746
unsigned long rtt;
749747

748+
dst_confirm(dst);
749+
750750
if (icsk->icsk_backoff || !tp->srtt) {
751751
/* This session failed to estimate rtt. Why?
752752
* Probably, no packets returned in time.
@@ -3869,9 +3869,11 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
38693869
tcp_cong_avoid(sk, ack, prior_in_flight);
38703870
}
38713871

3872-
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))
3873-
dst_confirm(__sk_dst_get(sk));
3874-
3872+
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) {
3873+
struct dst_entry *dst = __sk_dst_get(sk);
3874+
if (dst)
3875+
dst_confirm(dst);
3876+
}
38753877
return 1;
38763878

38773879
no_queue:
@@ -6140,9 +6142,14 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
61406142

61416143
case TCP_FIN_WAIT1:
61426144
if (tp->snd_una == tp->write_seq) {
6145+
struct dst_entry *dst;
6146+
61436147
tcp_set_state(sk, TCP_FIN_WAIT2);
61446148
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);
61466153

61476154
if (!sock_flag(sk, SOCK_DEAD))
61486155
/* Wake up lingering close() */

net/ipv6/ip6_output.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
125125
rcu_read_lock();
126126
neigh = dst_get_neighbour_noref(dst);
127127
if (neigh) {
128-
int res = neigh_output(neigh, skb);
128+
int res = dst_neigh_output(dst, neigh, skb);
129129

130130
rcu_read_unlock();
131131
return res;

0 commit comments

Comments
 (0)