@@ -41,7 +41,7 @@ struct bpf_offload_dev {
4141struct bpf_offload_netdev {
4242 struct rhash_head l ;
4343 struct net_device * netdev ;
44- struct bpf_offload_dev * offdev ;
44+ struct bpf_offload_dev * offdev ; /* NULL when bound-only */
4545 struct list_head progs ;
4646 struct list_head maps ;
4747 struct list_head offdev_netdevs ;
@@ -89,19 +89,17 @@ static int __bpf_offload_dev_netdev_register(struct bpf_offload_dev *offdev,
8989 INIT_LIST_HEAD (& ondev -> progs );
9090 INIT_LIST_HEAD (& ondev -> maps );
9191
92- down_write (& bpf_devs_lock );
9392 err = rhashtable_insert_fast (& offdevs , & ondev -> l , offdevs_params );
9493 if (err ) {
9594 netdev_warn (netdev , "failed to register for BPF offload\n" );
96- goto err_unlock_free ;
95+ goto err_free ;
9796 }
9897
99- list_add ( & ondev -> offdev_netdevs , & offdev -> netdevs );
100- up_write ( & bpf_devs_lock );
98+ if ( offdev )
99+ list_add ( & ondev -> offdev_netdevs , & offdev -> netdevs );
101100 return 0 ;
102101
103- err_unlock_free :
104- up_write (& bpf_devs_lock );
102+ err_free :
105103 kfree (ondev );
106104 return err ;
107105}
@@ -149,24 +147,26 @@ static void __bpf_map_offload_destroy(struct bpf_offloaded_map *offmap)
149147static void __bpf_offload_dev_netdev_unregister (struct bpf_offload_dev * offdev ,
150148 struct net_device * netdev )
151149{
152- struct bpf_offload_netdev * ondev , * altdev ;
150+ struct bpf_offload_netdev * ondev , * altdev = NULL ;
153151 struct bpf_offloaded_map * offmap , * mtmp ;
154152 struct bpf_prog_offload * offload , * ptmp ;
155153
156154 ASSERT_RTNL ();
157155
158- down_write (& bpf_devs_lock );
159156 ondev = rhashtable_lookup_fast (& offdevs , & netdev , offdevs_params );
160157 if (WARN_ON (!ondev ))
161- goto unlock ;
158+ return ;
162159
163160 WARN_ON (rhashtable_remove_fast (& offdevs , & ondev -> l , offdevs_params ));
164- list_del (& ondev -> offdev_netdevs );
165161
166162 /* Try to move the objects to another netdev of the device */
167- altdev = list_first_entry_or_null (& offdev -> netdevs ,
168- struct bpf_offload_netdev ,
169- offdev_netdevs );
163+ if (offdev ) {
164+ list_del (& ondev -> offdev_netdevs );
165+ altdev = list_first_entry_or_null (& offdev -> netdevs ,
166+ struct bpf_offload_netdev ,
167+ offdev_netdevs );
168+ }
169+
170170 if (altdev ) {
171171 list_for_each_entry (offload , & ondev -> progs , offloads )
172172 offload -> netdev = altdev -> netdev ;
@@ -185,11 +185,9 @@ static void __bpf_offload_dev_netdev_unregister(struct bpf_offload_dev *offdev,
185185 WARN_ON (!list_empty (& ondev -> progs ));
186186 WARN_ON (!list_empty (& ondev -> maps ));
187187 kfree (ondev );
188- unlock :
189- up_write (& bpf_devs_lock );
190188}
191189
192- int bpf_prog_offload_init (struct bpf_prog * prog , union bpf_attr * attr )
190+ int bpf_prog_dev_bound_init (struct bpf_prog * prog , union bpf_attr * attr )
193191{
194192 struct bpf_offload_netdev * ondev ;
195193 struct bpf_prog_offload * offload ;
@@ -199,7 +197,11 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
199197 attr -> prog_type != BPF_PROG_TYPE_XDP )
200198 return - EINVAL ;
201199
202- if (attr -> prog_flags )
200+ if (attr -> prog_flags & ~BPF_F_XDP_DEV_BOUND_ONLY )
201+ return - EINVAL ;
202+
203+ if (attr -> prog_type == BPF_PROG_TYPE_SCHED_CLS &&
204+ attr -> prog_flags & BPF_F_XDP_DEV_BOUND_ONLY )
203205 return - EINVAL ;
204206
205207 offload = kzalloc (sizeof (* offload ), GFP_USER );
@@ -214,11 +216,23 @@ int bpf_prog_offload_init(struct bpf_prog *prog, union bpf_attr *attr)
214216 if (err )
215217 goto err_maybe_put ;
216218
219+ prog -> aux -> offload_requested = !(attr -> prog_flags & BPF_F_XDP_DEV_BOUND_ONLY );
220+
217221 down_write (& bpf_devs_lock );
218222 ondev = bpf_offload_find_netdev (offload -> netdev );
219223 if (!ondev ) {
220- err = - EINVAL ;
221- goto err_unlock ;
224+ if (bpf_prog_is_offloaded (prog -> aux )) {
225+ err = - EINVAL ;
226+ goto err_unlock ;
227+ }
228+
229+ /* When only binding to the device, explicitly
230+ * create an entry in the hashtable.
231+ */
232+ err = __bpf_offload_dev_netdev_register (NULL , offload -> netdev );
233+ if (err )
234+ goto err_unlock ;
235+ ondev = bpf_offload_find_netdev (offload -> netdev );
222236 }
223237 offload -> offdev = ondev -> offdev ;
224238 prog -> aux -> offload = offload ;
@@ -321,12 +335,25 @@ bpf_prog_offload_remove_insns(struct bpf_verifier_env *env, u32 off, u32 cnt)
321335 up_read (& bpf_devs_lock );
322336}
323337
324- void bpf_prog_offload_destroy (struct bpf_prog * prog )
338+ void bpf_prog_dev_bound_destroy (struct bpf_prog * prog )
325339{
340+ struct bpf_offload_netdev * ondev ;
341+ struct net_device * netdev ;
342+
343+ rtnl_lock ();
326344 down_write (& bpf_devs_lock );
327- if (prog -> aux -> offload )
345+ if (prog -> aux -> offload ) {
346+ list_del_init (& prog -> aux -> offload -> offloads );
347+
348+ netdev = prog -> aux -> offload -> netdev ;
328349 __bpf_prog_offload_destroy (prog );
350+
351+ ondev = bpf_offload_find_netdev (netdev );
352+ if (!ondev -> offdev && list_empty (& ondev -> progs ))
353+ __bpf_offload_dev_netdev_unregister (NULL , netdev );
354+ }
329355 up_write (& bpf_devs_lock );
356+ rtnl_unlock ();
330357}
331358
332359static int bpf_prog_offload_translate (struct bpf_prog * prog )
@@ -621,7 +648,7 @@ static bool __bpf_offload_dev_match(struct bpf_prog *prog,
621648 struct bpf_offload_netdev * ondev1 , * ondev2 ;
622649 struct bpf_prog_offload * offload ;
623650
624- if (!bpf_prog_is_offloaded (prog -> aux ))
651+ if (!bpf_prog_is_dev_bound (prog -> aux ))
625652 return false;
626653
627654 offload = prog -> aux -> offload ;
@@ -667,14 +694,21 @@ bool bpf_offload_prog_map_match(struct bpf_prog *prog, struct bpf_map *map)
667694int bpf_offload_dev_netdev_register (struct bpf_offload_dev * offdev ,
668695 struct net_device * netdev )
669696{
670- return __bpf_offload_dev_netdev_register (offdev , netdev );
697+ int err ;
698+
699+ down_write (& bpf_devs_lock );
700+ err = __bpf_offload_dev_netdev_register (offdev , netdev );
701+ up_write (& bpf_devs_lock );
702+ return err ;
671703}
672704EXPORT_SYMBOL_GPL (bpf_offload_dev_netdev_register );
673705
674706void bpf_offload_dev_netdev_unregister (struct bpf_offload_dev * offdev ,
675707 struct net_device * netdev )
676708{
709+ down_write (& bpf_devs_lock );
677710 __bpf_offload_dev_netdev_unregister (offdev , netdev );
711+ up_write (& bpf_devs_lock );
678712}
679713EXPORT_SYMBOL_GPL (bpf_offload_dev_netdev_unregister );
680714
@@ -708,6 +742,19 @@ void *bpf_offload_dev_priv(struct bpf_offload_dev *offdev)
708742}
709743EXPORT_SYMBOL_GPL (bpf_offload_dev_priv );
710744
745+ void bpf_dev_bound_netdev_unregister (struct net_device * dev )
746+ {
747+ struct bpf_offload_netdev * ondev ;
748+
749+ ASSERT_RTNL ();
750+
751+ down_write (& bpf_devs_lock );
752+ ondev = bpf_offload_find_netdev (dev );
753+ if (ondev && !ondev -> offdev )
754+ __bpf_offload_dev_netdev_unregister (NULL , ondev -> netdev );
755+ up_write (& bpf_devs_lock );
756+ }
757+
711758static int __init bpf_offload_init (void )
712759{
713760 return rhashtable_init (& offdevs , & offdevs_params );
0 commit comments