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: Eric Dumazet Cc: Mahesh Bandewar --- v2: guard ipvlan_ht_addr_lookup6() with CONFIG_IPV6 (kernel test robot) v1: https://lore.kernel.org/netdev/20260121215728.560645-1-edumazet@google.com/ drivers/net/ipvlan/ipvlan_core.c | 55 ++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 21 deletions(-) diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index 2efa3ba148aa7efed999dc3c06ccbb787eca92e5..f1568d50f5cc8259e6166993bda8a3425e4e5937 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -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]); } @@ -357,21 +369,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. @@ -379,24 +394,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); @@ -405,9 +419,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; } } -- 2.52.0.457.g6b5491de43-goog