@@ -3839,6 +3839,138 @@ static const struct bpf_func_proto bpf_xdp_adjust_head_proto = {
3839
3839
.arg2_type = ARG_ANYTHING ,
3840
3840
};
3841
3841
3842
+ static void bpf_xdp_copy_buf (struct xdp_buff * xdp , unsigned long off ,
3843
+ void * buf , unsigned long len , bool flush )
3844
+ {
3845
+ unsigned long ptr_len , ptr_off = 0 ;
3846
+ skb_frag_t * next_frag , * end_frag ;
3847
+ struct skb_shared_info * sinfo ;
3848
+ void * src , * dst ;
3849
+ u8 * ptr_buf ;
3850
+
3851
+ if (likely (xdp -> data_end - xdp -> data >= off + len )) {
3852
+ src = flush ? buf : xdp -> data + off ;
3853
+ dst = flush ? xdp -> data + off : buf ;
3854
+ memcpy (dst , src , len );
3855
+ return ;
3856
+ }
3857
+
3858
+ sinfo = xdp_get_shared_info_from_buff (xdp );
3859
+ end_frag = & sinfo -> frags [sinfo -> nr_frags ];
3860
+ next_frag = & sinfo -> frags [0 ];
3861
+
3862
+ ptr_len = xdp -> data_end - xdp -> data ;
3863
+ ptr_buf = xdp -> data ;
3864
+
3865
+ while (true) {
3866
+ if (off < ptr_off + ptr_len ) {
3867
+ unsigned long copy_off = off - ptr_off ;
3868
+ unsigned long copy_len = min (len , ptr_len - copy_off );
3869
+
3870
+ src = flush ? buf : ptr_buf + copy_off ;
3871
+ dst = flush ? ptr_buf + copy_off : buf ;
3872
+ memcpy (dst , src , copy_len );
3873
+
3874
+ off += copy_len ;
3875
+ len -= copy_len ;
3876
+ buf += copy_len ;
3877
+ }
3878
+
3879
+ if (!len || next_frag == end_frag )
3880
+ break ;
3881
+
3882
+ ptr_off += ptr_len ;
3883
+ ptr_buf = skb_frag_address (next_frag );
3884
+ ptr_len = skb_frag_size (next_frag );
3885
+ next_frag ++ ;
3886
+ }
3887
+ }
3888
+
3889
+ static void * bpf_xdp_pointer (struct xdp_buff * xdp , u32 offset , u32 len )
3890
+ {
3891
+ struct skb_shared_info * sinfo = xdp_get_shared_info_from_buff (xdp );
3892
+ u32 size = xdp -> data_end - xdp -> data ;
3893
+ void * addr = xdp -> data ;
3894
+ int i ;
3895
+
3896
+ if (unlikely (offset > 0xffff || len > 0xffff ))
3897
+ return ERR_PTR (- EFAULT );
3898
+
3899
+ if (offset + len > xdp_get_buff_len (xdp ))
3900
+ return ERR_PTR (- EINVAL );
3901
+
3902
+ if (offset < size ) /* linear area */
3903
+ goto out ;
3904
+
3905
+ offset -= size ;
3906
+ for (i = 0 ; i < sinfo -> nr_frags ; i ++ ) { /* paged area */
3907
+ u32 frag_size = skb_frag_size (& sinfo -> frags [i ]);
3908
+
3909
+ if (offset < frag_size ) {
3910
+ addr = skb_frag_address (& sinfo -> frags [i ]);
3911
+ size = frag_size ;
3912
+ break ;
3913
+ }
3914
+ offset -= frag_size ;
3915
+ }
3916
+ out :
3917
+ return offset + len < size ? addr + offset : NULL ;
3918
+ }
3919
+
3920
+ BPF_CALL_4 (bpf_xdp_load_bytes , struct xdp_buff * , xdp , u32 , offset ,
3921
+ void * , buf , u32 , len )
3922
+ {
3923
+ void * ptr ;
3924
+
3925
+ ptr = bpf_xdp_pointer (xdp , offset , len );
3926
+ if (IS_ERR (ptr ))
3927
+ return PTR_ERR (ptr );
3928
+
3929
+ if (!ptr )
3930
+ bpf_xdp_copy_buf (xdp , offset , buf , len , false);
3931
+ else
3932
+ memcpy (buf , ptr , len );
3933
+
3934
+ return 0 ;
3935
+ }
3936
+
3937
+ static const struct bpf_func_proto bpf_xdp_load_bytes_proto = {
3938
+ .func = bpf_xdp_load_bytes ,
3939
+ .gpl_only = false,
3940
+ .ret_type = RET_INTEGER ,
3941
+ .arg1_type = ARG_PTR_TO_CTX ,
3942
+ .arg2_type = ARG_ANYTHING ,
3943
+ .arg3_type = ARG_PTR_TO_UNINIT_MEM ,
3944
+ .arg4_type = ARG_CONST_SIZE ,
3945
+ };
3946
+
3947
+ BPF_CALL_4 (bpf_xdp_store_bytes , struct xdp_buff * , xdp , u32 , offset ,
3948
+ void * , buf , u32 , len )
3949
+ {
3950
+ void * ptr ;
3951
+
3952
+ ptr = bpf_xdp_pointer (xdp , offset , len );
3953
+ if (IS_ERR (ptr ))
3954
+ return PTR_ERR (ptr );
3955
+
3956
+ if (!ptr )
3957
+ bpf_xdp_copy_buf (xdp , offset , buf , len , true);
3958
+ else
3959
+ memcpy (ptr , buf , len );
3960
+
3961
+ return 0 ;
3962
+ }
3963
+
3964
+ static const struct bpf_func_proto bpf_xdp_store_bytes_proto = {
3965
+ .func = bpf_xdp_store_bytes ,
3966
+ .gpl_only = false,
3967
+ .ret_type = RET_INTEGER ,
3968
+ .arg1_type = ARG_PTR_TO_CTX ,
3969
+ .arg2_type = ARG_ANYTHING ,
3970
+ .arg3_type = ARG_PTR_TO_UNINIT_MEM ,
3971
+ .arg4_type = ARG_CONST_SIZE ,
3972
+ };
3973
+
3842
3974
static int bpf_xdp_frags_increase_tail (struct xdp_buff * xdp , int offset )
3843
3975
{
3844
3976
struct skb_shared_info * sinfo = xdp_get_shared_info_from_buff (xdp );
@@ -4677,48 +4809,12 @@ static const struct bpf_func_proto bpf_sk_ancestor_cgroup_id_proto = {
4677
4809
};
4678
4810
#endif
4679
4811
4680
- static unsigned long bpf_xdp_copy (void * dst_buff , const void * ctx ,
4812
+ static unsigned long bpf_xdp_copy (void * dst , const void * ctx ,
4681
4813
unsigned long off , unsigned long len )
4682
4814
{
4683
4815
struct xdp_buff * xdp = (struct xdp_buff * )ctx ;
4684
- unsigned long ptr_len , ptr_off = 0 ;
4685
- skb_frag_t * next_frag , * end_frag ;
4686
- struct skb_shared_info * sinfo ;
4687
- u8 * ptr_buf ;
4688
-
4689
- if (likely (xdp -> data_end - xdp -> data >= off + len )) {
4690
- memcpy (dst_buff , xdp -> data + off , len );
4691
- return 0 ;
4692
- }
4693
-
4694
- sinfo = xdp_get_shared_info_from_buff (xdp );
4695
- end_frag = & sinfo -> frags [sinfo -> nr_frags ];
4696
- next_frag = & sinfo -> frags [0 ];
4697
-
4698
- ptr_len = xdp -> data_end - xdp -> data ;
4699
- ptr_buf = xdp -> data ;
4700
-
4701
- while (true) {
4702
- if (off < ptr_off + ptr_len ) {
4703
- unsigned long copy_off = off - ptr_off ;
4704
- unsigned long copy_len = min (len , ptr_len - copy_off );
4705
-
4706
- memcpy (dst_buff , ptr_buf + copy_off , copy_len );
4707
-
4708
- off += copy_len ;
4709
- len -= copy_len ;
4710
- dst_buff += copy_len ;
4711
- }
4712
-
4713
- if (!len || next_frag == end_frag )
4714
- break ;
4715
-
4716
- ptr_off += ptr_len ;
4717
- ptr_buf = skb_frag_address (next_frag );
4718
- ptr_len = skb_frag_size (next_frag );
4719
- next_frag ++ ;
4720
- }
4721
4816
4817
+ bpf_xdp_copy_buf (xdp , off , dst , len , false);
4722
4818
return 0 ;
4723
4819
}
4724
4820
@@ -7660,6 +7756,10 @@ xdp_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
7660
7756
return & bpf_xdp_adjust_tail_proto ;
7661
7757
case BPF_FUNC_xdp_get_buff_len :
7662
7758
return & bpf_xdp_get_buff_len_proto ;
7759
+ case BPF_FUNC_xdp_load_bytes :
7760
+ return & bpf_xdp_load_bytes_proto ;
7761
+ case BPF_FUNC_xdp_store_bytes :
7762
+ return & bpf_xdp_store_bytes_proto ;
7663
7763
case BPF_FUNC_fib_lookup :
7664
7764
return & bpf_xdp_fib_lookup_proto ;
7665
7765
case BPF_FUNC_check_mtu :
0 commit comments