Commit 05413022 authored by Eric Dumazet's avatar Eric Dumazet Committed by Jakub Kicinski
Browse files

ipvlan: remove ipvlan_ht_addr_lookup()



ipvlan_ht_addr_lookup() is called four times and not inlined.

Split it to ipvlan_ht_addr_lookup6() and ipvlan_ht_addr_lookup4()
and rework ipvlan_addr_lookup() to call these helpers once,
so that they are (auto)inlined.

After this change, ipvlan_addr_lookup() is faster, and we save
350 bytes of text on x86_64.

$ scripts/bloat-o-meter -t vmlinux.old vmlinux.new
add/remove: 0/2 grow/shrink: 1/0 up/down: 123/-473 (-350)
Function                                     old     new   delta
ipvlan_addr_lookup                           467     590    +123
__pfx_ipvlan_ht_addr_lookup                   16       -     -16
ipvlan_ht_addr_lookup                        457       -    -457
Total: Before=22571833, After=22571483, chg -0.00%

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Mahesh Bandewar <maheshb@google.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260122165049.2366985-1-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 37b0ea8f
Loading
Loading
Loading
Loading
+34 −21
Original line number Diff line number Diff line
@@ -48,11 +48,9 @@ static u8 ipvlan_get_v6_hash(const void *iaddr)
}
#endif

static u8 ipvlan_get_v4_hash(const void *iaddr)
static u8 ipvlan_get_v4_hash(__be32 addr)
{
	const struct in_addr *ip4_addr = iaddr;

	return jhash_1word((__force u32)ip4_addr->s_addr, ipvlan_jhash_secret) &
	return jhash_1word((__force u32)addr, ipvlan_jhash_secret) &
			   IPVLAN_HASH_MASK;
}

@@ -73,16 +71,30 @@ static bool addr_equal(bool is_v6, struct ipvl_addr *addr, const void *iaddr)
	return false;
}

static struct ipvl_addr *ipvlan_ht_addr_lookup(const struct ipvl_port *port,
					       const void *iaddr, bool is_v6)
#if IS_ENABLED(CONFIG_IPV6)
static struct ipvl_addr *ipvlan_ht_addr_lookup6(const struct ipvl_port *port,
						const void *iaddr)
{
	struct ipvl_addr *addr;
	u8 hash;

	hash = is_v6 ? ipvlan_get_v6_hash(iaddr) :
	       ipvlan_get_v4_hash(iaddr);
	hash = ipvlan_get_v6_hash(iaddr);
	hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode)
		if (addr_equal(is_v6, addr, iaddr))
		if (addr_equal(true, addr, iaddr))
			return addr;
	return NULL;
}
#endif

static struct ipvl_addr *ipvlan_ht_addr_lookup4(const struct ipvl_port *port,
						__be32 addr4)
{
	struct ipvl_addr *addr;
	u8 hash;

	hash = ipvlan_get_v4_hash(addr4);
	hlist_for_each_entry_rcu(addr, &port->hlhead[hash], hlnode)
		if (addr->atype == IPVL_IPV4 && addr->ip4addr.s_addr == addr4)
			return addr;
	return NULL;
}
@@ -94,7 +106,7 @@ void ipvlan_ht_addr_add(struct ipvl_dev *ipvlan, struct ipvl_addr *addr)

	hash = (addr->atype == IPVL_IPV6) ?
	       ipvlan_get_v6_hash(&addr->ip6addr) :
	       ipvlan_get_v4_hash(&addr->ip4addr);
	       ipvlan_get_v4_hash(addr->ip4addr.s_addr);
	if (hlist_unhashed(&addr->hlnode))
		hlist_add_head_rcu(&addr->hlnode, &port->hlhead[hash]);
}
@@ -355,21 +367,24 @@ struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, void *lyr3h,
				     int addr_type, bool use_dest)
{
	struct ipvl_addr *addr = NULL;
#if IS_ENABLED(CONFIG_IPV6)
	struct in6_addr *i6addr;
#endif
	__be32 addr4;

	switch (addr_type) {
#if IS_ENABLED(CONFIG_IPV6)
	case IPVL_IPV6: {
		struct ipv6hdr *ip6h;
		struct in6_addr *i6addr;

		ip6h = (struct ipv6hdr *)lyr3h;
		i6addr = use_dest ? &ip6h->daddr : &ip6h->saddr;
		addr = ipvlan_ht_addr_lookup(port, i6addr, true);
lookup6:
		addr = ipvlan_ht_addr_lookup6(port, i6addr);
		break;
	}
	case IPVL_ICMPV6: {
		struct nd_msg *ndmh;
		struct in6_addr *i6addr;

		/* Make sure that the NeighborSolicitation ICMPv6 packets
		 * are handled to avoid DAD issue.
@@ -377,24 +392,23 @@ struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, void *lyr3h,
		ndmh = (struct nd_msg *)lyr3h;
		if (ndmh->icmph.icmp6_type == NDISC_NEIGHBOUR_SOLICITATION) {
			i6addr = &ndmh->target;
			addr = ipvlan_ht_addr_lookup(port, i6addr, true);
			goto lookup6;
		}
		break;
	}
#endif
	case IPVL_IPV4: {
		struct iphdr *ip4h;
		__be32 *i4addr;

		ip4h = (struct iphdr *)lyr3h;
		i4addr = use_dest ? &ip4h->daddr : &ip4h->saddr;
		addr = ipvlan_ht_addr_lookup(port, i4addr, false);
		addr4 = use_dest ? ip4h->daddr : ip4h->saddr;
lookup4:
		addr = ipvlan_ht_addr_lookup4(port, addr4);
		break;
	}
	case IPVL_ARP: {
		struct arphdr *arph;
		unsigned char *arp_ptr;
		__be32 dip;

		arph = (struct arphdr *)lyr3h;
		arp_ptr = (unsigned char *)(arph + 1);
@@ -403,9 +417,8 @@ struct ipvl_addr *ipvlan_addr_lookup(struct ipvl_port *port, void *lyr3h,
		else
			arp_ptr += port->dev->addr_len;

		memcpy(&dip, arp_ptr, 4);
		addr = ipvlan_ht_addr_lookup(port, &dip, false);
		break;
		addr4 = get_unaligned((__be32 *)arp_ptr);
		goto lookup4;
	}
	}