1717#include <linux/bpf_verifier.h>
1818#include <linux/debugfs.h>
1919#include <linux/kernel.h>
20+ #include <linux/mutex.h>
2021#include <linux/rtnetlink.h>
2122#include <net/pkt_cls.h>
2223
@@ -31,6 +32,19 @@ struct nsim_bpf_bound_prog {
3132 struct list_head l ;
3233};
3334
35+ #define NSIM_BPF_MAX_KEYS 2
36+
37+ struct nsim_bpf_bound_map {
38+ struct netdevsim * ns ;
39+ struct bpf_offloaded_map * map ;
40+ struct mutex mutex ;
41+ struct nsim_map_entry {
42+ void * key ;
43+ void * value ;
44+ } entry [NSIM_BPF_MAX_KEYS ];
45+ struct list_head l ;
46+ };
47+
3448static int nsim_debugfs_bpf_string_read (struct seq_file * file , void * data )
3549{
3650 const char * * str = file -> private ;
@@ -284,6 +298,224 @@ nsim_setup_prog_hw_checks(struct netdevsim *ns, struct netdev_bpf *bpf)
284298 return 0 ;
285299}
286300
301+ static bool
302+ nsim_map_key_match (struct bpf_map * map , struct nsim_map_entry * e , void * key )
303+ {
304+ return e -> key && !memcmp (key , e -> key , map -> key_size );
305+ }
306+
307+ static int nsim_map_key_find (struct bpf_offloaded_map * offmap , void * key )
308+ {
309+ struct nsim_bpf_bound_map * nmap = offmap -> dev_priv ;
310+ unsigned int i ;
311+
312+ for (i = 0 ; i < ARRAY_SIZE (nmap -> entry ); i ++ )
313+ if (nsim_map_key_match (& offmap -> map , & nmap -> entry [i ], key ))
314+ return i ;
315+
316+ return - ENOENT ;
317+ }
318+
319+ static int
320+ nsim_map_alloc_elem (struct bpf_offloaded_map * offmap , unsigned int idx )
321+ {
322+ struct nsim_bpf_bound_map * nmap = offmap -> dev_priv ;
323+
324+ nmap -> entry [idx ].key = kmalloc (offmap -> map .key_size , GFP_USER );
325+ if (!nmap -> entry [idx ].key )
326+ return - ENOMEM ;
327+ nmap -> entry [idx ].value = kmalloc (offmap -> map .value_size , GFP_USER );
328+ if (!nmap -> entry [idx ].value ) {
329+ kfree (nmap -> entry [idx ].key );
330+ nmap -> entry [idx ].key = NULL ;
331+ return - ENOMEM ;
332+ }
333+
334+ return 0 ;
335+ }
336+
337+ static int
338+ nsim_map_get_next_key (struct bpf_offloaded_map * offmap ,
339+ void * key , void * next_key )
340+ {
341+ struct nsim_bpf_bound_map * nmap = offmap -> dev_priv ;
342+ int idx = - ENOENT ;
343+
344+ mutex_lock (& nmap -> mutex );
345+
346+ if (key )
347+ idx = nsim_map_key_find (offmap , key );
348+ if (idx == - ENOENT )
349+ idx = 0 ;
350+ else
351+ idx ++ ;
352+
353+ for (; idx < ARRAY_SIZE (nmap -> entry ); idx ++ ) {
354+ if (nmap -> entry [idx ].key ) {
355+ memcpy (next_key , nmap -> entry [idx ].key ,
356+ offmap -> map .key_size );
357+ break ;
358+ }
359+ }
360+
361+ mutex_unlock (& nmap -> mutex );
362+
363+ if (idx == ARRAY_SIZE (nmap -> entry ))
364+ return - ENOENT ;
365+ return 0 ;
366+ }
367+
368+ static int
369+ nsim_map_lookup_elem (struct bpf_offloaded_map * offmap , void * key , void * value )
370+ {
371+ struct nsim_bpf_bound_map * nmap = offmap -> dev_priv ;
372+ int idx ;
373+
374+ mutex_lock (& nmap -> mutex );
375+
376+ idx = nsim_map_key_find (offmap , key );
377+ if (idx >= 0 )
378+ memcpy (value , nmap -> entry [idx ].value , offmap -> map .value_size );
379+
380+ mutex_unlock (& nmap -> mutex );
381+
382+ return idx < 0 ? idx : 0 ;
383+ }
384+
385+ static int
386+ nsim_map_update_elem (struct bpf_offloaded_map * offmap ,
387+ void * key , void * value , u64 flags )
388+ {
389+ struct nsim_bpf_bound_map * nmap = offmap -> dev_priv ;
390+ int idx , err = 0 ;
391+
392+ mutex_lock (& nmap -> mutex );
393+
394+ idx = nsim_map_key_find (offmap , key );
395+ if (idx < 0 && flags == BPF_EXIST ) {
396+ err = idx ;
397+ goto exit_unlock ;
398+ }
399+ if (idx >= 0 && flags == BPF_NOEXIST ) {
400+ err = - EEXIST ;
401+ goto exit_unlock ;
402+ }
403+
404+ if (idx < 0 ) {
405+ for (idx = 0 ; idx < ARRAY_SIZE (nmap -> entry ); idx ++ )
406+ if (!nmap -> entry [idx ].key )
407+ break ;
408+ if (idx == ARRAY_SIZE (nmap -> entry )) {
409+ err = - E2BIG ;
410+ goto exit_unlock ;
411+ }
412+
413+ err = nsim_map_alloc_elem (offmap , idx );
414+ if (err )
415+ goto exit_unlock ;
416+ }
417+
418+ memcpy (nmap -> entry [idx ].key , key , offmap -> map .key_size );
419+ memcpy (nmap -> entry [idx ].value , value , offmap -> map .value_size );
420+ exit_unlock :
421+ mutex_unlock (& nmap -> mutex );
422+
423+ return err ;
424+ }
425+
426+ static int nsim_map_delete_elem (struct bpf_offloaded_map * offmap , void * key )
427+ {
428+ struct nsim_bpf_bound_map * nmap = offmap -> dev_priv ;
429+ int idx ;
430+
431+ if (offmap -> map .map_type == BPF_MAP_TYPE_ARRAY )
432+ return - EINVAL ;
433+
434+ mutex_lock (& nmap -> mutex );
435+
436+ idx = nsim_map_key_find (offmap , key );
437+ if (idx >= 0 ) {
438+ kfree (nmap -> entry [idx ].key );
439+ kfree (nmap -> entry [idx ].value );
440+ memset (& nmap -> entry [idx ], 0 , sizeof (nmap -> entry [idx ]));
441+ }
442+
443+ mutex_unlock (& nmap -> mutex );
444+
445+ return idx < 0 ? idx : 0 ;
446+ }
447+
448+ static const struct bpf_map_dev_ops nsim_bpf_map_ops = {
449+ .map_get_next_key = nsim_map_get_next_key ,
450+ .map_lookup_elem = nsim_map_lookup_elem ,
451+ .map_update_elem = nsim_map_update_elem ,
452+ .map_delete_elem = nsim_map_delete_elem ,
453+ };
454+
455+ static int
456+ nsim_bpf_map_alloc (struct netdevsim * ns , struct bpf_offloaded_map * offmap )
457+ {
458+ struct nsim_bpf_bound_map * nmap ;
459+ unsigned int i ;
460+ int err ;
461+
462+ if (WARN_ON (offmap -> map .map_type != BPF_MAP_TYPE_ARRAY &&
463+ offmap -> map .map_type != BPF_MAP_TYPE_HASH ))
464+ return - EINVAL ;
465+ if (offmap -> map .max_entries > NSIM_BPF_MAX_KEYS )
466+ return - ENOMEM ;
467+ if (offmap -> map .map_flags )
468+ return - EINVAL ;
469+
470+ nmap = kzalloc (sizeof (* nmap ), GFP_USER );
471+ if (!nmap )
472+ return - ENOMEM ;
473+
474+ offmap -> dev_priv = nmap ;
475+ nmap -> ns = ns ;
476+ nmap -> map = offmap ;
477+ mutex_init (& nmap -> mutex );
478+
479+ if (offmap -> map .map_type == BPF_MAP_TYPE_ARRAY ) {
480+ for (i = 0 ; i < ARRAY_SIZE (nmap -> entry ); i ++ ) {
481+ u32 * key ;
482+
483+ err = nsim_map_alloc_elem (offmap , i );
484+ if (err )
485+ goto err_free ;
486+ key = nmap -> entry [i ].key ;
487+ * key = i ;
488+ }
489+ }
490+
491+ offmap -> dev_ops = & nsim_bpf_map_ops ;
492+ list_add_tail (& nmap -> l , & ns -> bpf_bound_maps );
493+
494+ return 0 ;
495+
496+ err_free :
497+ while (-- i ) {
498+ kfree (nmap -> entry [i ].key );
499+ kfree (nmap -> entry [i ].value );
500+ }
501+ kfree (nmap );
502+ return err ;
503+ }
504+
505+ static void nsim_bpf_map_free (struct bpf_offloaded_map * offmap )
506+ {
507+ struct nsim_bpf_bound_map * nmap = offmap -> dev_priv ;
508+ unsigned int i ;
509+
510+ for (i = 0 ; i < ARRAY_SIZE (nmap -> entry ); i ++ ) {
511+ kfree (nmap -> entry [i ].key );
512+ kfree (nmap -> entry [i ].value );
513+ }
514+ list_del_init (& nmap -> l );
515+ mutex_destroy (& nmap -> mutex );
516+ kfree (nmap );
517+ }
518+
287519int nsim_bpf (struct net_device * dev , struct netdev_bpf * bpf )
288520{
289521 struct netdevsim * ns = netdev_priv (dev );
@@ -328,6 +560,14 @@ int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf)
328560 return err ;
329561
330562 return nsim_xdp_set_prog (ns , bpf );
563+ case BPF_OFFLOAD_MAP_ALLOC :
564+ if (!ns -> bpf_map_accept )
565+ return - EOPNOTSUPP ;
566+
567+ return nsim_bpf_map_alloc (ns , bpf -> offmap );
568+ case BPF_OFFLOAD_MAP_FREE :
569+ nsim_bpf_map_free (bpf -> offmap );
570+ return 0 ;
331571 default :
332572 return - EINVAL ;
333573 }
@@ -336,6 +576,7 @@ int nsim_bpf(struct net_device *dev, struct netdev_bpf *bpf)
336576int nsim_bpf_init (struct netdevsim * ns )
337577{
338578 INIT_LIST_HEAD (& ns -> bpf_bound_progs );
579+ INIT_LIST_HEAD (& ns -> bpf_bound_maps );
339580
340581 debugfs_create_u32 ("bpf_offloaded_id" , 0400 , ns -> ddir ,
341582 & ns -> bpf_offloaded_id );
@@ -362,12 +603,17 @@ int nsim_bpf_init(struct netdevsim *ns)
362603 debugfs_create_bool ("bpf_xdpoffload_accept" , 0600 , ns -> ddir ,
363604 & ns -> bpf_xdpoffload_accept );
364605
606+ ns -> bpf_map_accept = true;
607+ debugfs_create_bool ("bpf_map_accept" , 0600 , ns -> ddir ,
608+ & ns -> bpf_map_accept );
609+
365610 return 0 ;
366611}
367612
368613void nsim_bpf_uninit (struct netdevsim * ns )
369614{
370615 WARN_ON (!list_empty (& ns -> bpf_bound_progs ));
616+ WARN_ON (!list_empty (& ns -> bpf_bound_maps ));
371617 WARN_ON (ns -> xdp_prog );
372618 WARN_ON (ns -> bpf_offloaded );
373619}
0 commit comments