Re: No direct copy from ctx to map possible, why?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Apr 17, 2024 at 12:39 PM Fabian Pfitzner
<f.pfitzner@xxxxxxxxxxxxxxxxxx> wrote:
>
> > In your particular example, since you intend to copy xdp_md->data, you
> > can directly
> > access that from xdp_md->data pointer, there is no need to copy ctx
> > which is not
> > what you want.
> Thanks for your answer, but I think you misunderstood me. I need to
> store the packet's payload in a map (not the xdp_md structure itself),
> because my use case forces me to do so.
>
> I write a program that reassembles split packets into a single one.
> Therefore I have to buffer packet fragments until all have been arrived.
> The only way in eBPF to realize such a buffer is a map, so I have to put
> the packet's payload in there. My problem is, that I have no clue how to
> do it properly as there is no direct way to put the payload into a map.
>
> How would you put a packet with a size of 700 bytes into a map? What
> would be your strategy when you can only access your packet via the
> xdp_md structure? My strategy (and that's the best I have found so far)
> is to split this packet into two packets of size 350 bytes, so that I
> can process them on the stack consecutively.

Check bpf_dynptr_from_skb()/bpf_dynptr_from_xdp() (see selftests for
examples) and then generic bpf_dynptr_data() will give you a pointer
into packet data. There are also generic bpf_dynptr_{read,write}()
helpers, which might be useful (all depends on specifics of
implementation).

As for 512 on the stack limitation. Just as a general solution, you
can use a single-element per-CPU ARRAY map as a temporary scratch
space to copy data there.

>
> On 4/16/24 5:22 AM, Yonghong Song wrote:
> >
> > On 4/15/24 1:25 PM, Fabian Pfitzner wrote:
> >>> Looks like you intend to copy packet data. So from the above,
> >>> 'expected=fp,pkt,pkt_meta...', you can just put the first argument
> >>> with xdp->data, right?
> >> Yes, I intend to copy packet data. What do you mean by "first
> >> argument"? I'd like to put the whole data that is depicted by
> >> xdp->data into a map that stores them as raw bytes (by using a char
> >> array as map element to store the data).
> >
> > Sorry, typo. 'first argument' should be 'third argument'.
> >
> >>
> >>> Verifer rejects to 'ctx' since 'ctx' contents are subject to
> >>> verifier rewrite. So actual 'ctx' contents/layouts may not match
> >>> uapi definition.
> >> Sorry but I do not understand what you mean by "subject to verifier
> >> rewrite". What kind of rewrite happens when using the ctx as
> >> argument? Furthermore, am I correct that you assume that the uapi may
> >> dictate the structure of the data that can be stored in a map? How is
> >> it different to the case when first storing it on the stack and then
> >> putting it into a map?
> >
> > The UAPI xdp_md struct:
> >
> > struct xdp_md {
> >         __u32 data;
> >         __u32 data_end;
> >         __u32 data_meta;
> >         /* Below access go through struct xdp_rxq_info */
> >         __u32 ingress_ifindex; /* rxq->dev->ifindex */
> >         __u32 rx_queue_index;  /* rxq->queue_index  */
> >
> >         __u32 egress_ifindex;  /* txq->dev->ifindex */
> > };
> >
> > The actual kernel representation of xdp_md:
> >
> > struct xdp_buff {
> >         void *data;
> >         void *data_end;
> >         void *data_meta;
> >         void *data_hard_start;
> >         struct xdp_rxq_info *rxq;
> >         struct xdp_txq_info *txq;
> >         u32 frame_sz; /* frame size to deduce data_hard_end/reserved
> > tailroom*/
> >         u32 flags; /* supported values defined in xdp_buff_flags */
> > };
> >
> > You can see they are quite different. So to use pointee of 'ctx' as
> > the key, we
> > need to allocate a space of sizeof(struct_md) to the stack and copy
> > necessary
> > stuff to that structure. For example, xdp_md->ingress_ifindex =
> > xdp_buff->rxq->dev->ifindex, etc.
> > Some fields actually does not make sense for copying, e.g.,
> > data/data_end/data_meta in 64bit
> > architecture. Since stack allocation is needed any way, so disabling
> > ctx and requires
> > user explicit using stack make sense (if they want to use *ctx as map
> > update value).
> >
> > In your particular example, since you intend to copy xdp_md->data, you
> > can directly
> > access that from xdp_md->data pointer, there is no need to copy ctx
> > which is not
> > what you want.
> >
> >>
> >> On 4/15/24 6:01 PM, Yonghong Song wrote:
> >>>
> >>> On 4/14/24 2:34 PM, Fabian Pfitzner wrote:
> >>>> Hello,
> >>>>
> >>>> is there a specific reason why it is not allowed to copy data from
> >>>> ctx directly into a map via the bpf_map_update_elem helper?
> >>>> I develop a XDP program where I need to store incoming packets
> >>>> (including the whole payload) into a map in order to buffer them.
> >>>> I thought I could simply put them into a map via the mentioned
> >>>> helper function, but the verifier complains about expecting another
> >>>> type as "ctx" (R3 type=ctx expected=fp, pkt, pkt_meta, .....).
> >>>
> >>> Looks like you intend to copy packet data. So from the above,
> >>> 'expected=fp,pkt,pkt_meta...', you can just put the first argument
> >>> with xdp->data, right?
> >>> Verifer rejects to 'ctx' since 'ctx' contents are subject to
> >>> verifier rewrite. So actual 'ctx' contents/layouts may not match
> >>> uapi definition.
> >>>
> >>>>
> >>>> I was able to circumvent this error by first putting the packet
> >>>> onto the stack (via xdp->data) and then write it into the map.
> >>>> The only limitation with this is that I cannot store packets larger
> >>>> than 512 bytes due to the maximum stack size.
> >>>>
> >>>> I was also able to circumvent this by slicing chunks, that are
> >>>> smaller than 512 bytes, out of the packet so that I can use the
> >>>> stack as a clipboard before putting them into the map. This is a
> >>>> really ugly solution, but I have not found a better one yet.
> >>>>
> >>>> So my question is: Why does this limitation exist? I am not sure if
> >>>> its only related to XDP programs as this restriction is defined
> >>>> inside of the bpf_map_update_elem_proto struct (arg3_type restricts
> >>>> this), so I think it is a general limitation that affects all
> >>>> program types.
> >>>>
> >>>> Best regards,
> >>>> Fabian Pfitzner
> >>>>
> >>>>
> >>>>
> >>>>
> >>
>





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux