18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (C) 2017 Netronome Systems, Inc.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is licensed under the GNU General License Version 2,
58c2ecf20Sopenharmony_ci * June 1991 as shown in the file COPYING in the top-level directory of this
68c2ecf20Sopenharmony_ci * source tree.
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
98c2ecf20Sopenharmony_ci * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
108c2ecf20Sopenharmony_ci * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
118c2ecf20Sopenharmony_ci * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
128c2ecf20Sopenharmony_ci * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
138c2ecf20Sopenharmony_ci * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
148c2ecf20Sopenharmony_ci */
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include <linux/bpf.h>
178c2ecf20Sopenharmony_ci#include <linux/bpf_verifier.h>
188c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
198c2ecf20Sopenharmony_ci#include <linux/kernel.h>
208c2ecf20Sopenharmony_ci#include <linux/mutex.h>
218c2ecf20Sopenharmony_ci#include <linux/rtnetlink.h>
228c2ecf20Sopenharmony_ci#include <net/pkt_cls.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "netdevsim.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define pr_vlog(env, fmt, ...)	\
278c2ecf20Sopenharmony_ci	bpf_verifier_log_write(env, "[netdevsim] " fmt, ##__VA_ARGS__)
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_cistruct nsim_bpf_bound_prog {
308c2ecf20Sopenharmony_ci	struct nsim_dev *nsim_dev;
318c2ecf20Sopenharmony_ci	struct bpf_prog *prog;
328c2ecf20Sopenharmony_ci	struct dentry *ddir;
338c2ecf20Sopenharmony_ci	const char *state;
348c2ecf20Sopenharmony_ci	bool is_loaded;
358c2ecf20Sopenharmony_ci	struct list_head l;
368c2ecf20Sopenharmony_ci};
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define NSIM_BPF_MAX_KEYS		2
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistruct nsim_bpf_bound_map {
418c2ecf20Sopenharmony_ci	struct netdevsim *ns;
428c2ecf20Sopenharmony_ci	struct bpf_offloaded_map *map;
438c2ecf20Sopenharmony_ci	struct mutex mutex;
448c2ecf20Sopenharmony_ci	struct nsim_map_entry {
458c2ecf20Sopenharmony_ci		void *key;
468c2ecf20Sopenharmony_ci		void *value;
478c2ecf20Sopenharmony_ci	} entry[NSIM_BPF_MAX_KEYS];
488c2ecf20Sopenharmony_ci	struct list_head l;
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic int nsim_bpf_string_show(struct seq_file *file, void *data)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	const char **str = file->private;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (*str)
568c2ecf20Sopenharmony_ci		seq_printf(file, "%s\n", *str);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	return 0;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(nsim_bpf_string);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic int
638c2ecf20Sopenharmony_cinsim_bpf_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_prog *state;
668c2ecf20Sopenharmony_ci	int ret = 0;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	state = env->prog->aux->offload->dev_priv;
698c2ecf20Sopenharmony_ci	if (state->nsim_dev->bpf_bind_verifier_delay && !insn_idx)
708c2ecf20Sopenharmony_ci		msleep(state->nsim_dev->bpf_bind_verifier_delay);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (insn_idx == env->prog->len - 1) {
738c2ecf20Sopenharmony_ci		pr_vlog(env, "Hello from netdevsim!\n");
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		if (!state->nsim_dev->bpf_bind_verifier_accept)
768c2ecf20Sopenharmony_ci			ret = -EOPNOTSUPP;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return ret;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cistatic int nsim_bpf_finalize(struct bpf_verifier_env *env)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	return 0;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic bool nsim_xdp_offload_active(struct netdevsim *ns)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	return ns->xdp_hw.prog;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic void nsim_prog_set_loaded(struct bpf_prog *prog, bool loaded)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_prog *state;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (!prog || !prog->aux->offload)
978c2ecf20Sopenharmony_ci		return;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	state = prog->aux->offload->dev_priv;
1008c2ecf20Sopenharmony_ci	state->is_loaded = loaded;
1018c2ecf20Sopenharmony_ci}
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_cistatic int
1048c2ecf20Sopenharmony_cinsim_bpf_offload(struct netdevsim *ns, struct bpf_prog *prog, bool oldprog)
1058c2ecf20Sopenharmony_ci{
1068c2ecf20Sopenharmony_ci	nsim_prog_set_loaded(ns->bpf_offloaded, false);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	WARN(!!ns->bpf_offloaded != oldprog,
1098c2ecf20Sopenharmony_ci	     "bad offload state, expected offload %sto be active",
1108c2ecf20Sopenharmony_ci	     oldprog ? "" : "not ");
1118c2ecf20Sopenharmony_ci	ns->bpf_offloaded = prog;
1128c2ecf20Sopenharmony_ci	ns->bpf_offloaded_id = prog ? prog->aux->id : 0;
1138c2ecf20Sopenharmony_ci	nsim_prog_set_loaded(prog, true);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	return 0;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ciint nsim_bpf_setup_tc_block_cb(enum tc_setup_type type,
1198c2ecf20Sopenharmony_ci			       void *type_data, void *cb_priv)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct tc_cls_bpf_offload *cls_bpf = type_data;
1228c2ecf20Sopenharmony_ci	struct bpf_prog *prog = cls_bpf->prog;
1238c2ecf20Sopenharmony_ci	struct netdevsim *ns = cb_priv;
1248c2ecf20Sopenharmony_ci	struct bpf_prog *oldprog;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	if (type != TC_SETUP_CLSBPF) {
1278c2ecf20Sopenharmony_ci		NSIM_EA(cls_bpf->common.extack,
1288c2ecf20Sopenharmony_ci			"only offload of BPF classifiers supported");
1298c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (!tc_cls_can_offload_and_chain0(ns->netdev, &cls_bpf->common))
1338c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (cls_bpf->common.protocol != htons(ETH_P_ALL)) {
1368c2ecf20Sopenharmony_ci		NSIM_EA(cls_bpf->common.extack,
1378c2ecf20Sopenharmony_ci			"only ETH_P_ALL supported as filter protocol");
1388c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	if (!ns->bpf_tc_accept) {
1428c2ecf20Sopenharmony_ci		NSIM_EA(cls_bpf->common.extack,
1438c2ecf20Sopenharmony_ci			"netdevsim configured to reject BPF TC offload");
1448c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci	/* Note: progs without skip_sw will probably not be dev bound */
1478c2ecf20Sopenharmony_ci	if (prog && !prog->aux->offload && !ns->bpf_tc_non_bound_accept) {
1488c2ecf20Sopenharmony_ci		NSIM_EA(cls_bpf->common.extack,
1498c2ecf20Sopenharmony_ci			"netdevsim configured to reject unbound programs");
1508c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1518c2ecf20Sopenharmony_ci	}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (cls_bpf->command != TC_CLSBPF_OFFLOAD)
1548c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	oldprog = cls_bpf->oldprog;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	/* Don't remove if oldprog doesn't match driver's state */
1598c2ecf20Sopenharmony_ci	if (ns->bpf_offloaded != oldprog) {
1608c2ecf20Sopenharmony_ci		oldprog = NULL;
1618c2ecf20Sopenharmony_ci		if (!cls_bpf->prog)
1628c2ecf20Sopenharmony_ci			return 0;
1638c2ecf20Sopenharmony_ci		if (ns->bpf_offloaded) {
1648c2ecf20Sopenharmony_ci			NSIM_EA(cls_bpf->common.extack,
1658c2ecf20Sopenharmony_ci				"driver and netdev offload states mismatch");
1668c2ecf20Sopenharmony_ci			return -EBUSY;
1678c2ecf20Sopenharmony_ci		}
1688c2ecf20Sopenharmony_ci	}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return nsim_bpf_offload(ns, cls_bpf->prog, oldprog);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ciint nsim_bpf_disable_tc(struct netdevsim *ns)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	if (ns->bpf_offloaded && !nsim_xdp_offload_active(ns))
1768c2ecf20Sopenharmony_ci		return -EBUSY;
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic int nsim_xdp_offload_prog(struct netdevsim *ns, struct netdev_bpf *bpf)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	if (!nsim_xdp_offload_active(ns) && !bpf->prog)
1838c2ecf20Sopenharmony_ci		return 0;
1848c2ecf20Sopenharmony_ci	if (!nsim_xdp_offload_active(ns) && bpf->prog && ns->bpf_offloaded) {
1858c2ecf20Sopenharmony_ci		NSIM_EA(bpf->extack, "TC program is already loaded");
1868c2ecf20Sopenharmony_ci		return -EBUSY;
1878c2ecf20Sopenharmony_ci	}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return nsim_bpf_offload(ns, bpf->prog, nsim_xdp_offload_active(ns));
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic int
1938c2ecf20Sopenharmony_cinsim_xdp_set_prog(struct netdevsim *ns, struct netdev_bpf *bpf,
1948c2ecf20Sopenharmony_ci		  struct xdp_attachment_info *xdp)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	int err;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	if (bpf->command == XDP_SETUP_PROG && !ns->bpf_xdpdrv_accept) {
1998c2ecf20Sopenharmony_ci		NSIM_EA(bpf->extack, "driver XDP disabled in DebugFS");
2008c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci	if (bpf->command == XDP_SETUP_PROG_HW && !ns->bpf_xdpoffload_accept) {
2038c2ecf20Sopenharmony_ci		NSIM_EA(bpf->extack, "XDP offload disabled in DebugFS");
2048c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2058c2ecf20Sopenharmony_ci	}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	if (bpf->command == XDP_SETUP_PROG_HW) {
2088c2ecf20Sopenharmony_ci		err = nsim_xdp_offload_prog(ns, bpf);
2098c2ecf20Sopenharmony_ci		if (err)
2108c2ecf20Sopenharmony_ci			return err;
2118c2ecf20Sopenharmony_ci	}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	xdp_attachment_setup(xdp, bpf);
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	return 0;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_cistatic int nsim_bpf_create_prog(struct nsim_dev *nsim_dev,
2198c2ecf20Sopenharmony_ci				struct bpf_prog *prog)
2208c2ecf20Sopenharmony_ci{
2218c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_prog *state;
2228c2ecf20Sopenharmony_ci	char name[16];
2238c2ecf20Sopenharmony_ci	int ret;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	state = kzalloc(sizeof(*state), GFP_KERNEL);
2268c2ecf20Sopenharmony_ci	if (!state)
2278c2ecf20Sopenharmony_ci		return -ENOMEM;
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	state->nsim_dev = nsim_dev;
2308c2ecf20Sopenharmony_ci	state->prog = prog;
2318c2ecf20Sopenharmony_ci	state->state = "verify";
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	/* Program id is not populated yet when we create the state. */
2348c2ecf20Sopenharmony_ci	sprintf(name, "%u", nsim_dev->prog_id_gen++);
2358c2ecf20Sopenharmony_ci	state->ddir = debugfs_create_dir(name, nsim_dev->ddir_bpf_bound_progs);
2368c2ecf20Sopenharmony_ci	if (IS_ERR(state->ddir)) {
2378c2ecf20Sopenharmony_ci		ret = PTR_ERR(state->ddir);
2388c2ecf20Sopenharmony_ci		kfree(state);
2398c2ecf20Sopenharmony_ci		return ret;
2408c2ecf20Sopenharmony_ci	}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	debugfs_create_u32("id", 0400, state->ddir, &prog->aux->id);
2438c2ecf20Sopenharmony_ci	debugfs_create_file("state", 0400, state->ddir,
2448c2ecf20Sopenharmony_ci			    &state->state, &nsim_bpf_string_fops);
2458c2ecf20Sopenharmony_ci	debugfs_create_bool("loaded", 0400, state->ddir, &state->is_loaded);
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	list_add_tail(&state->l, &nsim_dev->bpf_bound_progs);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	prog->aux->offload->dev_priv = state;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return 0;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int nsim_bpf_verifier_prep(struct bpf_prog *prog)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	struct nsim_dev *nsim_dev =
2578c2ecf20Sopenharmony_ci			bpf_offload_dev_priv(prog->aux->offload->offdev);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	if (!nsim_dev->bpf_bind_accept)
2608c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	return nsim_bpf_create_prog(nsim_dev, prog);
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_cistatic int nsim_bpf_translate(struct bpf_prog *prog)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_prog *state = prog->aux->offload->dev_priv;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	state->state = "xlated";
2708c2ecf20Sopenharmony_ci	return 0;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic void nsim_bpf_destroy_prog(struct bpf_prog *prog)
2748c2ecf20Sopenharmony_ci{
2758c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_prog *state;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	state = prog->aux->offload->dev_priv;
2788c2ecf20Sopenharmony_ci	WARN(state->is_loaded,
2798c2ecf20Sopenharmony_ci	     "offload state destroyed while program still bound");
2808c2ecf20Sopenharmony_ci	debugfs_remove_recursive(state->ddir);
2818c2ecf20Sopenharmony_ci	list_del(&state->l);
2828c2ecf20Sopenharmony_ci	kfree(state);
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic const struct bpf_prog_offload_ops nsim_bpf_dev_ops = {
2868c2ecf20Sopenharmony_ci	.insn_hook	= nsim_bpf_verify_insn,
2878c2ecf20Sopenharmony_ci	.finalize	= nsim_bpf_finalize,
2888c2ecf20Sopenharmony_ci	.prepare	= nsim_bpf_verifier_prep,
2898c2ecf20Sopenharmony_ci	.translate	= nsim_bpf_translate,
2908c2ecf20Sopenharmony_ci	.destroy	= nsim_bpf_destroy_prog,
2918c2ecf20Sopenharmony_ci};
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic int nsim_setup_prog_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	if (bpf->prog && bpf->prog->aux->offload) {
2968c2ecf20Sopenharmony_ci		NSIM_EA(bpf->extack, "attempt to load offloaded prog to drv");
2978c2ecf20Sopenharmony_ci		return -EINVAL;
2988c2ecf20Sopenharmony_ci	}
2998c2ecf20Sopenharmony_ci	if (ns->netdev->mtu > NSIM_XDP_MAX_MTU) {
3008c2ecf20Sopenharmony_ci		NSIM_EA(bpf->extack, "MTU too large w/ XDP enabled");
3018c2ecf20Sopenharmony_ci		return -EINVAL;
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci	return 0;
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int
3078c2ecf20Sopenharmony_cinsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_prog *state;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	if (!bpf->prog)
3128c2ecf20Sopenharmony_ci		return 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (!bpf->prog->aux->offload) {
3158c2ecf20Sopenharmony_ci		NSIM_EA(bpf->extack, "xdpoffload of non-bound program");
3168c2ecf20Sopenharmony_ci		return -EINVAL;
3178c2ecf20Sopenharmony_ci	}
3188c2ecf20Sopenharmony_ci	if (!bpf_offload_dev_match(bpf->prog, ns->netdev)) {
3198c2ecf20Sopenharmony_ci		NSIM_EA(bpf->extack, "program bound to different dev");
3208c2ecf20Sopenharmony_ci		return -EINVAL;
3218c2ecf20Sopenharmony_ci	}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	state = bpf->prog->aux->offload->dev_priv;
3248c2ecf20Sopenharmony_ci	if (WARN_ON(strcmp(state->state, "xlated"))) {
3258c2ecf20Sopenharmony_ci		NSIM_EA(bpf->extack, "offloading program in bad state");
3268c2ecf20Sopenharmony_ci		return -EINVAL;
3278c2ecf20Sopenharmony_ci	}
3288c2ecf20Sopenharmony_ci	return 0;
3298c2ecf20Sopenharmony_ci}
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic bool
3328c2ecf20Sopenharmony_cinsim_map_key_match(struct bpf_map *map, struct nsim_map_entry *e, void *key)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	return e->key && !memcmp(key, e->key, map->key_size);
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_cistatic int nsim_map_key_find(struct bpf_offloaded_map *offmap, void *key)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_map *nmap = offmap->dev_priv;
3408c2ecf20Sopenharmony_ci	unsigned int i;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(nmap->entry); i++)
3438c2ecf20Sopenharmony_ci		if (nsim_map_key_match(&offmap->map, &nmap->entry[i], key))
3448c2ecf20Sopenharmony_ci			return i;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return -ENOENT;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int
3508c2ecf20Sopenharmony_cinsim_map_alloc_elem(struct bpf_offloaded_map *offmap, unsigned int idx)
3518c2ecf20Sopenharmony_ci{
3528c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_map *nmap = offmap->dev_priv;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci	nmap->entry[idx].key = kmalloc(offmap->map.key_size,
3558c2ecf20Sopenharmony_ci				       GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
3568c2ecf20Sopenharmony_ci	if (!nmap->entry[idx].key)
3578c2ecf20Sopenharmony_ci		return -ENOMEM;
3588c2ecf20Sopenharmony_ci	nmap->entry[idx].value = kmalloc(offmap->map.value_size,
3598c2ecf20Sopenharmony_ci					 GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
3608c2ecf20Sopenharmony_ci	if (!nmap->entry[idx].value) {
3618c2ecf20Sopenharmony_ci		kfree(nmap->entry[idx].key);
3628c2ecf20Sopenharmony_ci		nmap->entry[idx].key = NULL;
3638c2ecf20Sopenharmony_ci		return -ENOMEM;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	return 0;
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic int
3708c2ecf20Sopenharmony_cinsim_map_get_next_key(struct bpf_offloaded_map *offmap,
3718c2ecf20Sopenharmony_ci		      void *key, void *next_key)
3728c2ecf20Sopenharmony_ci{
3738c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_map *nmap = offmap->dev_priv;
3748c2ecf20Sopenharmony_ci	int idx = -ENOENT;
3758c2ecf20Sopenharmony_ci
3768c2ecf20Sopenharmony_ci	mutex_lock(&nmap->mutex);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	if (key)
3798c2ecf20Sopenharmony_ci		idx = nsim_map_key_find(offmap, key);
3808c2ecf20Sopenharmony_ci	if (idx == -ENOENT)
3818c2ecf20Sopenharmony_ci		idx = 0;
3828c2ecf20Sopenharmony_ci	else
3838c2ecf20Sopenharmony_ci		idx++;
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	for (; idx < ARRAY_SIZE(nmap->entry); idx++) {
3868c2ecf20Sopenharmony_ci		if (nmap->entry[idx].key) {
3878c2ecf20Sopenharmony_ci			memcpy(next_key, nmap->entry[idx].key,
3888c2ecf20Sopenharmony_ci			       offmap->map.key_size);
3898c2ecf20Sopenharmony_ci			break;
3908c2ecf20Sopenharmony_ci		}
3918c2ecf20Sopenharmony_ci	}
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	mutex_unlock(&nmap->mutex);
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (idx == ARRAY_SIZE(nmap->entry))
3968c2ecf20Sopenharmony_ci		return -ENOENT;
3978c2ecf20Sopenharmony_ci	return 0;
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic int
4018c2ecf20Sopenharmony_cinsim_map_lookup_elem(struct bpf_offloaded_map *offmap, void *key, void *value)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_map *nmap = offmap->dev_priv;
4048c2ecf20Sopenharmony_ci	int idx;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci	mutex_lock(&nmap->mutex);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	idx = nsim_map_key_find(offmap, key);
4098c2ecf20Sopenharmony_ci	if (idx >= 0)
4108c2ecf20Sopenharmony_ci		memcpy(value, nmap->entry[idx].value, offmap->map.value_size);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	mutex_unlock(&nmap->mutex);
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	return idx < 0 ? idx : 0;
4158c2ecf20Sopenharmony_ci}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_cistatic int
4188c2ecf20Sopenharmony_cinsim_map_update_elem(struct bpf_offloaded_map *offmap,
4198c2ecf20Sopenharmony_ci		     void *key, void *value, u64 flags)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_map *nmap = offmap->dev_priv;
4228c2ecf20Sopenharmony_ci	int idx, err = 0;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	mutex_lock(&nmap->mutex);
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci	idx = nsim_map_key_find(offmap, key);
4278c2ecf20Sopenharmony_ci	if (idx < 0 && flags == BPF_EXIST) {
4288c2ecf20Sopenharmony_ci		err = idx;
4298c2ecf20Sopenharmony_ci		goto exit_unlock;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci	if (idx >= 0 && flags == BPF_NOEXIST) {
4328c2ecf20Sopenharmony_ci		err = -EEXIST;
4338c2ecf20Sopenharmony_ci		goto exit_unlock;
4348c2ecf20Sopenharmony_ci	}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	if (idx < 0) {
4378c2ecf20Sopenharmony_ci		for (idx = 0; idx < ARRAY_SIZE(nmap->entry); idx++)
4388c2ecf20Sopenharmony_ci			if (!nmap->entry[idx].key)
4398c2ecf20Sopenharmony_ci				break;
4408c2ecf20Sopenharmony_ci		if (idx == ARRAY_SIZE(nmap->entry)) {
4418c2ecf20Sopenharmony_ci			err = -E2BIG;
4428c2ecf20Sopenharmony_ci			goto exit_unlock;
4438c2ecf20Sopenharmony_ci		}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		err = nsim_map_alloc_elem(offmap, idx);
4468c2ecf20Sopenharmony_ci		if (err)
4478c2ecf20Sopenharmony_ci			goto exit_unlock;
4488c2ecf20Sopenharmony_ci	}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	memcpy(nmap->entry[idx].key, key, offmap->map.key_size);
4518c2ecf20Sopenharmony_ci	memcpy(nmap->entry[idx].value, value, offmap->map.value_size);
4528c2ecf20Sopenharmony_ciexit_unlock:
4538c2ecf20Sopenharmony_ci	mutex_unlock(&nmap->mutex);
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	return err;
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic int nsim_map_delete_elem(struct bpf_offloaded_map *offmap, void *key)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_map *nmap = offmap->dev_priv;
4618c2ecf20Sopenharmony_ci	int idx;
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	if (offmap->map.map_type == BPF_MAP_TYPE_ARRAY)
4648c2ecf20Sopenharmony_ci		return -EINVAL;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	mutex_lock(&nmap->mutex);
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	idx = nsim_map_key_find(offmap, key);
4698c2ecf20Sopenharmony_ci	if (idx >= 0) {
4708c2ecf20Sopenharmony_ci		kfree(nmap->entry[idx].key);
4718c2ecf20Sopenharmony_ci		kfree(nmap->entry[idx].value);
4728c2ecf20Sopenharmony_ci		memset(&nmap->entry[idx], 0, sizeof(nmap->entry[idx]));
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	mutex_unlock(&nmap->mutex);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	return idx < 0 ? idx : 0;
4788c2ecf20Sopenharmony_ci}
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_cistatic const struct bpf_map_dev_ops nsim_bpf_map_ops = {
4818c2ecf20Sopenharmony_ci	.map_get_next_key	= nsim_map_get_next_key,
4828c2ecf20Sopenharmony_ci	.map_lookup_elem	= nsim_map_lookup_elem,
4838c2ecf20Sopenharmony_ci	.map_update_elem	= nsim_map_update_elem,
4848c2ecf20Sopenharmony_ci	.map_delete_elem	= nsim_map_delete_elem,
4858c2ecf20Sopenharmony_ci};
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic int
4888c2ecf20Sopenharmony_cinsim_bpf_map_alloc(struct netdevsim *ns, struct bpf_offloaded_map *offmap)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_map *nmap;
4918c2ecf20Sopenharmony_ci	int i, err;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	if (WARN_ON(offmap->map.map_type != BPF_MAP_TYPE_ARRAY &&
4948c2ecf20Sopenharmony_ci		    offmap->map.map_type != BPF_MAP_TYPE_HASH))
4958c2ecf20Sopenharmony_ci		return -EINVAL;
4968c2ecf20Sopenharmony_ci	if (offmap->map.max_entries > NSIM_BPF_MAX_KEYS)
4978c2ecf20Sopenharmony_ci		return -ENOMEM;
4988c2ecf20Sopenharmony_ci	if (offmap->map.map_flags)
4998c2ecf20Sopenharmony_ci		return -EINVAL;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	nmap = kzalloc(sizeof(*nmap), GFP_KERNEL_ACCOUNT);
5028c2ecf20Sopenharmony_ci	if (!nmap)
5038c2ecf20Sopenharmony_ci		return -ENOMEM;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci	offmap->dev_priv = nmap;
5068c2ecf20Sopenharmony_ci	nmap->ns = ns;
5078c2ecf20Sopenharmony_ci	nmap->map = offmap;
5088c2ecf20Sopenharmony_ci	mutex_init(&nmap->mutex);
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	if (offmap->map.map_type == BPF_MAP_TYPE_ARRAY) {
5118c2ecf20Sopenharmony_ci		for (i = 0; i < ARRAY_SIZE(nmap->entry); i++) {
5128c2ecf20Sopenharmony_ci			u32 *key;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci			err = nsim_map_alloc_elem(offmap, i);
5158c2ecf20Sopenharmony_ci			if (err)
5168c2ecf20Sopenharmony_ci				goto err_free;
5178c2ecf20Sopenharmony_ci			key = nmap->entry[i].key;
5188c2ecf20Sopenharmony_ci			*key = i;
5198c2ecf20Sopenharmony_ci			memset(nmap->entry[i].value, 0, offmap->map.value_size);
5208c2ecf20Sopenharmony_ci		}
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	offmap->dev_ops = &nsim_bpf_map_ops;
5248c2ecf20Sopenharmony_ci	list_add_tail(&nmap->l, &ns->nsim_dev->bpf_bound_maps);
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	return 0;
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cierr_free:
5298c2ecf20Sopenharmony_ci	while (--i >= 0) {
5308c2ecf20Sopenharmony_ci		kfree(nmap->entry[i].key);
5318c2ecf20Sopenharmony_ci		kfree(nmap->entry[i].value);
5328c2ecf20Sopenharmony_ci	}
5338c2ecf20Sopenharmony_ci	kfree(nmap);
5348c2ecf20Sopenharmony_ci	return err;
5358c2ecf20Sopenharmony_ci}
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_cistatic void nsim_bpf_map_free(struct bpf_offloaded_map *offmap)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct nsim_bpf_bound_map *nmap = offmap->dev_priv;
5408c2ecf20Sopenharmony_ci	unsigned int i;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(nmap->entry); i++) {
5438c2ecf20Sopenharmony_ci		kfree(nmap->entry[i].key);
5448c2ecf20Sopenharmony_ci		kfree(nmap->entry[i].value);
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci	list_del_init(&nmap->l);
5478c2ecf20Sopenharmony_ci	mutex_destroy(&nmap->mutex);
5488c2ecf20Sopenharmony_ci	kfree(nmap);
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ciint nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf)
5528c2ecf20Sopenharmony_ci{
5538c2ecf20Sopenharmony_ci	struct netdevsim *ns = netdev_priv(dev);
5548c2ecf20Sopenharmony_ci	int err;
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci	ASSERT_RTNL();
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	switch (bpf->command) {
5598c2ecf20Sopenharmony_ci	case XDP_SETUP_PROG:
5608c2ecf20Sopenharmony_ci		err = nsim_setup_prog_checks(ns, bpf);
5618c2ecf20Sopenharmony_ci		if (err)
5628c2ecf20Sopenharmony_ci			return err;
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci		return nsim_xdp_set_prog(ns, bpf, &ns->xdp);
5658c2ecf20Sopenharmony_ci	case XDP_SETUP_PROG_HW:
5668c2ecf20Sopenharmony_ci		err = nsim_setup_prog_hw_checks(ns, bpf);
5678c2ecf20Sopenharmony_ci		if (err)
5688c2ecf20Sopenharmony_ci			return err;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci		return nsim_xdp_set_prog(ns, bpf, &ns->xdp_hw);
5718c2ecf20Sopenharmony_ci	case BPF_OFFLOAD_MAP_ALLOC:
5728c2ecf20Sopenharmony_ci		if (!ns->bpf_map_accept)
5738c2ecf20Sopenharmony_ci			return -EOPNOTSUPP;
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci		return nsim_bpf_map_alloc(ns, bpf->offmap);
5768c2ecf20Sopenharmony_ci	case BPF_OFFLOAD_MAP_FREE:
5778c2ecf20Sopenharmony_ci		nsim_bpf_map_free(bpf->offmap);
5788c2ecf20Sopenharmony_ci		return 0;
5798c2ecf20Sopenharmony_ci	default:
5808c2ecf20Sopenharmony_ci		return -EINVAL;
5818c2ecf20Sopenharmony_ci	}
5828c2ecf20Sopenharmony_ci}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ciint nsim_bpf_dev_init(struct nsim_dev *nsim_dev)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	int err;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&nsim_dev->bpf_bound_progs);
5898c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&nsim_dev->bpf_bound_maps);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	nsim_dev->ddir_bpf_bound_progs = debugfs_create_dir("bpf_bound_progs",
5928c2ecf20Sopenharmony_ci							    nsim_dev->ddir);
5938c2ecf20Sopenharmony_ci	if (IS_ERR(nsim_dev->ddir_bpf_bound_progs))
5948c2ecf20Sopenharmony_ci		return PTR_ERR(nsim_dev->ddir_bpf_bound_progs);
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ci	nsim_dev->bpf_dev = bpf_offload_dev_create(&nsim_bpf_dev_ops, nsim_dev);
5978c2ecf20Sopenharmony_ci	err = PTR_ERR_OR_ZERO(nsim_dev->bpf_dev);
5988c2ecf20Sopenharmony_ci	if (err)
5998c2ecf20Sopenharmony_ci		return err;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	nsim_dev->bpf_bind_accept = true;
6028c2ecf20Sopenharmony_ci	debugfs_create_bool("bpf_bind_accept", 0600, nsim_dev->ddir,
6038c2ecf20Sopenharmony_ci			    &nsim_dev->bpf_bind_accept);
6048c2ecf20Sopenharmony_ci	debugfs_create_u32("bpf_bind_verifier_delay", 0600, nsim_dev->ddir,
6058c2ecf20Sopenharmony_ci			   &nsim_dev->bpf_bind_verifier_delay);
6068c2ecf20Sopenharmony_ci	nsim_dev->bpf_bind_verifier_accept = true;
6078c2ecf20Sopenharmony_ci	debugfs_create_bool("bpf_bind_verifier_accept", 0600, nsim_dev->ddir,
6088c2ecf20Sopenharmony_ci			    &nsim_dev->bpf_bind_verifier_accept);
6098c2ecf20Sopenharmony_ci	return 0;
6108c2ecf20Sopenharmony_ci}
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_civoid nsim_bpf_dev_exit(struct nsim_dev *nsim_dev)
6138c2ecf20Sopenharmony_ci{
6148c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&nsim_dev->bpf_bound_progs));
6158c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&nsim_dev->bpf_bound_maps));
6168c2ecf20Sopenharmony_ci	bpf_offload_dev_destroy(nsim_dev->bpf_dev);
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ciint nsim_bpf_init(struct netdevsim *ns)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct dentry *ddir = ns->nsim_dev_port->ddir;
6228c2ecf20Sopenharmony_ci	int err;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	err = bpf_offload_dev_netdev_register(ns->nsim_dev->bpf_dev,
6258c2ecf20Sopenharmony_ci					      ns->netdev);
6268c2ecf20Sopenharmony_ci	if (err)
6278c2ecf20Sopenharmony_ci		return err;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	debugfs_create_u32("bpf_offloaded_id", 0400, ddir,
6308c2ecf20Sopenharmony_ci			   &ns->bpf_offloaded_id);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_ci	ns->bpf_tc_accept = true;
6338c2ecf20Sopenharmony_ci	debugfs_create_bool("bpf_tc_accept", 0600, ddir,
6348c2ecf20Sopenharmony_ci			    &ns->bpf_tc_accept);
6358c2ecf20Sopenharmony_ci	debugfs_create_bool("bpf_tc_non_bound_accept", 0600, ddir,
6368c2ecf20Sopenharmony_ci			    &ns->bpf_tc_non_bound_accept);
6378c2ecf20Sopenharmony_ci	ns->bpf_xdpdrv_accept = true;
6388c2ecf20Sopenharmony_ci	debugfs_create_bool("bpf_xdpdrv_accept", 0600, ddir,
6398c2ecf20Sopenharmony_ci			    &ns->bpf_xdpdrv_accept);
6408c2ecf20Sopenharmony_ci	ns->bpf_xdpoffload_accept = true;
6418c2ecf20Sopenharmony_ci	debugfs_create_bool("bpf_xdpoffload_accept", 0600, ddir,
6428c2ecf20Sopenharmony_ci			    &ns->bpf_xdpoffload_accept);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci	ns->bpf_map_accept = true;
6458c2ecf20Sopenharmony_ci	debugfs_create_bool("bpf_map_accept", 0600, ddir,
6468c2ecf20Sopenharmony_ci			    &ns->bpf_map_accept);
6478c2ecf20Sopenharmony_ci
6488c2ecf20Sopenharmony_ci	return 0;
6498c2ecf20Sopenharmony_ci}
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_civoid nsim_bpf_uninit(struct netdevsim *ns)
6528c2ecf20Sopenharmony_ci{
6538c2ecf20Sopenharmony_ci	WARN_ON(ns->xdp.prog);
6548c2ecf20Sopenharmony_ci	WARN_ON(ns->xdp_hw.prog);
6558c2ecf20Sopenharmony_ci	WARN_ON(ns->bpf_offloaded);
6568c2ecf20Sopenharmony_ci	bpf_offload_dev_netdev_unregister(ns->nsim_dev->bpf_dev, ns->netdev);
6578c2ecf20Sopenharmony_ci}
658