* No direct copy from ctx to map possible, why?
@ 2024-04-14 21:34 Fabian Pfitzner
2024-04-15 16:01 ` Yonghong Song
2024-04-16 5:12 ` Hengqi Chen
0 siblings, 2 replies; 9+ messages in thread
From: Fabian Pfitzner @ 2024-04-14 21:34 UTC (permalink / raw)
To: bpf
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, .....).
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
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: No direct copy from ctx to map possible, why?
2024-04-14 21:34 No direct copy from ctx to map possible, why? Fabian Pfitzner
@ 2024-04-15 16:01 ` Yonghong Song
2024-04-15 20:25 ` Fabian Pfitzner
2024-04-16 5:12 ` Hengqi Chen
1 sibling, 1 reply; 9+ messages in thread
From: Yonghong Song @ 2024-04-15 16:01 UTC (permalink / raw)
To: Fabian Pfitzner, bpf
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
>
>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: No direct copy from ctx to map possible, why?
2024-04-15 16:01 ` Yonghong Song
@ 2024-04-15 20:25 ` Fabian Pfitzner
2024-04-16 3:22 ` Yonghong Song
0 siblings, 1 reply; 9+ messages in thread
From: Fabian Pfitzner @ 2024-04-15 20:25 UTC (permalink / raw)
To: Yonghong Song, bpf
> 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).
> 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?
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
>>
>>
>>
>>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: No direct copy from ctx to map possible, why?
2024-04-15 20:25 ` Fabian Pfitzner
@ 2024-04-16 3:22 ` Yonghong Song
2024-04-17 19:38 ` Fabian Pfitzner
0 siblings, 1 reply; 9+ messages in thread
From: Yonghong Song @ 2024-04-16 3:22 UTC (permalink / raw)
To: Fabian Pfitzner, bpf
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
>>>
>>>
>>>
>>>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: No direct copy from ctx to map possible, why?
2024-04-14 21:34 No direct copy from ctx to map possible, why? Fabian Pfitzner
2024-04-15 16:01 ` Yonghong Song
@ 2024-04-16 5:12 ` Hengqi Chen
2024-04-17 19:42 ` Fabian Pfitzner
1 sibling, 1 reply; 9+ messages in thread
From: Hengqi Chen @ 2024-04-16 5:12 UTC (permalink / raw)
To: Fabian Pfitzner; +Cc: bpf
On Mon, Apr 15, 2024 at 5:41 AM Fabian Pfitzner
<f.pfitzner@tu-braunschweig.de> 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, .....).
>
> 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.
>
Have you tried bpf_xdp_output() helper ?
> 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
>
>
>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: No direct copy from ctx to map possible, why?
2024-04-16 3:22 ` Yonghong Song
@ 2024-04-17 19:38 ` Fabian Pfitzner
2024-04-18 0:09 ` Yonghong Song
2024-04-19 0:20 ` Andrii Nakryiko
0 siblings, 2 replies; 9+ messages in thread
From: Fabian Pfitzner @ 2024-04-17 19:38 UTC (permalink / raw)
To: Yonghong Song, bpf
> 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.
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
>>>>
>>>>
>>>>
>>>>
>>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: No direct copy from ctx to map possible, why?
2024-04-16 5:12 ` Hengqi Chen
@ 2024-04-17 19:42 ` Fabian Pfitzner
0 siblings, 0 replies; 9+ messages in thread
From: Fabian Pfitzner @ 2024-04-17 19:42 UTC (permalink / raw)
To: Hengqi Chen; +Cc: bpf
> Have you tried bpf_xdp_output() helper ?
I haven't. Can I use that helper even though my program isn't related to
perf at all?
I'll definitely give it a try. Thanks
On 4/16/24 7:12 AM, Hengqi Chen wrote:
> On Mon, Apr 15, 2024 at 5:41 AM Fabian Pfitzner
> <f.pfitzner@tu-braunschweig.de> 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, .....).
>>
>> 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.
>>
> Have you tried bpf_xdp_output() helper ?
>
>> 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
>>
>>
>>
>>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: No direct copy from ctx to map possible, why?
2024-04-17 19:38 ` Fabian Pfitzner
@ 2024-04-18 0:09 ` Yonghong Song
2024-04-19 0:20 ` Andrii Nakryiko
1 sibling, 0 replies; 9+ messages in thread
From: Yonghong Song @ 2024-04-18 0:09 UTC (permalink / raw)
To: Fabian Pfitzner, bpf
On 4/17/24 12:38 PM, Fabian Pfitzner 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.
The map value can be packet pointer as your early mentioned:
expecting another type as "ctx" (R3 type=ctx expected=fp, pkt, pkt_meta, .....).
But you need to do packet range checking to ensure the packet range (from start of packet->data) must be the same or greater
than map value size.
>
> 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
>>>>>
>>>>>
>>>>>
>>>>>
>>>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: No direct copy from ctx to map possible, why?
2024-04-17 19:38 ` Fabian Pfitzner
2024-04-18 0:09 ` Yonghong Song
@ 2024-04-19 0:20 ` Andrii Nakryiko
1 sibling, 0 replies; 9+ messages in thread
From: Andrii Nakryiko @ 2024-04-19 0:20 UTC (permalink / raw)
To: Fabian Pfitzner; +Cc: Yonghong Song, bpf
On Wed, Apr 17, 2024 at 12:39 PM Fabian Pfitzner
<f.pfitzner@tu-braunschweig.de> 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
> >>>>
> >>>>
> >>>>
> >>>>
> >>
>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2024-04-19 0:20 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-04-14 21:34 No direct copy from ctx to map possible, why? Fabian Pfitzner
2024-04-15 16:01 ` Yonghong Song
2024-04-15 20:25 ` Fabian Pfitzner
2024-04-16 3:22 ` Yonghong Song
2024-04-17 19:38 ` Fabian Pfitzner
2024-04-18 0:09 ` Yonghong Song
2024-04-19 0:20 ` Andrii Nakryiko
2024-04-16 5:12 ` Hengqi Chen
2024-04-17 19:42 ` Fabian Pfitzner
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.