diff options
| author | Eric Dumazet <edumazet@google.com> | 2026-01-22 19:50:49 +0300 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-01-26 01:35:19 +0300 |
| commit | 0541302227817d1abb16b3aa7d968ce574272724 (patch) | |
| tree | dc3c7cb1163abe693e0a535d20589c5b7ebe313d | |
| parent | 37b0ea8fef56ccc29bd5a07f235ac218f7f98379 (diff) | |
| download | linux-0541302227817d1abb16b3aa7d968ce574272724.tar.xz | |
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: Eric Dumazet <edumazet@google.com>
Cc: Mahesh Bandewar <maheshb@google.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20260122165049.2366985-1-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ipvlan/ipvlan_core.c | 55 |
1 files changed, 34 insertions, 21 deletions
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index bdb3a46b327c..835e048351a9 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]); } @@ -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; } } |
