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>
This commit is contained in:
parent
60d354ebeb
commit
5110effee8
6 changed files with 38 additions and 32 deletions
|
@ -51,7 +51,7 @@ struct dst_entry {
|
||||||
int (*input)(struct sk_buff *);
|
int (*input)(struct sk_buff *);
|
||||||
int (*output)(struct sk_buff *);
|
int (*output)(struct sk_buff *);
|
||||||
|
|
||||||
int flags;
|
unsigned short flags;
|
||||||
#define DST_HOST 0x0001
|
#define DST_HOST 0x0001
|
||||||
#define DST_NOXFRM 0x0002
|
#define DST_NOXFRM 0x0002
|
||||||
#define DST_NOPOLICY 0x0004
|
#define DST_NOPOLICY 0x0004
|
||||||
|
@ -62,6 +62,8 @@ struct dst_entry {
|
||||||
#define DST_FAKE_RTABLE 0x0080
|
#define DST_FAKE_RTABLE 0x0080
|
||||||
#define DST_XFRM_TUNNEL 0x0100
|
#define DST_XFRM_TUNNEL 0x0100
|
||||||
|
|
||||||
|
unsigned short pending_confirm;
|
||||||
|
|
||||||
short error;
|
short error;
|
||||||
short obsolete;
|
short obsolete;
|
||||||
unsigned short header_len; /* more space at head required */
|
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)
|
||||||
|
|
||||||
extern int dst_discard(struct sk_buff *skb);
|
extern int dst_discard(struct sk_buff *skb);
|
||||||
extern void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
|
extern void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
|
||||||
int initial_ref, int initial_obsolete, int flags);
|
int initial_ref, int initial_obsolete,
|
||||||
|
unsigned short flags);
|
||||||
extern void __dst_free(struct dst_entry *dst);
|
extern void __dst_free(struct dst_entry *dst);
|
||||||
extern struct dst_entry *dst_destroy(struct dst_entry *dst);
|
extern struct dst_entry *dst_destroy(struct dst_entry *dst);
|
||||||
|
|
||||||
|
@ -395,14 +398,24 @@ static inline void dst_rcu_free(struct rcu_head *head)
|
||||||
|
|
||||||
static inline void dst_confirm(struct dst_entry *dst)
|
static inline void dst_confirm(struct dst_entry *dst)
|
||||||
{
|
{
|
||||||
if (dst) {
|
dst->pending_confirm = 1;
|
||||||
struct neighbour *n;
|
}
|
||||||
|
|
||||||
rcu_read_lock();
|
static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
|
||||||
n = dst_get_neighbour_noref(dst);
|
struct sk_buff *skb)
|
||||||
neigh_confirm(n);
|
{
|
||||||
rcu_read_unlock();
|
struct hh_cache *hh;
|
||||||
|
|
||||||
|
if (unlikely(dst->pending_confirm)) {
|
||||||
|
n->confirmed = jiffies;
|
||||||
|
dst->pending_confirm = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hh = &n->hh;
|
||||||
|
if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
|
||||||
|
return neigh_hh_output(hh, skb);
|
||||||
|
else
|
||||||
|
return n->output(n, skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr)
|
static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr)
|
||||||
|
|
|
@ -309,12 +309,6 @@ static inline struct neighbour * neigh_clone(struct neighbour *neigh)
|
||||||
|
|
||||||
#define neigh_hold(n) atomic_inc(&(n)->refcnt)
|
#define neigh_hold(n) atomic_inc(&(n)->refcnt)
|
||||||
|
|
||||||
static inline void neigh_confirm(struct neighbour *neigh)
|
|
||||||
{
|
|
||||||
if (neigh)
|
|
||||||
neigh->confirmed = jiffies;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
|
static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
unsigned long now = jiffies;
|
unsigned long now = jiffies;
|
||||||
|
@ -358,15 +352,6 @@ static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
|
||||||
return dev_queue_xmit(skb);
|
return dev_queue_xmit(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int neigh_output(struct neighbour *n, struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
struct hh_cache *hh = &n->hh;
|
|
||||||
if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
|
|
||||||
return neigh_hh_output(hh, skb);
|
|
||||||
else
|
|
||||||
return n->output(n, skb);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct neighbour *
|
static inline struct neighbour *
|
||||||
__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
|
__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,7 +152,7 @@ EXPORT_SYMBOL(dst_discard);
|
||||||
const u32 dst_default_metrics[RTAX_MAX];
|
const u32 dst_default_metrics[RTAX_MAX];
|
||||||
|
|
||||||
void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
|
void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
|
||||||
int initial_ref, int initial_obsolete, int flags)
|
int initial_ref, int initial_obsolete, unsigned short flags)
|
||||||
{
|
{
|
||||||
struct dst_entry *dst;
|
struct dst_entry *dst;
|
||||||
|
|
||||||
|
@ -188,6 +188,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
|
||||||
dst->__use = 0;
|
dst->__use = 0;
|
||||||
dst->lastuse = jiffies;
|
dst->lastuse = jiffies;
|
||||||
dst->flags = flags;
|
dst->flags = flags;
|
||||||
|
dst->pending_confirm = 0;
|
||||||
dst->next = NULL;
|
dst->next = NULL;
|
||||||
if (!(flags & DST_NOCOUNT))
|
if (!(flags & DST_NOCOUNT))
|
||||||
dst_entries_add(ops, 1);
|
dst_entries_add(ops, 1);
|
||||||
|
|
|
@ -198,7 +198,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
|
||||||
if (unlikely(!neigh))
|
if (unlikely(!neigh))
|
||||||
neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
|
neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
|
||||||
if (neigh) {
|
if (neigh) {
|
||||||
int res = neigh_output(neigh, skb);
|
int res = dst_neigh_output(dst, neigh, skb);
|
||||||
|
|
||||||
rcu_read_unlock_bh();
|
rcu_read_unlock_bh();
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -740,13 +740,13 @@ void tcp_update_metrics(struct sock *sk)
|
||||||
if (sysctl_tcp_nometrics_save)
|
if (sysctl_tcp_nometrics_save)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dst_confirm(dst);
|
|
||||||
|
|
||||||
if (dst && (dst->flags & DST_HOST)) {
|
if (dst && (dst->flags & DST_HOST)) {
|
||||||
const struct inet_connection_sock *icsk = inet_csk(sk);
|
const struct inet_connection_sock *icsk = inet_csk(sk);
|
||||||
int m;
|
int m;
|
||||||
unsigned long rtt;
|
unsigned long rtt;
|
||||||
|
|
||||||
|
dst_confirm(dst);
|
||||||
|
|
||||||
if (icsk->icsk_backoff || !tp->srtt) {
|
if (icsk->icsk_backoff || !tp->srtt) {
|
||||||
/* This session failed to estimate rtt. Why?
|
/* This session failed to estimate rtt. Why?
|
||||||
* Probably, no packets returned in time.
|
* Probably, no packets returned in time.
|
||||||
|
@ -3869,9 +3869,11 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag)
|
||||||
tcp_cong_avoid(sk, ack, prior_in_flight);
|
tcp_cong_avoid(sk, ack, prior_in_flight);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))
|
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) {
|
||||||
dst_confirm(__sk_dst_get(sk));
|
struct dst_entry *dst = __sk_dst_get(sk);
|
||||||
|
if (dst)
|
||||||
|
dst_confirm(dst);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
no_queue:
|
no_queue:
|
||||||
|
@ -6140,9 +6142,14 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
|
||||||
|
|
||||||
case TCP_FIN_WAIT1:
|
case TCP_FIN_WAIT1:
|
||||||
if (tp->snd_una == tp->write_seq) {
|
if (tp->snd_una == tp->write_seq) {
|
||||||
|
struct dst_entry *dst;
|
||||||
|
|
||||||
tcp_set_state(sk, TCP_FIN_WAIT2);
|
tcp_set_state(sk, TCP_FIN_WAIT2);
|
||||||
sk->sk_shutdown |= SEND_SHUTDOWN;
|
sk->sk_shutdown |= SEND_SHUTDOWN;
|
||||||
dst_confirm(__sk_dst_get(sk));
|
|
||||||
|
dst = __sk_dst_get(sk);
|
||||||
|
if (dst)
|
||||||
|
dst_confirm(dst);
|
||||||
|
|
||||||
if (!sock_flag(sk, SOCK_DEAD))
|
if (!sock_flag(sk, SOCK_DEAD))
|
||||||
/* Wake up lingering close() */
|
/* Wake up lingering close() */
|
||||||
|
|
|
@ -125,7 +125,7 @@ static int ip6_finish_output2(struct sk_buff *skb)
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
neigh = dst_get_neighbour_noref(dst);
|
neigh = dst_get_neighbour_noref(dst);
|
||||||
if (neigh) {
|
if (neigh) {
|
||||||
int res = neigh_output(neigh, skb);
|
int res = dst_neigh_output(dst, neigh, skb);
|
||||||
|
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
return res;
|
return res;
|
||||||
|
|
Loading…
Reference in a new issue