浏览代码

arp: postpone addr_type calculation to as late as possible

The addr_type retrieval can be costly, so it's worth trying to avoid its
calculation as much as possible. This patch makes it calculated only
for gratuitous ARP packets. This is especially important since later we
may want to move is_garp calculation outside of arp_accept block, at
which point the costly operation will be executed for all setups.

The patch is the result of a discussion in net-dev:
http://marc.info/?l=linux-netdev&m=149506354216994

Suggested-by: Julian Anastasov <ja@ssi.bg>
Signed-off-by: Ihar Hrachyshka <ihrachys@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Ihar Hrachyshka 8 年之前
父节点
当前提交
d9ef2e7bf9
共有 1 个文件被更改,包括 17 次插入7 次删除
  1. 17 7
      net/ipv4/arp.c

+ 17 - 7
net/ipv4/arp.c

@@ -641,12 +641,12 @@ void arp_xmit(struct sk_buff *skb)
 }
 }
 EXPORT_SYMBOL(arp_xmit);
 EXPORT_SYMBOL(arp_xmit);
 
 
-static bool arp_is_garp(struct net_device *dev, int addr_type,
-			__be16 ar_op,
+static bool arp_is_garp(struct net *net, struct net_device *dev,
+			int *addr_type, __be16 ar_op,
 			__be32 sip, __be32 tip,
 			__be32 sip, __be32 tip,
 			unsigned char *sha, unsigned char *tha)
 			unsigned char *sha, unsigned char *tha)
 {
 {
-	bool is_garp = tip == sip && addr_type == RTN_UNICAST;
+	bool is_garp = tip == sip;
 
 
 	/* Gratuitous ARP _replies_ also require target hwaddr to be
 	/* Gratuitous ARP _replies_ also require target hwaddr to be
 	 * the same as source.
 	 * the same as source.
@@ -659,6 +659,11 @@ static bool arp_is_garp(struct net_device *dev, int addr_type,
 			tha &&
 			tha &&
 			!memcmp(tha, sha, dev->addr_len);
 			!memcmp(tha, sha, dev->addr_len);
 
 
+	if (is_garp) {
+		*addr_type = inet_addr_type_dev_table(net, dev, sip);
+		if (*addr_type != RTN_UNICAST)
+			is_garp = false;
+	}
 	return is_garp;
 	return is_garp;
 }
 }
 
 
@@ -859,18 +864,23 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb)
 	n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
 	n = __neigh_lookup(&arp_tbl, &sip, dev, 0);
 
 
 	if (IN_DEV_ARP_ACCEPT(in_dev)) {
 	if (IN_DEV_ARP_ACCEPT(in_dev)) {
-		unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip);
+		addr_type = -1;
 
 
 		/* Unsolicited ARP is not accepted by default.
 		/* Unsolicited ARP is not accepted by default.
 		   It is possible, that this option should be enabled for some
 		   It is possible, that this option should be enabled for some
 		   devices (strip is candidate)
 		   devices (strip is candidate)
 		 */
 		 */
-		is_garp = arp_is_garp(dev, addr_type, arp->ar_op,
+		is_garp = arp_is_garp(net, dev, &addr_type, arp->ar_op,
 				      sip, tip, sha, tha);
 				      sip, tip, sha, tha);
 
 
 		if (!n &&
 		if (!n &&
-		    ((arp->ar_op == htons(ARPOP_REPLY)  &&
-				addr_type == RTN_UNICAST) || is_garp))
+		    (is_garp ||
+		     (arp->ar_op == htons(ARPOP_REPLY) &&
+		      (addr_type == RTN_UNICAST ||
+		       (addr_type < 0 &&
+			/* postpone calculation to as late as possible */
+			inet_addr_type_dev_table(net, dev, sip) ==
+				RTN_UNICAST)))))
 			n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
 			n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
 	}
 	}