Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5110effe authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parent 60d354eb
Loading
Loading
Loading
Loading
+21 −8
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ struct dst_entry {
	int			(*input)(struct sk_buff *);
	int			(*output)(struct sk_buff *);

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

	unsigned short		pending_confirm;

	short			error;
	short			obsolete;
	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 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 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)
{
	if (dst) {
		struct neighbour *n;
	dst->pending_confirm = 1;
}

		rcu_read_lock();
		n = dst_get_neighbour_noref(dst);
		neigh_confirm(n);
		rcu_read_unlock();
static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n,
				   struct sk_buff *skb)
{
	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)
+0 −15
Original line number Diff line number Diff line
@@ -309,12 +309,6 @@ static inline struct neighbour * neigh_clone(struct neighbour *neigh)

#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)
{
	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);
}

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 *
__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
{
+2 −1
Original line number Diff line number Diff line
@@ -152,7 +152,7 @@ EXPORT_SYMBOL(dst_discard);
const u32 dst_default_metrics[RTAX_MAX];

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;

@@ -188,6 +188,7 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev,
	dst->__use = 0;
	dst->lastuse = jiffies;
	dst->flags = flags;
	dst->pending_confirm = 0;
	dst->next = NULL;
	if (!(flags & DST_NOCOUNT))
		dst_entries_add(ops, 1);
+1 −1
Original line number Diff line number Diff line
@@ -198,7 +198,7 @@ static inline int ip_finish_output2(struct sk_buff *skb)
	if (unlikely(!neigh))
		neigh = __neigh_create(&arp_tbl, &nexthop, dev, false);
	if (neigh) {
		int res = neigh_output(neigh, skb);
		int res = dst_neigh_output(dst, neigh, skb);

		rcu_read_unlock_bh();
		return res;
+13 −6
Original line number Diff line number Diff line
@@ -740,13 +740,13 @@ void tcp_update_metrics(struct sock *sk)
	if (sysctl_tcp_nometrics_save)
		return;

	dst_confirm(dst);

	if (dst && (dst->flags & DST_HOST)) {
		const struct inet_connection_sock *icsk = inet_csk(sk);
		int m;
		unsigned long rtt;

		dst_confirm(dst);

		if (icsk->icsk_backoff || !tp->srtt) {
			/* This session failed to estimate rtt. Why?
			 * 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);
	}

	if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP))
		dst_confirm(__sk_dst_get(sk));

	if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) {
		struct dst_entry *dst = __sk_dst_get(sk);
		if (dst)
			dst_confirm(dst);
	}
	return 1;

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

		case TCP_FIN_WAIT1:
			if (tp->snd_una == tp->write_seq) {
				struct dst_entry *dst;

				tcp_set_state(sk, TCP_FIN_WAIT2);
				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))
					/* Wake up lingering close() */
Loading