On 2023/6/12 22:27, Liu Jian wrote:
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)
static
+{
- int i;
- for (i = 0; i < IN4_ADDR_HSIZE; i++)
INIT_HLIST_HEAD(&localip_lst[i]);
- register_inetaddr_notifier(&localip_notifier);
error handling
- bpf_is_local_ipaddr_func = is_local_ipaddr;
- return 0;
+}
+void localip_cleanup(void)
static
+{
- 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_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:
default: return bpf_sk_base_func_proto(func_id); }return &bpf_is_local_ipaddr_proto;
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