mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-05 07:08:06 -04:00
net: core: neighbour: Extract ARP queue processing to a helper function
In order to make manipulation with this bit of code clearer, extract it to a helper function, neigh_update_process_arp_queue(). Signed-off-by: Petr Machata <petrm@nvidia.com> Reviewed-by: Ido Schimmel <idosch@nvidia.com> Reviewed-by: Simon Horman <horms@kernel.org> Link: https://patch.msgid.link/8b0fa0abe2cf0e24484903f5436fe0ac64163057.1769012464.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
committed by
Jakub Kicinski
parent
0ecdccb8a4
commit
705ef89ac9
@@ -1302,6 +1302,47 @@ static void neigh_update_hhs(struct neighbour *neigh)
|
||||
}
|
||||
}
|
||||
|
||||
static void neigh_update_process_arp_queue(struct neighbour *neigh)
|
||||
__releases(neigh->lock)
|
||||
__acquires(neigh->lock)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Again: avoid deadlock if something went wrong. */
|
||||
while (neigh->nud_state & NUD_VALID &&
|
||||
(skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct neighbour *n2, *n1 = neigh;
|
||||
|
||||
write_unlock_bh(&neigh->lock);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Why not just use 'neigh' as-is? The problem is that
|
||||
* things such as shaper, eql, and sch_teql can end up
|
||||
* using alternative, different, neigh objects to output
|
||||
* the packet in the output path. So what we need to do
|
||||
* here is re-lookup the top-level neigh in the path so
|
||||
* we can reinject the packet there.
|
||||
*/
|
||||
n2 = NULL;
|
||||
if (dst &&
|
||||
READ_ONCE(dst->obsolete) != DST_OBSOLETE_DEAD) {
|
||||
n2 = dst_neigh_lookup_skb(dst, skb);
|
||||
if (n2)
|
||||
n1 = n2;
|
||||
}
|
||||
READ_ONCE(n1->output)(n1, skb);
|
||||
if (n2)
|
||||
neigh_release(n2);
|
||||
rcu_read_unlock();
|
||||
|
||||
write_lock_bh(&neigh->lock);
|
||||
}
|
||||
__skb_queue_purge(&neigh->arp_queue);
|
||||
neigh->arp_queue_len_bytes = 0;
|
||||
}
|
||||
|
||||
/* Generic update routine.
|
||||
-- lladdr is new lladdr or NULL, if it is not supplied.
|
||||
-- new is new state.
|
||||
@@ -1461,43 +1502,10 @@ static int __neigh_update(struct neighbour *neigh, const u8 *lladdr,
|
||||
neigh_connect(neigh);
|
||||
else
|
||||
neigh_suspect(neigh);
|
||||
if (!(old & NUD_VALID)) {
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* Again: avoid dead loop if something went wrong */
|
||||
if (!(old & NUD_VALID))
|
||||
neigh_update_process_arp_queue(neigh);
|
||||
|
||||
while (neigh->nud_state & NUD_VALID &&
|
||||
(skb = __skb_dequeue(&neigh->arp_queue)) != NULL) {
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct neighbour *n2, *n1 = neigh;
|
||||
write_unlock_bh(&neigh->lock);
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
/* Why not just use 'neigh' as-is? The problem is that
|
||||
* things such as shaper, eql, and sch_teql can end up
|
||||
* using alternative, different, neigh objects to output
|
||||
* the packet in the output path. So what we need to do
|
||||
* here is re-lookup the top-level neigh in the path so
|
||||
* we can reinject the packet there.
|
||||
*/
|
||||
n2 = NULL;
|
||||
if (dst &&
|
||||
READ_ONCE(dst->obsolete) != DST_OBSOLETE_DEAD) {
|
||||
n2 = dst_neigh_lookup_skb(dst, skb);
|
||||
if (n2)
|
||||
n1 = n2;
|
||||
}
|
||||
READ_ONCE(n1->output)(n1, skb);
|
||||
if (n2)
|
||||
neigh_release(n2);
|
||||
rcu_read_unlock();
|
||||
|
||||
write_lock_bh(&neigh->lock);
|
||||
}
|
||||
__skb_queue_purge(&neigh->arp_queue);
|
||||
neigh->arp_queue_len_bytes = 0;
|
||||
}
|
||||
out:
|
||||
if (update_isrouter)
|
||||
neigh_update_is_router(neigh, flags, ¬ify);
|
||||
|
||||
Reference in New Issue
Block a user