aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2017-12-31 10:12:24 -0500
committerDaniel Borkmann <daniel@iogearbox.net>2017-12-31 10:12:24 -0500
commit5620e1a8e2e6f96bdb72abfd68a56ce8cb94dd4d (patch)
tree1028ca0b34c579067d321d7ac10ce13606b66346
parentfb982666e380c1632a74495b68b3c33a66e76430 (diff)
parent752d7b4501c250bead233ab041738db84436b1af (diff)
Merge branch 'bpf-offload-report-dev'
Jakub Kicinski says: ==================== This series is a redo of reporting offload device information to user space after the first attempt did not take into account name spaces. As requested by Kirill offloads are now protected by an r/w sem. This allows us to remove the workqueue and free the offload state fully when device is removed (suggested by Alexei). Net namespace is reported with a device/inode pair. The accompanying bpftool support is placed in common code because maps will have very similar info. Note that the UAPI information can't be nicely encapsulated into a struct, because in case we need to grow the device information the new fields will have to be added at the end of struct bpf_prog_info, we can't grow structures in the middle of bpf_prog_info. v3: - use dev_get_by_index(); - redo ns code (new patch 6). v2: - rework the locking in patch 1 (use RCU instead of locking dependencies); - grab RTNL for a short time in patch 6; - minor update to the test in patch 8. ==================== Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/main.h2
-rw-r--r--drivers/net/ethernet/netronome/nfp/bpf/verifier.c2
-rw-r--r--drivers/net/netdevsim/bpf.c2
-rw-r--r--fs/nsfs.c29
-rw-r--r--include/linux/bpf.h16
-rw-r--r--include/linux/bpf_verifier.h16
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/proc_ns.h3
-rw-r--r--include/uapi/linux/bpf.h3
-rw-r--r--kernel/bpf/offload.c147
-rw-r--r--kernel/bpf/syscall.c19
-rw-r--r--kernel/bpf/verifier.c20
-rw-r--r--tools/bpf/bpftool/common.c52
-rw-r--r--tools/bpf/bpftool/main.h2
-rw-r--r--tools/bpf/bpftool/prog.c3
-rw-r--r--tools/include/uapi/linux/bpf.h3
-rwxr-xr-xtools/testing/selftests/bpf/test_offload.py112
17 files changed, 346 insertions, 89 deletions
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/main.h b/drivers/net/ethernet/netronome/nfp/bpf/main.h
index aae1be9ed056..89a9b6393882 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/main.h
+++ b/drivers/net/ethernet/netronome/nfp/bpf/main.h
@@ -238,7 +238,7 @@ struct nfp_bpf_vnic {
238 238
239int nfp_bpf_jit(struct nfp_prog *prog); 239int nfp_bpf_jit(struct nfp_prog *prog);
240 240
241extern const struct bpf_ext_analyzer_ops nfp_bpf_analyzer_ops; 241extern const struct bpf_prog_offload_ops nfp_bpf_analyzer_ops;
242 242
243struct netdev_bpf; 243struct netdev_bpf;
244struct nfp_app; 244struct nfp_app;
diff --git a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
index 9c2608445bd8..d8870c2f11f3 100644
--- a/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
+++ b/drivers/net/ethernet/netronome/nfp/bpf/verifier.c
@@ -260,6 +260,6 @@ nfp_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn_idx)
260 return 0; 260 return 0;
261} 261}
262 262
263const struct bpf_ext_analyzer_ops nfp_bpf_analyzer_ops = { 263const struct bpf_prog_offload_ops nfp_bpf_analyzer_ops = {
264 .insn_hook = nfp_verify_insn, 264 .insn_hook = nfp_verify_insn,
265}; 265};
diff --git a/drivers/net/netdevsim/bpf.c b/drivers/net/netdevsim/bpf.c
index a243fa7ae02f..5134d5c1306c 100644
--- a/drivers/net/netdevsim/bpf.c
+++ b/drivers/net/netdevsim/bpf.c
@@ -66,7 +66,7 @@ nsim_bpf_verify_insn(struct bpf_verifier_env *env, int insn_idx, int prev_insn)
66 return 0; 66 return 0;
67} 67}
68 68
69static const struct bpf_ext_analyzer_ops nsim_bpf_analyzer_ops = { 69static const struct bpf_prog_offload_ops nsim_bpf_analyzer_ops = {
70 .insn_hook = nsim_bpf_verify_insn, 70 .insn_hook = nsim_bpf_verify_insn,
71}; 71};
72 72
diff --git a/fs/nsfs.c b/fs/nsfs.c
index 7c6f76d29f56..36b0772701a0 100644
--- a/fs/nsfs.c
+++ b/fs/nsfs.c
@@ -103,14 +103,14 @@ slow:
103 goto got_it; 103 goto got_it;
104} 104}
105 105
106void *ns_get_path(struct path *path, struct task_struct *task, 106void *ns_get_path_cb(struct path *path, ns_get_path_helper_t *ns_get_cb,
107 const struct proc_ns_operations *ns_ops) 107 void *private_data)
108{ 108{
109 struct ns_common *ns; 109 struct ns_common *ns;
110 void *ret; 110 void *ret;
111 111
112again: 112again:
113 ns = ns_ops->get(task); 113 ns = ns_get_cb(private_data);
114 if (!ns) 114 if (!ns)
115 return ERR_PTR(-ENOENT); 115 return ERR_PTR(-ENOENT);
116 116
@@ -120,6 +120,29 @@ again:
120 return ret; 120 return ret;
121} 121}
122 122
123struct ns_get_path_task_args {
124 const struct proc_ns_operations *ns_ops;
125 struct task_struct *task;
126};
127
128static struct ns_common *ns_get_path_task(void *private_data)
129{
130 struct ns_get_path_task_args *args = private_data;
131
132 return args->ns_ops->get(args->task);
133}
134
135void *ns_get_path(struct path *path, struct task_struct *task,
136 const struct proc_ns_operations *ns_ops)
137{
138 struct ns_get_path_task_args args = {
139 .ns_ops = ns_ops,
140 .task = task,
141 };
142
143 return ns_get_path_cb(path, ns_get_path_task, &args);
144}
145
123int open_related_ns(struct ns_common *ns, 146int open_related_ns(struct ns_common *ns,
124 struct ns_common *(*get_ns)(struct ns_common *ns)) 147 struct ns_common *(*get_ns)(struct ns_common *ns))
125{ 148{
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index da54ef644fcd..7810ae57b357 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -17,6 +17,7 @@
17#include <linux/numa.h> 17#include <linux/numa.h>
18#include <linux/wait.h> 18#include <linux/wait.h>
19 19
20struct bpf_verifier_env;
20struct perf_event; 21struct perf_event;
21struct bpf_prog; 22struct bpf_prog;
22struct bpf_map; 23struct bpf_map;
@@ -184,14 +185,18 @@ struct bpf_verifier_ops {
184 struct bpf_prog *prog, u32 *target_size); 185 struct bpf_prog *prog, u32 *target_size);
185}; 186};
186 187
188struct bpf_prog_offload_ops {
189 int (*insn_hook)(struct bpf_verifier_env *env,
190 int insn_idx, int prev_insn_idx);
191};
192
187struct bpf_dev_offload { 193struct bpf_dev_offload {
188 struct bpf_prog *prog; 194 struct bpf_prog *prog;
189 struct net_device *netdev; 195 struct net_device *netdev;
190 void *dev_priv; 196 void *dev_priv;
191 struct list_head offloads; 197 struct list_head offloads;
192 bool dev_state; 198 bool dev_state;
193 bool verifier_running; 199 const struct bpf_prog_offload_ops *dev_ops;
194 wait_queue_head_t verifier_done;
195}; 200};
196 201
197struct bpf_prog_aux { 202struct bpf_prog_aux {
@@ -201,6 +206,7 @@ struct bpf_prog_aux {
201 u32 stack_depth; 206 u32 stack_depth;
202 u32 id; 207 u32 id;
203 u32 func_cnt; 208 u32 func_cnt;
209 bool offload_requested;
204 struct bpf_prog **func; 210 struct bpf_prog **func;
205 void *jit_data; /* JIT specific data. arch dependent */ 211 void *jit_data; /* JIT specific data. arch dependent */
206 struct latch_tree_node ksym_tnode; 212 struct latch_tree_node ksym_tnode;
@@ -351,6 +357,8 @@ void bpf_prog_put(struct bpf_prog *prog);
351int __bpf_prog_charge(struct user_struct *user, u32 pages); 357int __bpf_prog_charge(struct user_struct *user, u32 pages);
352void __bpf_prog_uncharge(struct user_struct *user, u32 pages); 358void __bpf_prog_uncharge(struct user_struct *user, u32 pages);
353 359
360void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock);
361
354struct bpf_map *bpf_map_get_with_uref(u32 ufd); 362struct bpf_map *bpf_map_get_with_uref(u32 ufd);
355struct bpf_map *__bpf_map_get(struct fd f); 363struct bpf_map *__bpf_map_get(struct fd f);
356struct bpf_map * __must_check bpf_map_inc(struct bpf_map *map, bool uref); 364struct bpf_map * __must_check bpf_map_inc(struct bpf_map *map, bool uref);
@@ -523,13 +531,15 @@ static inline struct bpf_prog *bpf_prog_get_type(u32 ufd,
523 531
524int bpf_prog_offload_compile(struct bpf_prog *prog); 532int bpf_prog_offload_compile(struct bpf_prog *prog);
525void bpf_prog_offload_destroy(struct bpf_prog *prog); 533void bpf_prog_offload_destroy(struct bpf_prog *prog);
534int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
535 struct bpf_prog *prog);
526 536
527#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL) 537#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
528int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr); 538int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr);
529 539
530static inline bool bpf_prog_is_dev_bound(struct bpf_prog_aux *aux) 540static inline bool bpf_prog_is_dev_bound(struct bpf_prog_aux *aux)
531{ 541{
532 return aux->offload; 542 return aux->offload_requested;
533} 543}
534#else 544#else
535static inline int bpf_prog_offload_init(struct bpf_prog *prog, 545static inline int bpf_prog_offload_init(struct bpf_prog *prog,
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 883a35d50cd5..2feb218c001d 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -166,12 +166,6 @@ static inline bool bpf_verifier_log_full(const struct bpf_verifer_log *log)
166 return log->len_used >= log->len_total - 1; 166 return log->len_used >= log->len_total - 1;
167} 167}
168 168
169struct bpf_verifier_env;
170struct bpf_ext_analyzer_ops {
171 int (*insn_hook)(struct bpf_verifier_env *env,
172 int insn_idx, int prev_insn_idx);
173};
174
175#define BPF_MAX_SUBPROGS 256 169#define BPF_MAX_SUBPROGS 256
176 170
177/* single container for all structs 171/* single container for all structs
@@ -185,7 +179,6 @@ struct bpf_verifier_env {
185 bool strict_alignment; /* perform strict pointer alignment checks */ 179 bool strict_alignment; /* perform strict pointer alignment checks */
186 struct bpf_verifier_state *cur_state; /* current verifier state */ 180 struct bpf_verifier_state *cur_state; /* current verifier state */
187 struct bpf_verifier_state_list **explored_states; /* search pruning optimization */ 181 struct bpf_verifier_state_list **explored_states; /* search pruning optimization */
188 const struct bpf_ext_analyzer_ops *dev_ops; /* device analyzer ops */
189 struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */ 182 struct bpf_map *used_maps[MAX_USED_MAPS]; /* array of map's used by eBPF program */
190 u32 used_map_cnt; /* number of used maps */ 183 u32 used_map_cnt; /* number of used maps */
191 u32 id_gen; /* used to generate unique reg IDs */ 184 u32 id_gen; /* used to generate unique reg IDs */
@@ -206,13 +199,8 @@ static inline struct bpf_reg_state *cur_regs(struct bpf_verifier_env *env)
206 return cur->frame[cur->curframe]->regs; 199 return cur->frame[cur->curframe]->regs;
207} 200}
208 201
209#if defined(CONFIG_NET) && defined(CONFIG_BPF_SYSCALL)
210int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env); 202int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env);
211#else 203int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env,
212static inline int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env) 204 int insn_idx, int prev_insn_idx);
213{
214 return -EOPNOTSUPP;
215}
216#endif
217 205
218#endif /* _LINUX_BPF_VERIFIER_H */ 206#endif /* _LINUX_BPF_VERIFIER_H */
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 352066e4eeef..49bfc6eec74c 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -804,7 +804,7 @@ enum bpf_netdev_command {
804 BPF_OFFLOAD_DESTROY, 804 BPF_OFFLOAD_DESTROY,
805}; 805};
806 806
807struct bpf_ext_analyzer_ops; 807struct bpf_prog_offload_ops;
808struct netlink_ext_ack; 808struct netlink_ext_ack;
809 809
810struct netdev_bpf { 810struct netdev_bpf {
@@ -826,7 +826,7 @@ struct netdev_bpf {
826 /* BPF_OFFLOAD_VERIFIER_PREP */ 826 /* BPF_OFFLOAD_VERIFIER_PREP */
827 struct { 827 struct {
828 struct bpf_prog *prog; 828 struct bpf_prog *prog;
829 const struct bpf_ext_analyzer_ops *ops; /* callee set */ 829 const struct bpf_prog_offload_ops *ops; /* callee set */
830 } verifier; 830 } verifier;
831 /* BPF_OFFLOAD_TRANSLATE, BPF_OFFLOAD_DESTROY */ 831 /* BPF_OFFLOAD_TRANSLATE, BPF_OFFLOAD_DESTROY */
832 struct { 832 struct {
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index 2ff18c9840a7..d31cb6215905 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -78,6 +78,9 @@ extern struct file *proc_ns_fget(int fd);
78#define get_proc_ns(inode) ((struct ns_common *)(inode)->i_private) 78#define get_proc_ns(inode) ((struct ns_common *)(inode)->i_private)
79extern void *ns_get_path(struct path *path, struct task_struct *task, 79extern void *ns_get_path(struct path *path, struct task_struct *task,
80 const struct proc_ns_operations *ns_ops); 80 const struct proc_ns_operations *ns_ops);
81typedef struct ns_common *ns_get_path_helper_t(void *);
82extern void *ns_get_path_cb(struct path *path, ns_get_path_helper_t ns_get_cb,
83 void *private_data);
81 84
82extern int ns_get_name(char *buf, size_t size, struct task_struct *task, 85extern int ns_get_name(char *buf, size_t size, struct task_struct *task,
83 const struct proc_ns_operations *ns_ops); 86 const struct proc_ns_operations *ns_ops);
diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h
index 69eabfcb9bdb..f2f8b36e2ad4 100644
--- a/include/uapi/linux/bpf.h
+++ b/include/uapi/linux/bpf.h
@@ -921,6 +921,9 @@ struct bpf_prog_info {
921 __u32 nr_map_ids; 921 __u32 nr_map_ids;
922 __aligned_u64 map_ids; 922 __aligned_u64 map_ids;
923 char name[BPF_OBJ_NAME_LEN]; 923 char name[BPF_OBJ_NAME_LEN];
924 __u32 ifindex;
925 __u64 netns_dev;
926 __u64 netns_ino;
924} __attribute__((aligned(8))); 927} __attribute__((aligned(8)));
925 928
926struct bpf_map_info { 929struct bpf_map_info {
diff --git a/kernel/bpf/offload.c b/kernel/bpf/offload.c
index 8455b89d1bbf..040d4e0edf3f 100644
--- a/kernel/bpf/offload.c
+++ b/kernel/bpf/offload.c
@@ -16,17 +16,22 @@
16#include <linux/bpf.h> 16#include <linux/bpf.h>
17#include <linux/bpf_verifier.h> 17#include <linux/bpf_verifier.h>
18#include <linux/bug.h> 18#include <linux/bug.h>
19#include <linux/kdev_t.h>
19#include <linux/list.h> 20#include <linux/list.h>
20#include <linux/netdevice.h> 21#include <linux/netdevice.h>
21#include <linux/printk.h> 22#include <linux/printk.h>
23#include <linux/proc_ns.h>
22#include <linux/rtnetlink.h> 24#include <linux/rtnetlink.h>
25#include <linux/rwsem.h>
23 26
24/* protected by RTNL */ 27/* Protects bpf_prog_offload_devs and offload members of all progs.
28 * RTNL lock cannot be taken when holding this lock.
29 */
30static DECLARE_RWSEM(bpf_devs_lock);
25static LIST_HEAD(bpf_prog_offload_devs); 31static LIST_HEAD(bpf_prog_offload_devs);
26 32
27int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr) 33int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
28{ 34{
29 struct net *net = current->nsproxy->net_ns;
30 struct bpf_dev_offload *offload; 35 struct bpf_dev_offload *offload;
31 36
32 if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS && 37 if (attr->prog_type != BPF_PROG_TYPE_SCHED_CLS &&
@@ -41,32 +46,40 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
41 return -ENOMEM; 46 return -ENOMEM;
42 47
43 offload->prog = prog; 48 offload->prog = prog;
44 init_waitqueue_head(&offload->verifier_done);
45 49
46 rtnl_lock(); 50 offload->netdev = dev_get_by_index(current->nsproxy->net_ns,
47 offload->netdev = __dev_get_by_index(net, attr->prog_ifindex); 51 attr->prog_ifindex);
48 if (!offload->netdev) { 52 if (!offload->netdev)
49 rtnl_unlock(); 53 goto err_free;
50 kfree(offload);
51 return -EINVAL;
52 }
53 54
55 down_write(&bpf_devs_lock);
56 if (offload->netdev->reg_state != NETREG_REGISTERED)
57 goto err_unlock;
54 prog->aux->offload = offload; 58 prog->aux->offload = offload;
55 list_add_tail(&offload->offloads, &bpf_prog_offload_devs); 59 list_add_tail(&offload->offloads, &bpf_prog_offload_devs);
56 rtnl_unlock(); 60 dev_put(offload->netdev);
61 up_write(&bpf_devs_lock);
57 62
58 return 0; 63 return 0;
64err_unlock:
65 up_write(&bpf_devs_lock);
66 dev_put(offload->netdev);
67err_free:
68 kfree(offload);
69 return -EINVAL;
59} 70}
60 71
61static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd, 72static int __bpf_offload_ndo(struct bpf_prog *prog, enum bpf_netdev_command cmd,
62 struct netdev_bpf *data) 73 struct netdev_bpf *data)
63{ 74{
64 struct net_device *netdev = prog->aux->offload->netdev; 75 struct bpf_dev_offload *offload = prog->aux->offload;
76 struct net_device *netdev;
65 77
66 ASSERT_RTNL(); 78 ASSERT_RTNL();
67 79
68 if (!netdev) 80 if (!offload)
69 return -ENODEV; 81 return -ENODEV;
82 netdev = offload->netdev;
70 if (!netdev->netdev_ops->ndo_bpf) 83 if (!netdev->netdev_ops->ndo_bpf)
71 return -EOPNOTSUPP; 84 return -EOPNOTSUPP;
72 85
@@ -87,62 +100,63 @@ int bpf_prog_offload_verifier_prep(struct bpf_verifier_env *env)
87 if (err) 100 if (err)
88 goto exit_unlock; 101 goto exit_unlock;
89 102
90 env->dev_ops = data.verifier.ops; 103 env->prog->aux->offload->dev_ops = data.verifier.ops;
91
92 env->prog->aux->offload->dev_state = true; 104 env->prog->aux->offload->dev_state = true;
93 env->prog->aux->offload->verifier_running = true;
94exit_unlock: 105exit_unlock:
95 rtnl_unlock(); 106 rtnl_unlock();
96 return err; 107 return err;
97} 108}
98 109
110int bpf_prog_offload_verify_insn(struct bpf_verifier_env *env,
111 int insn_idx, int prev_insn_idx)
112{
113 struct bpf_dev_offload *offload;
114 int ret = -ENODEV;
115
116 down_read(&bpf_devs_lock);
117 offload = env->prog->aux->offload;
118 if (offload)
119 ret = offload->dev_ops->insn_hook(env, insn_idx, prev_insn_idx);
120 up_read(&bpf_devs_lock);
121
122 return ret;
123}
124
99static void __bpf_prog_offload_destroy(struct bpf_prog *prog) 125static void __bpf_prog_offload_destroy(struct bpf_prog *prog)
100{ 126{
101 struct bpf_dev_offload *offload = prog->aux->offload; 127 struct bpf_dev_offload *offload = prog->aux->offload;
102 struct netdev_bpf data = {}; 128 struct netdev_bpf data = {};
103 129
104 /* Caution - if netdev is destroyed before the program, this function
105 * will be called twice.
106 */
107
108 data.offload.prog = prog; 130 data.offload.prog = prog;
109 131
110 if (offload->verifier_running)
111 wait_event(offload->verifier_done, !offload->verifier_running);
112
113 if (offload->dev_state) 132 if (offload->dev_state)
114 WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data)); 133 WARN_ON(__bpf_offload_ndo(prog, BPF_OFFLOAD_DESTROY, &data));
115 134
116 offload->dev_state = false; 135 /* Make sure BPF_PROG_GET_NEXT_ID can't find this dead program */
136 bpf_prog_free_id(prog, true);
137
117 list_del_init(&offload->offloads); 138 list_del_init(&offload->offloads);
118 offload->netdev = NULL; 139 kfree(offload);
140 prog->aux->offload = NULL;
119} 141}
120 142
121void bpf_prog_offload_destroy(struct bpf_prog *prog) 143void bpf_prog_offload_destroy(struct bpf_prog *prog)
122{ 144{
123 struct bpf_dev_offload *offload = prog->aux->offload;
124
125 offload->verifier_running = false;
126 wake_up(&offload->verifier_done);
127
128 rtnl_lock(); 145 rtnl_lock();
129 __bpf_prog_offload_destroy(prog); 146 down_write(&bpf_devs_lock);
147 if (prog->aux->offload)
148 __bpf_prog_offload_destroy(prog);
149 up_write(&bpf_devs_lock);
130 rtnl_unlock(); 150 rtnl_unlock();
131
132 kfree(offload);
133} 151}
134 152
135static int bpf_prog_offload_translate(struct bpf_prog *prog) 153static int bpf_prog_offload_translate(struct bpf_prog *prog)
136{ 154{
137 struct bpf_dev_offload *offload = prog->aux->offload;
138 struct netdev_bpf data = {}; 155 struct netdev_bpf data = {};
139 int ret; 156 int ret;
140 157
141 data.offload.prog = prog; 158 data.offload.prog = prog;
142 159
143 offload->verifier_running = false;
144 wake_up(&offload->verifier_done);
145
146 rtnl_lock(); 160 rtnl_lock();
147 ret = __bpf_offload_ndo(prog, BPF_OFFLOAD_TRANSLATE, &data); 161 ret = __bpf_offload_ndo(prog, BPF_OFFLOAD_TRANSLATE, &data);
148 rtnl_unlock(); 162 rtnl_unlock();
@@ -164,6 +178,63 @@ int bpf_prog_offload_compile(struct bpf_prog *prog)
164 return bpf_prog_offload_translate(prog); 178 return bpf_prog_offload_translate(prog);
165} 179}
166 180
181struct ns_get_path_bpf_prog_args {
182 struct bpf_prog *prog;
183 struct bpf_prog_info *info;
184};
185
186static struct ns_common *bpf_prog_offload_info_fill_ns(void *private_data)
187{
188 struct ns_get_path_bpf_prog_args *args = private_data;
189 struct bpf_prog_aux *aux = args->prog->aux;
190 struct ns_common *ns;
191 struct net *net;
192
193 rtnl_lock();
194 down_read(&bpf_devs_lock);
195
196 if (aux->offload) {
197 args->info->ifindex = aux->offload->netdev->ifindex;
198 net = dev_net(aux->offload->netdev);
199 get_net(net);
200 ns = &net->ns;
201 } else {
202 args->info->ifindex = 0;
203 ns = NULL;
204 }
205
206 up_read(&bpf_devs_lock);
207 rtnl_unlock();
208
209 return ns;
210}
211
212int bpf_prog_offload_info_fill(struct bpf_prog_info *info,
213 struct bpf_prog *prog)
214{
215 struct ns_get_path_bpf_prog_args args = {
216 .prog = prog,
217 .info = info,
218 };
219 struct inode *ns_inode;
220 struct path ns_path;
221 void *res;
222
223 res = ns_get_path_cb(&ns_path, bpf_prog_offload_info_fill_ns, &args);
224 if (IS_ERR(res)) {
225 if (!info->ifindex)
226 return -ENODEV;
227 return PTR_ERR(res);
228 }
229
230 ns_inode = ns_path.dentry->d_inode;
231 info->netns_dev = new_encode_dev(ns_inode->i_sb->s_dev);
232 info->netns_ino = ns_inode->i_ino;
233 path_put(&ns_path);
234
235 return 0;
236}
237
167const struct bpf_prog_ops bpf_offload_prog_ops = { 238const struct bpf_prog_ops bpf_offload_prog_ops = {
168}; 239};
169 240
@@ -181,11 +252,13 @@ static int bpf_offload_notification(struct notifier_block *notifier,
181 if (netdev->reg_state != NETREG_UNREGISTERING) 252 if (netdev->reg_state != NETREG_UNREGISTERING)
182 break; 253 break;
183 254
255 down_write(&bpf_devs_lock);
184 list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs, 256 list_for_each_entry_safe(offload, tmp, &bpf_prog_offload_devs,
185 offloads) { 257 offloads) {
186 if (offload->netdev == netdev) 258 if (offload->netdev == netdev)
187 __bpf_prog_offload_destroy(offload->prog); 259 __bpf_prog_offload_destroy(offload->prog);
188 } 260 }
261 up_write(&bpf_devs_lock);
189 break; 262 break;
190 default: 263 default:
191 break; 264 break;
diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c
index 007802c5ca7d..ebf0fb23e237 100644
--- a/kernel/bpf/syscall.c
+++ b/kernel/bpf/syscall.c
@@ -905,9 +905,13 @@ static int bpf_prog_alloc_id(struct bpf_prog *prog)
905 return id > 0 ? 0 : id; 905 return id > 0 ? 0 : id;
906} 906}
907 907
908static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock) 908void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
909{ 909{
910 /* cBPF to eBPF migrations are currently not in the idr store. */ 910 /* cBPF to eBPF migrations are currently not in the idr store.
911 * Offloaded programs are removed from the store when their device
912 * disappears - even if someone grabs an fd to them they are unusable,
913 * simply waiting for refcnt to drop to be freed.
914 */
911 if (!prog->aux->id) 915 if (!prog->aux->id)
912 return; 916 return;
913 917
@@ -917,6 +921,7 @@ static void bpf_prog_free_id(struct bpf_prog *prog, bool do_idr_lock)
917 __acquire(&prog_idr_lock); 921 __acquire(&prog_idr_lock);
918 922
919 idr_remove(&prog_idr, prog->aux->id); 923 idr_remove(&prog_idr, prog->aux->id);
924 prog->aux->id = 0;
920 925
921 if (do_idr_lock) 926 if (do_idr_lock)
922 spin_unlock_bh(&prog_idr_lock); 927 spin_unlock_bh(&prog_idr_lock);
@@ -1157,6 +1162,8 @@ static int bpf_prog_load(union bpf_attr *attr)
1157 if (!prog) 1162 if (!prog)
1158 return -ENOMEM; 1163 return -ENOMEM;
1159 1164
1165 prog->aux->offload_requested = !!attr->prog_ifindex;
1166
1160 err = security_bpf_prog_alloc(prog->aux); 1167 err = security_bpf_prog_alloc(prog->aux);
1161 if (err) 1168 if (err)
1162 goto free_prog_nouncharge; 1169 goto free_prog_nouncharge;
@@ -1178,7 +1185,7 @@ static int bpf_prog_load(union bpf_attr *attr)
1178 atomic_set(&prog->aux->refcnt, 1); 1185 atomic_set(&prog->aux->refcnt, 1);
1179 prog->gpl_compatible = is_gpl ? 1 : 0; 1186 prog->gpl_compatible = is_gpl ? 1 : 0;
1180 1187
1181 if (attr->prog_ifindex) { 1188 if (bpf_prog_is_dev_bound(prog->aux)) {
1182 err = bpf_prog_offload_init(prog, attr); 1189 err = bpf_prog_offload_init(prog, attr);
1183 if (err) 1190 if (err)
1184 goto free_prog; 1191 goto free_prog;
@@ -1700,6 +1707,12 @@ static int bpf_prog_get_info_by_fd(struct bpf_prog *prog,
1700 return -EFAULT; 1707 return -EFAULT;
1701 } 1708 }
1702 1709
1710 if (bpf_prog_is_dev_bound(prog->aux)) {
1711 err = bpf_prog_offload_info_fill(&info, prog);
1712 if (err)
1713 return err;
1714 }
1715
1703done: 1716done:
1704 if (copy_to_user(uinfo, &info, info_len) || 1717 if (copy_to_user(uinfo, &info, info_len) ||
1705 put_user(info_len, &uattr->info.info_len)) 1718 put_user(info_len, &uattr->info.info_len))
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 98d8637cf70d..a2b211262c25 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -4438,15 +4438,6 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
4438 return 0; 4438 return 0;
4439} 4439}
4440 4440
4441static int ext_analyzer_insn_hook(struct bpf_verifier_env *env,
4442 int insn_idx, int prev_insn_idx)
4443{
4444 if (env->dev_ops && env->dev_ops->insn_hook)
4445 return env->dev_ops->insn_hook(env, insn_idx, prev_insn_idx);
4446
4447 return 0;
4448}
4449
4450static int do_check(struct bpf_verifier_env *env) 4441static int do_check(struct bpf_verifier_env *env)
4451{ 4442{
4452 struct bpf_verifier_state *state; 4443 struct bpf_verifier_state *state;
@@ -4531,9 +4522,12 @@ static int do_check(struct bpf_verifier_env *env)
4531 print_bpf_insn(&cbs, env, insn, env->allow_ptr_leaks); 4522 print_bpf_insn(&cbs, env, insn, env->allow_ptr_leaks);
4532 } 4523 }
4533 4524
4534 err = ext_analyzer_insn_hook(env, insn_idx, prev_insn_idx); 4525 if (bpf_prog_is_dev_bound(env->prog->aux)) {
4535 if (err) 4526 err = bpf_prog_offload_verify_insn(env, insn_idx,
4536 return err; 4527 prev_insn_idx);
4528 if (err)
4529 return err;
4530 }
4537 4531
4538 regs = cur_regs(env); 4532 regs = cur_regs(env);
4539 env->insn_aux_data[insn_idx].seen = true; 4533 env->insn_aux_data[insn_idx].seen = true;
@@ -5463,7 +5457,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr)
5463 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) 5457 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS))
5464 env->strict_alignment = true; 5458 env->strict_alignment = true;
5465 5459
5466 if (env->prog->aux->offload) { 5460 if (bpf_prog_is_dev_bound(env->prog->aux)) {
5467 ret = bpf_prog_offload_verifier_prep(env); 5461 ret = bpf_prog_offload_verifier_prep(env);
5468 if (ret) 5462 if (ret)
5469 goto err_unlock; 5463 goto err_unlock;
diff --git a/tools/bpf/bpftool/common.c b/tools/bpf/bpftool/common.c
index b62c94e3997a..6601c95a9258 100644
--- a/tools/bpf/bpftool/common.c
+++ b/tools/bpf/bpftool/common.c
@@ -44,7 +44,9 @@
44#include <unistd.h> 44#include <unistd.h>
45#include <linux/limits.h> 45#include <linux/limits.h>
46#include <linux/magic.h> 46#include <linux/magic.h>
47#include <net/if.h>
47#include <sys/mount.h> 48#include <sys/mount.h>
49#include <sys/stat.h>
48#include <sys/types.h> 50#include <sys/types.h>
49#include <sys/vfs.h> 51#include <sys/vfs.h>
50 52
@@ -412,3 +414,53 @@ void delete_pinned_obj_table(struct pinned_obj_table *tab)
412 free(obj); 414 free(obj);
413 } 415 }
414} 416}
417
418static char *
419ifindex_to_name_ns(__u32 ifindex, __u32 ns_dev, __u32 ns_ino, char *buf)
420{
421 struct stat st;
422 int err;
423
424 err = stat("/proc/self/ns/net", &st);
425 if (err) {
426 p_err("Can't stat /proc/self: %s", strerror(errno));
427 return NULL;
428 }
429
430 if (st.st_dev != ns_dev || st.st_ino != ns_ino)
431 return NULL;
432
433 return if_indextoname(ifindex, buf);
434}
435
436void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
437{
438 char name[IF_NAMESIZE];
439
440 if (!ifindex)
441 return;
442
443 printf(" dev ");
444 if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
445 printf("%s", name);
446 else
447 printf("ifindex %u ns_dev %llu ns_ino %llu",
448 ifindex, ns_dev, ns_inode);
449}
450
451void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode)
452{
453 char name[IF_NAMESIZE];
454
455 if (!ifindex)
456 return;
457
458 jsonw_name(json_wtr, "dev");
459 jsonw_start_object(json_wtr);
460 jsonw_uint_field(json_wtr, "ifindex", ifindex);
461 jsonw_uint_field(json_wtr, "ns_dev", ns_dev);
462 jsonw_uint_field(json_wtr, "ns_inode", ns_inode);
463 if (ifindex_to_name_ns(ifindex, ns_dev, ns_inode, name))
464 jsonw_string_field(json_wtr, "ifname", name);
465 jsonw_end_object(json_wtr);
466}
diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h
index 8f6d3cac0347..65b526fe6e7e 100644
--- a/tools/bpf/bpftool/main.h
+++ b/tools/bpf/bpftool/main.h
@@ -96,6 +96,8 @@ struct pinned_obj {
96int build_pinned_obj_table(struct pinned_obj_table *table, 96int build_pinned_obj_table(struct pinned_obj_table *table,
97 enum bpf_obj_type type); 97 enum bpf_obj_type type);
98void delete_pinned_obj_table(struct pinned_obj_table *tab); 98void delete_pinned_obj_table(struct pinned_obj_table *tab);
99void print_dev_plain(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);
100void print_dev_json(__u32 ifindex, __u64 ns_dev, __u64 ns_inode);
99 101
100struct cmd { 102struct cmd {
101 const char *cmd; 103 const char *cmd;
diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c
index fd0873178503..98f871ed53d6 100644
--- a/tools/bpf/bpftool/prog.c
+++ b/tools/bpf/bpftool/prog.c
@@ -230,6 +230,8 @@ static void print_prog_json(struct bpf_prog_info *info, int fd)
230 info->tag[0], info->tag[1], info->tag[2], info->tag[3], 230 info->tag[0], info->tag[1], info->tag[2], info->tag[3],
231 info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 231 info->tag[4], info->tag[5], info->tag[6], info->tag[7]);
232 232
233 print_dev_json(info->ifindex, info->netns_dev, info->netns_ino);
234
233 if (info->load_time) { 235 if (info->load_time) {
234 char buf[32]; 236 char buf[32];
235 237
@@ -287,6 +289,7 @@ static void print_prog_plain(struct bpf_prog_info *info, int fd)
287 289
288 printf("tag "); 290 printf("tag ");
289 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 291 fprint_hex(stdout, info->tag, BPF_TAG_SIZE, "");
292 print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino);
290 printf("\n"); 293 printf("\n");
291 294
292 if (info->load_time) { 295 if (info->load_time) {
diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h
index db1b0923a308..4e8c60acfa32 100644
--- a/tools/include/uapi/linux/bpf.h
+++ b/tools/include/uapi/linux/bpf.h
@@ -921,6 +921,9 @@ struct bpf_prog_info {
921 __u32 nr_map_ids; 921 __u32 nr_map_ids;
922 __aligned_u64 map_ids; 922 __aligned_u64 map_ids;
923 char name[BPF_OBJ_NAME_LEN]; 923 char name[BPF_OBJ_NAME_LEN];
924 __u32 ifindex;
925 __u64 netns_dev;
926 __u64 netns_ino;
924} __attribute__((aligned(8))); 927} __attribute__((aligned(8)));
925 928
926struct bpf_map_info { 929struct bpf_map_info {
diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py
index c940505c2978..e3c750f17cb8 100755
--- a/tools/testing/selftests/bpf/test_offload.py
+++ b/tools/testing/selftests/bpf/test_offload.py
@@ -18,6 +18,8 @@ import argparse
18import json 18import json
19import os 19import os
20import pprint 20import pprint
21import random
22import string
21import subprocess 23import subprocess
22import time 24import time
23 25
@@ -27,6 +29,7 @@ bpf_test_dir = os.path.dirname(os.path.realpath(__file__))
27pp = pprint.PrettyPrinter() 29pp = pprint.PrettyPrinter()
28devs = [] # devices we created for clean up 30devs = [] # devices we created for clean up
29files = [] # files to be removed 31files = [] # files to be removed
32netns = [] # net namespaces to be removed
30 33
31def log_get_sec(level=0): 34def log_get_sec(level=0):
32 return "*" * (log_level + level) 35 return "*" * (log_level + level)
@@ -128,22 +131,25 @@ def rm(f):
128 if f in files: 131 if f in files:
129 files.remove(f) 132 files.remove(f)
130 133
131def tool(name, args, flags, JSON=True, fail=True): 134def tool(name, args, flags, JSON=True, ns="", fail=True):
132 params = "" 135 params = ""
133 if JSON: 136 if JSON:
134 params += "%s " % (flags["json"]) 137 params += "%s " % (flags["json"])
135 138
136 ret, out = cmd(name + " " + params + args, fail=fail) 139 if ns != "":
140 ns = "ip netns exec %s " % (ns)
141
142 ret, out = cmd(ns + name + " " + params + args, fail=fail)
137 if JSON and len(out.strip()) != 0: 143 if JSON and len(out.strip()) != 0:
138 return ret, json.loads(out) 144 return ret, json.loads(out)
139 else: 145 else:
140 return ret, out 146 return ret, out
141 147
142def bpftool(args, JSON=True, fail=True): 148def bpftool(args, JSON=True, ns="", fail=True):
143 return tool("bpftool", args, {"json":"-p"}, JSON=JSON, fail=fail) 149 return tool("bpftool", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail)
144 150
145def bpftool_prog_list(expected=None): 151def bpftool_prog_list(expected=None, ns=""):
146 _, progs = bpftool("prog show", JSON=True, fail=True) 152 _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True)
147 if expected is not None: 153 if expected is not None:
148 if len(progs) != expected: 154 if len(progs) != expected:
149 fail(True, "%d BPF programs loaded, expected %d" % 155 fail(True, "%d BPF programs loaded, expected %d" %
@@ -158,13 +164,13 @@ def bpftool_prog_list_wait(expected=0, n_retry=20):
158 time.sleep(0.05) 164 time.sleep(0.05)
159 raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs)) 165 raise Exception("Time out waiting for program counts to stabilize want %d, have %d" % (expected, nprogs))
160 166
161def ip(args, force=False, JSON=True, fail=True): 167def ip(args, force=False, JSON=True, ns="", fail=True):
162 if force: 168 if force:
163 args = "-force " + args 169 args = "-force " + args
164 return tool("ip", args, {"json":"-j"}, JSON=JSON, fail=fail) 170 return tool("ip", args, {"json":"-j"}, JSON=JSON, ns=ns, fail=fail)
165 171
166def tc(args, JSON=True, fail=True): 172def tc(args, JSON=True, ns="", fail=True):
167 return tool("tc", args, {"json":"-p"}, JSON=JSON, fail=fail) 173 return tool("tc", args, {"json":"-p"}, JSON=JSON, ns=ns, fail=fail)
168 174
169def ethtool(dev, opt, args, fail=True): 175def ethtool(dev, opt, args, fail=True):
170 return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail) 176 return cmd("ethtool %s %s %s" % (opt, dev["ifname"], args), fail=fail)
@@ -178,6 +184,15 @@ def bpf_pinned(name):
178def bpf_bytecode(bytecode): 184def bpf_bytecode(bytecode):
179 return "bytecode \"%s\"" % (bytecode) 185 return "bytecode \"%s\"" % (bytecode)
180 186
187def mknetns(n_retry=10):
188 for i in range(n_retry):
189 name = ''.join([random.choice(string.ascii_letters) for i in range(8)])
190 ret, _ = ip("netns add %s" % (name), fail=False)
191 if ret == 0:
192 netns.append(name)
193 return name
194 return None
195
181class DebugfsDir: 196class DebugfsDir:
182 """ 197 """
183 Class for accessing DebugFS directories as a dictionary. 198 Class for accessing DebugFS directories as a dictionary.
@@ -237,6 +252,8 @@ class NetdevSim:
237 self.dev = self._netdevsim_create() 252 self.dev = self._netdevsim_create()
238 devs.append(self) 253 devs.append(self)
239 254
255 self.ns = ""
256
240 self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname']) 257 self.dfs_dir = '/sys/kernel/debug/netdevsim/%s' % (self.dev['ifname'])
241 self.dfs_refresh() 258 self.dfs_refresh()
242 259
@@ -257,7 +274,7 @@ class NetdevSim:
257 274
258 def remove(self): 275 def remove(self):
259 devs.remove(self) 276 devs.remove(self)
260 ip("link del dev %s" % (self.dev["ifname"])) 277 ip("link del dev %s" % (self.dev["ifname"]), ns=self.ns)
261 278
262 def dfs_refresh(self): 279 def dfs_refresh(self):
263 self.dfs = DebugfsDir(self.dfs_dir) 280 self.dfs = DebugfsDir(self.dfs_dir)
@@ -285,6 +302,11 @@ class NetdevSim:
285 time.sleep(0.05) 302 time.sleep(0.05)
286 raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs)) 303 raise Exception("Time out waiting for program counts to stabilize want %d/%d, have %d bound, %d loaded" % (bound, total, nbound, nprogs))
287 304
305 def set_ns(self, ns):
306 name = "1" if ns == "" else ns
307 ip("link set dev %s netns %s" % (self.dev["ifname"], name), ns=self.ns)
308 self.ns = ns
309
288 def set_mtu(self, mtu, fail=True): 310 def set_mtu(self, mtu, fail=True):
289 return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu), 311 return ip("link set dev %s mtu %d" % (self.dev["ifname"], mtu),
290 fail=fail) 312 fail=fail)
@@ -372,6 +394,8 @@ def clean_up():
372 dev.remove() 394 dev.remove()
373 for f in files: 395 for f in files:
374 cmd("rm -f %s" % (f)) 396 cmd("rm -f %s" % (f))
397 for ns in netns:
398 cmd("ip netns delete %s" % (ns))
375 399
376def pin_prog(file_name, idx=0): 400def pin_prog(file_name, idx=0):
377 progs = bpftool_prog_list(expected=(idx + 1)) 401 progs = bpftool_prog_list(expected=(idx + 1))
@@ -381,6 +405,35 @@ def pin_prog(file_name, idx=0):
381 405
382 return file_name, bpf_pinned(file_name) 406 return file_name, bpf_pinned(file_name)
383 407
408def check_dev_info(other_ns, ns, pin_file=None, removed=False):
409 if removed:
410 bpftool_prog_list(expected=0)
411 ret, err = bpftool("prog show pin %s" % (pin_file), fail=False)
412 fail(ret == 0, "Showing prog with removed device did not fail")
413 fail(err["error"].find("No such device") == -1,
414 "Showing prog with removed device expected ENODEV, error is %s" %
415 (err["error"]))
416 return
417 progs = bpftool_prog_list(expected=int(not removed), ns=ns)
418 prog = progs[0]
419
420 fail("dev" not in prog.keys(), "Device parameters not reported")
421 dev = prog["dev"]
422 fail("ifindex" not in dev.keys(), "Device parameters not reported")
423 fail("ns_dev" not in dev.keys(), "Device parameters not reported")
424 fail("ns_inode" not in dev.keys(), "Device parameters not reported")
425
426 if not removed and not other_ns:
427 fail("ifname" not in dev.keys(), "Ifname not reported")
428 fail(dev["ifname"] != sim["ifname"],
429 "Ifname incorrect %s vs %s" % (dev["ifname"], sim["ifname"]))
430 else:
431 fail("ifname" in dev.keys(), "Ifname is reported for other ns")
432 if removed:
433 fail(dev["ifindex"] != 0, "Device perameters not zero on removed")
434 fail(dev["ns_dev"] != 0, "Device perameters not zero on removed")
435 fail(dev["ns_inode"] != 0, "Device perameters not zero on removed")
436
384# Parse command line 437# Parse command line
385parser = argparse.ArgumentParser() 438parser = argparse.ArgumentParser()
386parser.add_argument("--log", help="output verbose log to given file") 439parser.add_argument("--log", help="output verbose log to given file")
@@ -417,6 +470,12 @@ for s in samples:
417 skip(ret != 0, "sample %s/%s not found, please compile it" % 470 skip(ret != 0, "sample %s/%s not found, please compile it" %
418 (bpf_test_dir, s)) 471 (bpf_test_dir, s))
419 472
473# Check if net namespaces seem to work
474ns = mknetns()
475skip(ns is None, "Could not create a net namespace")
476cmd("ip netns delete %s" % (ns))
477netns = []
478
420try: 479try:
421 obj = bpf_obj("sample_ret0.o") 480 obj = bpf_obj("sample_ret0.o")
422 bytecode = bpf_bytecode("1,6 0 0 4294967295,") 481 bytecode = bpf_bytecode("1,6 0 0 4294967295,")
@@ -549,6 +608,8 @@ try:
549 progs = bpftool_prog_list(expected=1) 608 progs = bpftool_prog_list(expected=1)
550 fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"], 609 fail(ipl["xdp"]["prog"]["id"] != progs[0]["id"],
551 "Loaded program has wrong ID") 610 "Loaded program has wrong ID")
611 fail("dev" in progs[0].keys(),
612 "Device parameters reported for non-offloaded program")
552 613
553 start_test("Test XDP prog replace with bad flags...") 614 start_test("Test XDP prog replace with bad flags...")
554 ret, _ = sim.set_xdp(obj, "offload", force=True, fail=False) 615 ret, _ = sim.set_xdp(obj, "offload", force=True, fail=False)
@@ -673,6 +734,35 @@ try:
673 fail(time_diff < delay_sec, "Removal process took %s, expected %s" % 734 fail(time_diff < delay_sec, "Removal process took %s, expected %s" %
674 (time_diff, delay_sec)) 735 (time_diff, delay_sec))
675 736
737 # Remove all pinned files and reinstantiate the netdev
738 clean_up()
739 bpftool_prog_list_wait(expected=0)
740
741 sim = NetdevSim()
742 sim.set_ethtool_tc_offloads(True)
743 sim.set_xdp(obj, "offload")
744
745 start_test("Test bpftool bound info reporting (own ns)...")
746 check_dev_info(False, "")
747
748 start_test("Test bpftool bound info reporting (other ns)...")
749 ns = mknetns()
750 sim.set_ns(ns)
751 check_dev_info(True, "")
752
753 start_test("Test bpftool bound info reporting (remote ns)...")
754 check_dev_info(False, ns)
755
756 start_test("Test bpftool bound info reporting (back to own ns)...")
757 sim.set_ns("")
758 check_dev_info(False, "")
759
760 pin_file, _ = pin_prog("/sys/fs/bpf/tmp")
761 sim.remove()
762
763 start_test("Test bpftool bound info reporting (removed dev)...")
764 check_dev_info(True, "", pin_file=pin_file, removed=True)
765
676 print("%s: OK" % (os.path.basename(__file__))) 766 print("%s: OK" % (os.path.basename(__file__)))
677 767
678finally: 768finally: