Skip to content

Commit cd28ca0

Browse files
Eric Dumazetdavem330
authored andcommitted
neigh: reduce arp latency
Remove the artificial HZ latency on arp resolution. Instead of firing a timer in one jiffy (up to 10 ms if HZ=100), lets send the ARP message immediately. Before patch : # arp -d 192.168.20.108 ; ping -c 3 192.168.20.108 PING 192.168.20.108 (192.168.20.108) 56(84) bytes of data. 64 bytes from 192.168.20.108: icmp_seq=1 ttl=64 time=9.91 ms 64 bytes from 192.168.20.108: icmp_seq=2 ttl=64 time=0.065 ms 64 bytes from 192.168.20.108: icmp_seq=3 ttl=64 time=0.061 ms After patch : $ arp -d 192.168.20.108 ; ping -c 3 192.168.20.108 PING 192.168.20.108 (192.168.20.108) 56(84) bytes of data. 64 bytes from 192.168.20.108: icmp_seq=1 ttl=64 time=0.152 ms 64 bytes from 192.168.20.108: icmp_seq=2 ttl=64 time=0.064 ms 64 bytes from 192.168.20.108: icmp_seq=3 ttl=64 time=0.074 ms Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 68c3e5a commit cd28ca0

File tree

1 file changed

+26
-14
lines changed

1 file changed

+26
-14
lines changed

net/core/neighbour.c

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -844,6 +844,19 @@ static void neigh_invalidate(struct neighbour *neigh)
844844
skb_queue_purge(&neigh->arp_queue);
845845
}
846846

847+
static void neigh_probe(struct neighbour *neigh)
848+
__releases(neigh->lock)
849+
{
850+
struct sk_buff *skb = skb_peek(&neigh->arp_queue);
851+
/* keep skb alive even if arp_queue overflows */
852+
if (skb)
853+
skb = skb_copy(skb, GFP_ATOMIC);
854+
write_unlock(&neigh->lock);
855+
neigh->ops->solicit(neigh, skb);
856+
atomic_inc(&neigh->probes);
857+
kfree_skb(skb);
858+
}
859+
847860
/* Called when a timer expires for a neighbour entry. */
848861

849862
static void neigh_timer_handler(unsigned long arg)
@@ -920,14 +933,7 @@ static void neigh_timer_handler(unsigned long arg)
920933
neigh_hold(neigh);
921934
}
922935
if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) {
923-
struct sk_buff *skb = skb_peek(&neigh->arp_queue);
924-
/* keep skb alive even if arp_queue overflows */
925-
if (skb)
926-
skb = skb_copy(skb, GFP_ATOMIC);
927-
write_unlock(&neigh->lock);
928-
neigh->ops->solicit(neigh, skb);
929-
atomic_inc(&neigh->probes);
930-
kfree_skb(skb);
936+
neigh_probe(neigh);
931937
} else {
932938
out:
933939
write_unlock(&neigh->lock);
@@ -942,22 +948,24 @@ static void neigh_timer_handler(unsigned long arg)
942948
int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
943949
{
944950
int rc;
945-
unsigned long now;
951+
bool immediate_probe = false;
946952

947953
write_lock_bh(&neigh->lock);
948954

949955
rc = 0;
950956
if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE))
951957
goto out_unlock_bh;
952958

953-
now = jiffies;
954-
955959
if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) {
956960
if (neigh->parms->mcast_probes + neigh->parms->app_probes) {
961+
unsigned long next, now = jiffies;
962+
957963
atomic_set(&neigh->probes, neigh->parms->ucast_probes);
958964
neigh->nud_state = NUD_INCOMPLETE;
959-
neigh->updated = jiffies;
960-
neigh_add_timer(neigh, now + 1);
965+
neigh->updated = now;
966+
next = now + max(neigh->parms->retrans_time, HZ/2);
967+
neigh_add_timer(neigh, next);
968+
immediate_probe = true;
961969
} else {
962970
neigh->nud_state = NUD_FAILED;
963971
neigh->updated = jiffies;
@@ -989,7 +997,11 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
989997
rc = 1;
990998
}
991999
out_unlock_bh:
992-
write_unlock_bh(&neigh->lock);
1000+
if (immediate_probe)
1001+
neigh_probe(neigh);
1002+
else
1003+
write_unlock(&neigh->lock);
1004+
local_bh_enable();
9931005
return rc;
9941006
}
9951007
EXPORT_SYMBOL(__neigh_event_send);

0 commit comments

Comments
 (0)