@@ -660,20 +660,29 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_memb_release, KF_RELEASE)
660660BTF_KFUNCS_END (test_sk_check_kfunc_ids )
661661
662662static void * bpf_test_init (const union bpf_attr * kattr , u32 user_size ,
663- u32 size , u32 headroom , u32 tailroom )
663+ u32 size , u32 headroom , u32 tailroom , bool nonlinear )
664664{
665665 void __user * data_in = u64_to_user_ptr (kattr -> test .data_in );
666- void * data ;
666+ void * data , * dst ;
667667
668668 if (user_size < ETH_HLEN || user_size > PAGE_SIZE - headroom - tailroom )
669669 return ERR_PTR (- EINVAL );
670670
671- size = SKB_DATA_ALIGN (size );
672- data = kzalloc (size + headroom + tailroom , GFP_USER );
671+ /* In non-linear case, data_in is copied to the paged data */
672+ if (nonlinear ) {
673+ data = alloc_page (GFP_USER );
674+ } else {
675+ size = SKB_DATA_ALIGN (size );
676+ data = kzalloc (size + headroom + tailroom , GFP_USER );
677+ }
673678 if (!data )
674679 return ERR_PTR (- ENOMEM );
675680
676- if (copy_from_user (data + headroom , data_in , user_size )) {
681+ if (nonlinear )
682+ dst = page_address (data );
683+ else
684+ dst = data + headroom ;
685+ if (copy_from_user (dst , data_in , user_size )) {
677686 kfree (data );
678687 return ERR_PTR (- EFAULT );
679688 }
@@ -984,7 +993,7 @@ static struct proto bpf_dummy_proto = {
984993int bpf_prog_test_run_skb (struct bpf_prog * prog , const union bpf_attr * kattr ,
985994 union bpf_attr __user * uattr )
986995{
987- bool is_l2 = false, is_direct_pkt_access = false;
996+ bool is_l2 = false, is_direct_pkt_access = false, is_nonlinear = false ;
988997 struct net * net = current -> nsproxy -> net_ns ;
989998 struct net_device * dev = net -> loopback_dev ;
990999 u32 size = kattr -> test .data_size_in ;
@@ -997,21 +1006,11 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
9971006 void * data ;
9981007 int ret ;
9991008
1000- if ((kattr -> test .flags & ~BPF_F_TEST_SKB_CHECKSUM_COMPLETE ) ||
1009+ if ((kattr -> test .flags & ~( BPF_F_TEST_SKB_CHECKSUM_COMPLETE | BPF_F_TEST_SKB_NON_LINEAR ) ) ||
10011010 kattr -> test .cpu || kattr -> test .batch_size )
10021011 return - EINVAL ;
10031012
1004- data = bpf_test_init (kattr , kattr -> test .data_size_in ,
1005- size , NET_SKB_PAD + NET_IP_ALIGN ,
1006- SKB_DATA_ALIGN (sizeof (struct skb_shared_info )));
1007- if (IS_ERR (data ))
1008- return PTR_ERR (data );
1009-
1010- ctx = bpf_ctx_init (kattr , sizeof (struct __sk_buff ));
1011- if (IS_ERR (ctx )) {
1012- ret = PTR_ERR (ctx );
1013- goto out ;
1014- }
1013+ is_nonlinear = kattr -> test .flags & BPF_F_TEST_SKB_NON_LINEAR ;
10151014
10161015 switch (prog -> type ) {
10171016 case BPF_PROG_TYPE_SCHED_CLS :
@@ -1028,22 +1027,55 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
10281027 break ;
10291028 }
10301029
1030+ if (is_nonlinear && !is_l2 )
1031+ return - EINVAL ;
1032+
1033+ data = bpf_test_init (kattr , kattr -> test .data_size_in ,
1034+ size , NET_SKB_PAD + NET_IP_ALIGN ,
1035+ SKB_DATA_ALIGN (sizeof (struct skb_shared_info )),
1036+ is_nonlinear );
1037+ if (IS_ERR (data ))
1038+ return PTR_ERR (data );
1039+
1040+ ctx = bpf_ctx_init (kattr , sizeof (struct __sk_buff ));
1041+ if (IS_ERR (ctx )) {
1042+ ret = PTR_ERR (ctx );
1043+ goto out ;
1044+ }
1045+
10311046 sk = sk_alloc (net , AF_UNSPEC , GFP_USER , & bpf_dummy_proto , 1 );
10321047 if (!sk ) {
10331048 ret = - ENOMEM ;
10341049 goto out ;
10351050 }
10361051 sock_init_data (NULL , sk );
10371052
1038- skb = slab_build_skb (data );
1053+ if (is_nonlinear )
1054+ skb = alloc_skb (NET_SKB_PAD + NET_IP_ALIGN + size +
1055+ SKB_DATA_ALIGN (sizeof (struct skb_shared_info )),
1056+ GFP_USER );
1057+ else
1058+ skb = slab_build_skb (data );
10391059 if (!skb ) {
10401060 ret = - ENOMEM ;
10411061 goto out ;
10421062 }
1063+
10431064 skb -> sk = sk ;
10441065
10451066 skb_reserve (skb , NET_SKB_PAD + NET_IP_ALIGN );
1046- __skb_put (skb , size );
1067+
1068+ if (is_nonlinear ) {
1069+ skb_fill_page_desc (skb , 0 , data , 0 , size );
1070+ skb -> truesize += PAGE_SIZE ;
1071+ skb -> data_len = size ;
1072+ skb -> len = size ;
1073+
1074+ /* eth_type_trans expects the Ethernet header in the linear area. */
1075+ __pskb_pull_tail (skb , ETH_HLEN );
1076+ } else {
1077+ __skb_put (skb , size );
1078+ }
10471079
10481080 data = NULL ; /* data released via kfree_skb */
10491081
@@ -1126,9 +1158,11 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
11261158 convert_skb_to___skb (skb , ctx );
11271159
11281160 size = skb -> len ;
1129- /* bpf program can never convert linear skb to non-linear */
1130- if (WARN_ON_ONCE (skb_is_nonlinear (skb )))
1161+ if (skb_is_nonlinear (skb )) {
1162+ /* bpf program can never convert linear skb to non-linear */
1163+ WARN_ON_ONCE (!is_nonlinear );
11311164 size = skb_headlen (skb );
1165+ }
11321166 ret = bpf_test_finish (kattr , uattr , skb -> data , NULL , size , retval ,
11331167 duration );
11341168 if (!ret )
@@ -1138,7 +1172,8 @@ int bpf_prog_test_run_skb(struct bpf_prog *prog, const union bpf_attr *kattr,
11381172 if (dev && dev != net -> loopback_dev )
11391173 dev_put (dev );
11401174 kfree_skb (skb );
1141- kfree (data );
1175+ if (data )
1176+ is_nonlinear ? __free_page (data ) : kfree (data );
11421177 if (sk )
11431178 sk_free (sk );
11441179 kfree (ctx );
@@ -1264,7 +1299,7 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,
12641299 size = max_data_sz ;
12651300 }
12661301
1267- data = bpf_test_init (kattr , size , max_data_sz , headroom , tailroom );
1302+ data = bpf_test_init (kattr , size , max_data_sz , headroom , tailroom , false );
12681303 if (IS_ERR (data )) {
12691304 ret = PTR_ERR (data );
12701305 goto free_ctx ;
@@ -1387,7 +1422,7 @@ int bpf_prog_test_run_flow_dissector(struct bpf_prog *prog,
13871422 if (size < ETH_HLEN )
13881423 return - EINVAL ;
13891424
1390- data = bpf_test_init (kattr , kattr -> test .data_size_in , size , 0 , 0 );
1425+ data = bpf_test_init (kattr , kattr -> test .data_size_in , size , 0 , 0 , false );
13911426 if (IS_ERR (data ))
13921427 return PTR_ERR (data );
13931428
@@ -1660,7 +1695,8 @@ int bpf_prog_test_run_nf(struct bpf_prog *prog,
16601695
16611696 data = bpf_test_init (kattr , kattr -> test .data_size_in , size ,
16621697 NET_SKB_PAD + NET_IP_ALIGN ,
1663- SKB_DATA_ALIGN (sizeof (struct skb_shared_info )));
1698+ SKB_DATA_ALIGN (sizeof (struct skb_shared_info )),
1699+ false);
16641700 if (IS_ERR (data ))
16651701 return PTR_ERR (data );
16661702
0 commit comments