hulk inclusion category: feature bugzilla: NA CVE: N/A
----------------------------------------------------
Some network acceleration solutions, such as sockmap, are valid only for internal packets of the local host. The bpf_is_local_ipaddr() bpf helper function is added so that the ebpf program can determine whether a packet is an internal packet of the local host.
Signed-off-by: Liu Jian liujian56@huawei.com --- arch/arm64/configs/openeuler_defconfig | 1 + arch/x86/configs/openeuler_defconfig | 1 + drivers/net/Kconfig | 8 ++ drivers/net/Makefile | 1 + drivers/net/localip/Makefile | 8 ++ drivers/net/localip/localip.c | 146 +++++++++++++++++++++++++ include/uapi/linux/bpf.h | 7 ++ net/core/filter.c | 20 ++++ tools/include/uapi/linux/bpf.h | 7 ++ 9 files changed, 199 insertions(+) create mode 100644 drivers/net/localip/Makefile create mode 100644 drivers/net/localip/localip.c
diff --git a/arch/arm64/configs/openeuler_defconfig b/arch/arm64/configs/openeuler_defconfig index f934557ff765..b2d06797c08a 100644 --- a/arch/arm64/configs/openeuler_defconfig +++ b/arch/arm64/configs/openeuler_defconfig @@ -3131,6 +3131,7 @@ CONFIG_DLCI_MAX=8 CONFIG_USB4_NET=m # CONFIG_NETDEVSIM is not set CONFIG_NET_FAILOVER=m +CONFIG_NET_LOCALIP_LST=m # CONFIG_ISDN is not set
# diff --git a/arch/x86/configs/openeuler_defconfig b/arch/x86/configs/openeuler_defconfig index 11323cdc3301..4f2682d4b71e 100644 --- a/arch/x86/configs/openeuler_defconfig +++ b/arch/x86/configs/openeuler_defconfig @@ -3206,6 +3206,7 @@ CONFIG_USB4_NET=m CONFIG_HYPERV_NET=m CONFIG_NETDEVSIM=m CONFIG_NET_FAILOVER=m +CONFIG_NET_LOCALIP_LST=m CONFIG_ISDN=y CONFIG_ISDN_CAPI=y CONFIG_CAPI_TRACE=y diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f20808024305..913acb7eed6f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -592,4 +592,12 @@ config NET_FAILOVER a VM with direct attached VF by failing over to the paravirtual datapath when the VF is unplugged.
+config NET_LOCALIP_LST + tristate "Collect local ipv4 address" + depends on INET + default n + help + Similar to inet_addr_lst, only the IP address is recorded, and + net_namespace is not concerned. + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 72e18d505d1a..b4ff8a310dcc 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -84,3 +84,4 @@ thunderbolt-net-y += thunderbolt.o obj-$(CONFIG_USB4_NET) += thunderbolt-net.o obj-$(CONFIG_NETDEVSIM) += netdevsim/ obj-$(CONFIG_NET_FAILOVER) += net_failover.o +obj-$(CONFIG_NET_LOCALIP_LST) += localip/ diff --git a/drivers/net/localip/Makefile b/drivers/net/localip/Makefile new file mode 100644 index 000000000000..03b535709271 --- /dev/null +++ b/drivers/net/localip/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-$(CONFIG_NET_LOCALIP_LST) += localip.o diff --git a/drivers/net/localip/localip.c b/drivers/net/localip/localip.c new file mode 100644 index 000000000000..3756924553bf --- /dev/null +++ b/drivers/net/localip/localip.c @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2023 Huawei Technologies Co., Ltd + */ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/mutex.h> +#include <linux/device.h> +#include <linux/inetdevice.h> +#include <linux/spinlock.h> + +#define IN4_ADDR_HSIZE_SHIFT 8 +#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT) + +static struct hlist_head localip_lst[IN4_ADDR_HSIZE]; + +static DEFINE_SPINLOCK(localip_lock); + +struct localipaddr { + struct hlist_node node; + struct rcu_head rcu; + __u32 ipaddr; +}; + +static u32 localip_hash(__be32 addr) +{ + return hash_32(addr, IN4_ADDR_HSIZE_SHIFT); +} + +static void localip_hash_insert(struct localipaddr *ip) +{ + u32 hash = localip_hash(ip->ipaddr); + + hlist_add_head_rcu(&ip->node, &localip_lst[hash]); +} + +static void localip_hash_remove(struct localipaddr *ip) +{ + hlist_del_init_rcu(&ip->node); +} + +static int is_local_ipaddr(uint32_t ipaddr) +{ + u32 hash = localip_hash(ipaddr); + struct localipaddr *localip; + + rcu_read_lock(); + hlist_for_each_entry_rcu(localip, &localip_lst[hash], node) { + if (localip->ipaddr == ipaddr) { + rcu_read_unlock(); + return 1; + } + } + rcu_read_unlock(); + + return 0; +} + +static int localip_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct in_ifaddr *ifa = ptr; + struct net_device *event_netdev = ifa->ifa_dev->dev; + struct localipaddr *localip; + u32 hash; + + if (ipv4_is_loopback(ifa->ifa_local)) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + pr_debug("UP, dev:%s, ip:0x%x, mask:0x%x\n", event_netdev->name, + ifa->ifa_local, ifa->ifa_mask); + localip = kzalloc(sizeof(struct localipaddr), GFP_KERNEL); + if (!localip) { + pr_err("kzalloc failed.\n"); + break; + } + localip->ipaddr = ifa->ifa_local; + spin_lock(&localip_lock); + localip_hash_insert(localip); + spin_unlock(&localip_lock); + break; + case NETDEV_DOWN: + pr_debug("DOWN, dev:%s, ip:0x%x, mask:0x%x\n", event_netdev->name, + ifa->ifa_local, ifa->ifa_mask); + hash = localip_hash(ifa->ifa_local); + spin_lock(&localip_lock); + hlist_for_each_entry(localip, &localip_lst[hash], node) { + if (localip->ipaddr == ifa->ifa_local) { + localip_hash_remove(localip); + kfree_rcu(localip, rcu); + break; + } + } + spin_unlock(&localip_lock); + break; + default: + break; + } + return NOTIFY_DONE; +} + +static struct notifier_block localip_notifier = { + .notifier_call = localip_event, +}; + +typedef int (*is_local_ipaddr_func)(uint32_t ipaddr); +extern is_local_ipaddr_func bpf_is_local_ipaddr_func; + +int localip_init(void) +{ + int i; + + for (i = 0; i < IN4_ADDR_HSIZE; i++) + INIT_HLIST_HEAD(&localip_lst[i]); + + register_inetaddr_notifier(&localip_notifier); + bpf_is_local_ipaddr_func = is_local_ipaddr; + return 0; +} + +void localip_cleanup(void) +{ + struct localipaddr *localip; + struct hlist_node *n; + int i; + + bpf_is_local_ipaddr_func = NULL; + unregister_inetaddr_notifier(&localip_notifier); + + spin_lock(&localip_lock); + for (i = 0; i < IN4_ADDR_HSIZE; i++) { + hlist_for_each_entry_safe(localip, n, &localip_lst[i], node) { + pr_debug("cleanup, hash:%i, ip:0x%x\n", i, localip->ipaddr); + localip_hash_remove(localip); + kfree_rcu(localip, rcu); + } + } + spin_unlock(&localip_lock); + synchronize_rcu(); +} + +module_init(localip_init); +module_exit(localip_cleanup); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 9e64dac44d60..9373abafcb91 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -3872,6 +3872,12 @@ union bpf_attr { * check src_cpu whether share cache with dst_cpu. * Return * yes 1, no 0. + * + * long bpf_is_local_ipaddr(u32 ipaddr) + * Description + * Check the ipaddr is local address or not. + * Return + * 1 is local address, 0 is not. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4044,6 +4050,7 @@ union bpf_attr { FN(sched_entity_to_tg), \ FN(cpumask_op), \ FN(cpus_share_cache), \ + FN(is_local_ipaddr), \ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/net/core/filter.c b/net/core/filter.c index 012a5070a9e5..527b66921dd6 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5084,6 +5084,24 @@ static const struct bpf_func_proto bpf_sk_original_addr_proto = { .arg4_type = ARG_CONST_SIZE, };
+typedef int (*is_local_ipaddr_func)(uint32_t ipaddr); +is_local_ipaddr_func bpf_is_local_ipaddr_func; +EXPORT_SYMBOL(bpf_is_local_ipaddr_func); + +BPF_CALL_1(bpf_is_local_ipaddr, uint32_t, ipaddr) +{ + if (!bpf_is_local_ipaddr_func) + return 0; + return bpf_is_local_ipaddr_func(ipaddr); +} + +static const struct bpf_func_proto bpf_is_local_ipaddr_proto = { + .func = bpf_is_local_ipaddr, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_ANYTHING, +}; + BPF_CALL_5(bpf_sock_addr_getsockopt, struct bpf_sock_addr_kern *, ctx, int, level, int, optname, char *, optval, int, optlen) { @@ -7398,6 +7416,8 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) case BPF_FUNC_tcp_sock: return &bpf_tcp_sock_proto; #endif /* CONFIG_INET */ + case BPF_FUNC_is_local_ipaddr: + return &bpf_is_local_ipaddr_proto; default: return bpf_sk_base_func_proto(func_id); } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index abf8023d606b..41bc2f496176 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -3872,6 +3872,12 @@ union bpf_attr { * check src_cpu whether share cache with dst_cpu. * Return * true yes, false no. + * + * long bpf_is_local_ipaddr(u32 ipaddr) + * Description + * Check the ipaddr is local address or not. + * Return + * 1 is local address, 0 is not. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4044,6 +4050,7 @@ union bpf_attr { FN(sched_entity_to_tg), \ FN(cpumask_op), \ FN(cpus_share_cache), \ + FN(is_local_ipaddr), \ /* */
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
hulk inclusion category: feature bugzilla: NA CVE: N/A
----------------------------------------------------
Let sockops can use bpf_get_current_comm().
Signed-off-by: Liu Jian liujian56@huawei.com --- net/core/filter.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/net/core/filter.c b/net/core/filter.c index 527b66921dd6..bc81ce340a4d 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -7418,6 +7418,8 @@ sock_ops_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) #endif /* CONFIG_INET */ case BPF_FUNC_is_local_ipaddr: return &bpf_is_local_ipaddr_proto; + case BPF_FUNC_get_current_comm: + return &bpf_get_current_comm_proto; default: return bpf_sk_base_func_proto(func_id); }