mbox series

[bpf-next,00/10] xsk: stop softirq processing on full XSK Rx queue

Message ID 20220405110631.404427-1-maciej.fijalkowski@intel.com (mailing list archive)
Headers show
Series xsk: stop softirq processing on full XSK Rx queue | expand

Message

Maciej Fijalkowski April 5, 2022, 11:06 a.m. UTC
Hi!

This is a revival of Bjorn's idea [0] to break NAPI loop when XSK Rx
queue gets full which in turn makes it impossible to keep on
successfully producing descriptors to XSK Rx ring. By breaking out of
the driver side immediately we will give the user space opportunity for
consuming descriptors from XSK Rx ring and therefore provide room in the
ring so that HW Rx -> XSK Rx redirection can be done.

Maxim asked and Jesper agreed on simplifying Bjorn's original API used
for detecting the event of interest, so let's just simply check for
-ENOBUFS within Intel's ZC drivers after an attempt to redirect a buffer
to XSK Rx. No real need for redirect API extension.

One might ask why it is still relevant even after having proper busy
poll support in place - here is the justification.

For xdpsock that was:
- run for l2fwd scenario,
- app/driver processing took place on the same core in busy poll
  with 2048 budget,
- HW ring sizes Tx 256, Rx 2048,

this work improved throughput by 78% and reduced Rx queue full statistic
bump by 99%.

For testing ice, make sure that you have [1] present on your side.

This set, besides the work described above, also carries also
improvements around return codes in various XSK paths and lastly a minor
optimization for xskq_cons_has_entries(), a helper that might be used
when XSK Rx batching would make it to the kernel.

Thanks!
MF

[0]: https://lore.kernel.org/bpf/20200904135332.60259-1-bjorn.topel@gmail.com/
[1]: https://lore.kernel.org/netdev/20220317175727.340251-1-maciej.fijalkowski@intel.com/

Björn Töpel (1):
  xsk: improve xdp_do_redirect() error codes

Maciej Fijalkowski (9):
  xsk: diversify return codes in xsk_rcv_check()
  ice: xsk: terminate NAPI when XSK Rx queue gets full
  i40e: xsk: terminate NAPI when XSK Rx queue gets full
  ixgbe: xsk: terminate NAPI when XSK Rx queue gets full
  ice: xsk: diversify return values from xsk_wakeup call paths
  i40e: xsk: diversify return values from xsk_wakeup call paths
  ixgbe: xsk: diversify return values from xsk_wakeup call paths
  ice: xsk: avoid refilling single Rx descriptors
  xsk: drop ternary operator from xskq_cons_has_entries

 .../ethernet/intel/i40e/i40e_txrx_common.h    |  1 +
 drivers/net/ethernet/intel/i40e/i40e_xsk.c    | 27 +++++++++------
 drivers/net/ethernet/intel/ice/ice_txrx.h     |  1 +
 drivers/net/ethernet/intel/ice/ice_xsk.c      | 34 ++++++++++++-------
 .../ethernet/intel/ixgbe/ixgbe_txrx_common.h  |  1 +
 drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c  | 29 ++++++++++------
 net/xdp/xsk.c                                 |  4 +--
 net/xdp/xsk_queue.h                           |  4 +--
 8 files changed, 64 insertions(+), 37 deletions(-)

Comments

Maxim Mikityanskiy April 7, 2022, 10:49 a.m. UTC | #1
On 2022-04-05 14:06, Maciej Fijalkowski wrote:
> Hi!
> 
> This is a revival of Bjorn's idea [0] to break NAPI loop when XSK Rx
> queue gets full which in turn makes it impossible to keep on
> successfully producing descriptors to XSK Rx ring. By breaking out of
> the driver side immediately we will give the user space opportunity for
> consuming descriptors from XSK Rx ring and therefore provide room in the
> ring so that HW Rx -> XSK Rx redirection can be done.
> 
> Maxim asked and Jesper agreed on simplifying Bjorn's original API used
> for detecting the event of interest, so let's just simply check for
> -ENOBUFS within Intel's ZC drivers after an attempt to redirect a buffer
> to XSK Rx. No real need for redirect API extension.

I believe some of the other comments under the old series [0] might be 
still relevant:

1. need_wakeup behavior. If need_wakeup is disabled, the expected 
behavior is busy-looping in NAPI, you shouldn't break out early, as the 
application does not restart NAPI, and the driver restarts it itself, 
leading to a less efficient loop. If need_wakeup is enabled, it should 
be set on ENOBUFS - I believe this is the case here, right?

2. 50/50 AF_XDP and XDP_TX mix usecase. By breaking out early, you 
prevent further packets from being XDP_TXed, leading to unnecessary 
latency increase. The new feature should be opt-in, otherwise such 
usecases suffer.

3. When the driver receives ENOBUFS, it has to drop the packet before 
returning to the application. It would be better experience if your 
feature saved all N packets from being dropped, not just N-1.

4. A slow or malicious AF_XDP application may easily cause an overflow 
of the hardware receive ring. Your feature introduces a mechanism to 
pause the driver while the congestion is on the application side, but no 
symmetric mechanism to pause the application when the driver is close to 
an overflow. I don't know the behavior of Intel NICs on overflow, but in 
our NICs it's considered a critical error, that is followed by a 
recovery procedure, so it's not something that should happen under 
normal workloads.

> One might ask why it is still relevant even after having proper busy
> poll support in place - here is the justification.
> 
> For xdpsock that was:
> - run for l2fwd scenario,
> - app/driver processing took place on the same core in busy poll
>    with 2048 budget,
> - HW ring sizes Tx 256, Rx 2048,
> 
> this work improved throughput by 78% and reduced Rx queue full statistic
> bump by 99%.
> 
> For testing ice, make sure that you have [1] present on your side.
> 
> This set, besides the work described above, also carries also
> improvements around return codes in various XSK paths and lastly a minor
> optimization for xskq_cons_has_entries(), a helper that might be used
> when XSK Rx batching would make it to the kernel.

Regarding error codes, I would like them to be consistent across all 
drivers, otherwise all the debuggability improvements are not useful 
enough. Your series only changed Intel drivers. Here also applies the 
backward compatibility concern: the same error codes than were in use 
have been repurposed, which may confuse some of existing applications.

> Thanks!
> MF
> 
> [0]: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fbpf%2F20200904135332.60259-1-bjorn.topel%40gmail.com%2F&data=04%7C01%7Cmaximmi%40nvidia.com%7Cc9cefaa3a1cd465ccdb908da16f45eaf%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C637847536077594100%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=sLpTcgboo9YU55wtUtaY1%2F%2FbeiYxeWP5ubk%2FQ6X8vB8%3D&reserved=0
> [1]: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fnetdev%2F20220317175727.340251-1-maciej.fijalkowski%40intel.com%2F&data=04%7C01%7Cmaximmi%40nvidia.com%7Cc9cefaa3a1cd465ccdb908da16f45eaf%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C637847536077594100%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=OWXeZhc2Nouz%2FTMWBxvtTYbw%2FS8HWQfbfEqnVc5478k%3D&reserved=0
> 
> Björn Töpel (1):
>    xsk: improve xdp_do_redirect() error codes
> 
> Maciej Fijalkowski (9):
>    xsk: diversify return codes in xsk_rcv_check()
>    ice: xsk: terminate NAPI when XSK Rx queue gets full
>    i40e: xsk: terminate NAPI when XSK Rx queue gets full
>    ixgbe: xsk: terminate NAPI when XSK Rx queue gets full
>    ice: xsk: diversify return values from xsk_wakeup call paths
>    i40e: xsk: diversify return values from xsk_wakeup call paths
>    ixgbe: xsk: diversify return values from xsk_wakeup call paths
>    ice: xsk: avoid refilling single Rx descriptors
>    xsk: drop ternary operator from xskq_cons_has_entries
> 
>   .../ethernet/intel/i40e/i40e_txrx_common.h    |  1 +
>   drivers/net/ethernet/intel/i40e/i40e_xsk.c    | 27 +++++++++------
>   drivers/net/ethernet/intel/ice/ice_txrx.h     |  1 +
>   drivers/net/ethernet/intel/ice/ice_xsk.c      | 34 ++++++++++++-------
>   .../ethernet/intel/ixgbe/ixgbe_txrx_common.h  |  1 +
>   drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c  | 29 ++++++++++------
>   net/xdp/xsk.c                                 |  4 +--
>   net/xdp/xsk_queue.h                           |  4 +--
>   8 files changed, 64 insertions(+), 37 deletions(-)
>
Maciej Fijalkowski April 8, 2022, 9:08 a.m. UTC | #2
On Thu, Apr 07, 2022 at 01:49:02PM +0300, Maxim Mikityanskiy wrote:
> On 2022-04-05 14:06, Maciej Fijalkowski wrote:
> > Hi!
> > 
> > This is a revival of Bjorn's idea [0] to break NAPI loop when XSK Rx
> > queue gets full which in turn makes it impossible to keep on
> > successfully producing descriptors to XSK Rx ring. By breaking out of
> > the driver side immediately we will give the user space opportunity for
> > consuming descriptors from XSK Rx ring and therefore provide room in the
> > ring so that HW Rx -> XSK Rx redirection can be done.
> > 
> > Maxim asked and Jesper agreed on simplifying Bjorn's original API used
> > for detecting the event of interest, so let's just simply check for
> > -ENOBUFS within Intel's ZC drivers after an attempt to redirect a buffer
> > to XSK Rx. No real need for redirect API extension.
> 

Hey Maxim!

> I believe some of the other comments under the old series [0] might be still
> relevant:
> 
> 1. need_wakeup behavior. If need_wakeup is disabled, the expected behavior
> is busy-looping in NAPI, you shouldn't break out early, as the application
> does not restart NAPI, and the driver restarts it itself, leading to a less
> efficient loop. If need_wakeup is enabled, it should be set on ENOBUFS - I
> believe this is the case here, right?

Good point. We currently set need_wakeup flag for -ENOBUFS case as it is
being done for failure == true. You are right that we shouldn't be
breaking the loop on -ENOBUFS if need_wakeup flag is not set on xsk_pool,
will fix!

> 
> 2. 50/50 AF_XDP and XDP_TX mix usecase. By breaking out early, you prevent
> further packets from being XDP_TXed, leading to unnecessary latency
> increase. The new feature should be opt-in, otherwise such usecases suffer.

Anyone performing a lot of XDP_TX (or XDP_PASS, etc) should be using the
regular copy-mode driver, while the zero-copy driver should be used when most
packets are sent up to user-space. For the zero-copy driver, this opt in is not
necessary. But it sounds like a valid option for copy mode, though could we
think about the proper way as a follow up to this work?

> 
> 3. When the driver receives ENOBUFS, it has to drop the packet before
> returning to the application. It would be better experience if your feature
> saved all N packets from being dropped, not just N-1.

Sure, I'll re-run tests and see if we can omit freeing the current
xdp_buff and ntc bump, so that we would come back later on to the same
entry.

> 
> 4. A slow or malicious AF_XDP application may easily cause an overflow of
> the hardware receive ring. Your feature introduces a mechanism to pause the
> driver while the congestion is on the application side, but no symmetric
> mechanism to pause the application when the driver is close to an overflow.
> I don't know the behavior of Intel NICs on overflow, but in our NICs it's
> considered a critical error, that is followed by a recovery procedure, so
> it's not something that should happen under normal workloads.

I'm not sure I follow on this one. Feature is about overflowing the XSK
receive ring, not the HW one, right? Driver picks entries from fill ring
that were produced by app, so if app is slow on producing those I believe
this would be rather an underflow of ring, we would simply receive less
frames. For HW Rx ring actually being full, I think that HW would be
dropping the incoming frames, so I don't see the real reason to treat this
as critical error that needs to go through recovery.

Am I missing something? Maybe I have just misunderstood you.

> 
> > One might ask why it is still relevant even after having proper busy
> > poll support in place - here is the justification.
> > 
> > For xdpsock that was:
> > - run for l2fwd scenario,
> > - app/driver processing took place on the same core in busy poll
> >    with 2048 budget,
> > - HW ring sizes Tx 256, Rx 2048,
> > 
> > this work improved throughput by 78% and reduced Rx queue full statistic
> > bump by 99%.
> > 
> > For testing ice, make sure that you have [1] present on your side.
> > 
> > This set, besides the work described above, also carries also
> > improvements around return codes in various XSK paths and lastly a minor
> > optimization for xskq_cons_has_entries(), a helper that might be used
> > when XSK Rx batching would make it to the kernel.
> 
> Regarding error codes, I would like them to be consistent across all
> drivers, otherwise all the debuggability improvements are not useful enough.
> Your series only changed Intel drivers. Here also applies the backward
> compatibility concern: the same error codes than were in use have been
> repurposed, which may confuse some of existing applications.

I'll double check if ZC drivers are doing something unusual with return
values from xdp_do_redirect(). Regarding backward comp, I suppose you
refer only to changes in ndo_xsk_wakeup() callbacks as others are not
exposed to user space? They're not crucial to me, but it improved my
debugging experience.

FYI, your mail landed in my junk folder and the links [0] [1] are messed up in
the reply you sent. And this is true even on lore.kernel.org. They suddenly
refer to "nam11.safelinks.protection.outlook.com". Maybe something worth
looking into if you have this problem in the future.

> 
> > Thanks!
> > MF
> > 
> > [0]: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fbpf%2F20200904135332.60259-1-bjorn.topel%40gmail.com%2F&data=04%7C01%7Cmaximmi%40nvidia.com%7Cc9cefaa3a1cd465ccdb908da16f45eaf%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C637847536077594100%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=sLpTcgboo9YU55wtUtaY1%2F%2FbeiYxeWP5ubk%2FQ6X8vB8%3D&reserved=0
> > [1]: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fnetdev%2F20220317175727.340251-1-maciej.fijalkowski%40intel.com%2F&data=04%7C01%7Cmaximmi%40nvidia.com%7Cc9cefaa3a1cd465ccdb908da16f45eaf%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C637847536077594100%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=OWXeZhc2Nouz%2FTMWBxvtTYbw%2FS8HWQfbfEqnVc5478k%3D&reserved=0
> > 
> > Björn Töpel (1):
> >    xsk: improve xdp_do_redirect() error codes
> > 
> > Maciej Fijalkowski (9):
> >    xsk: diversify return codes in xsk_rcv_check()
> >    ice: xsk: terminate NAPI when XSK Rx queue gets full
> >    i40e: xsk: terminate NAPI when XSK Rx queue gets full
> >    ixgbe: xsk: terminate NAPI when XSK Rx queue gets full
> >    ice: xsk: diversify return values from xsk_wakeup call paths
> >    i40e: xsk: diversify return values from xsk_wakeup call paths
> >    ixgbe: xsk: diversify return values from xsk_wakeup call paths
> >    ice: xsk: avoid refilling single Rx descriptors
> >    xsk: drop ternary operator from xskq_cons_has_entries
> > 
> >   .../ethernet/intel/i40e/i40e_txrx_common.h    |  1 +
> >   drivers/net/ethernet/intel/i40e/i40e_xsk.c    | 27 +++++++++------
> >   drivers/net/ethernet/intel/ice/ice_txrx.h     |  1 +
> >   drivers/net/ethernet/intel/ice/ice_xsk.c      | 34 ++++++++++++-------
> >   .../ethernet/intel/ixgbe/ixgbe_txrx_common.h  |  1 +
> >   drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c  | 29 ++++++++++------
> >   net/xdp/xsk.c                                 |  4 +--
> >   net/xdp/xsk_queue.h                           |  4 +--
> >   8 files changed, 64 insertions(+), 37 deletions(-)
> > 
>
Maxim Mikityanskiy April 8, 2022, 12:48 p.m. UTC | #3
On 2022-04-08 12:08, Maciej Fijalkowski wrote:
> On Thu, Apr 07, 2022 at 01:49:02PM +0300, Maxim Mikityanskiy wrote:
>> On 2022-04-05 14:06, Maciej Fijalkowski wrote:
>>> Hi!
>>>
>>> This is a revival of Bjorn's idea [0] to break NAPI loop when XSK Rx
>>> queue gets full which in turn makes it impossible to keep on
>>> successfully producing descriptors to XSK Rx ring. By breaking out of
>>> the driver side immediately we will give the user space opportunity for
>>> consuming descriptors from XSK Rx ring and therefore provide room in the
>>> ring so that HW Rx -> XSK Rx redirection can be done.
>>>
>>> Maxim asked and Jesper agreed on simplifying Bjorn's original API used
>>> for detecting the event of interest, so let's just simply check for
>>> -ENOBUFS within Intel's ZC drivers after an attempt to redirect a buffer
>>> to XSK Rx. No real need for redirect API extension.
>>
> 
> Hey Maxim!
> 
>> I believe some of the other comments under the old series [0] might be still
>> relevant:
>>
>> 1. need_wakeup behavior. If need_wakeup is disabled, the expected behavior
>> is busy-looping in NAPI, you shouldn't break out early, as the application
>> does not restart NAPI, and the driver restarts it itself, leading to a less
>> efficient loop. If need_wakeup is enabled, it should be set on ENOBUFS - I
>> believe this is the case here, right?
> 
> Good point. We currently set need_wakeup flag for -ENOBUFS case as it is
> being done for failure == true. You are right that we shouldn't be
> breaking the loop on -ENOBUFS if need_wakeup flag is not set on xsk_pool,
> will fix!
> 
>>
>> 2. 50/50 AF_XDP and XDP_TX mix usecase. By breaking out early, you prevent
>> further packets from being XDP_TXed, leading to unnecessary latency
>> increase. The new feature should be opt-in, otherwise such usecases suffer.
> 
> Anyone performing a lot of XDP_TX (or XDP_PASS, etc) should be using the
> regular copy-mode driver, while the zero-copy driver should be used when most
> packets are sent up to user-space.

You generalized that easily, but how can you be so sure that all mixed 
use cases can live with the much slower copy mode? Also, how do you 
apply your rule of thumb to the 75/25 AF_XDP/XDP_TX use case? It's both 
"a lot of XDP_TX" and "most packets are sent up to user-space" at the 
same time.

At the moment, the application is free to decide whether it wants 
zerocopy XDP_TX or zerocopy AF_XDP, depending on its needs. After your 
patchset the only valid XDP verdict on zerocopy AF_XDP basically becomes 
"XDP_REDIRECT to XSKMAP". I don't think it's valid to break an entire 
feature to speed up some very specific use case.

Moreover, in early days of AF_XDP there was an attempt to implement 
zerocopy XDP_TX on AF_XDP queues, meaning both XDP_TX and AF_XDP could 
be zerocopy. The implementation suffered from possible overflows in 
driver queues, thus wasn't upstreamed, but it's still a valid idea that 
potentially could be done if overflows are worked around somehow.

> For the zero-copy driver, this opt in is not
> necessary. But it sounds like a valid option for copy mode, though could we
> think about the proper way as a follow up to this work?

My opinion is that the knob has to be part of initial submission, and 
the new feature should be disabled by default, otherwise we have huge 
issues with backward compatibility (if we delay it, the next update 
changes the behavior, breaking some existing use cases, and there is no 
way to work around it).

>>
>> 3. When the driver receives ENOBUFS, it has to drop the packet before
>> returning to the application. It would be better experience if your feature
>> saved all N packets from being dropped, not just N-1.
> 
> Sure, I'll re-run tests and see if we can omit freeing the current
> xdp_buff and ntc bump, so that we would come back later on to the same
> entry.
> 
>>
>> 4. A slow or malicious AF_XDP application may easily cause an overflow of
>> the hardware receive ring. Your feature introduces a mechanism to pause the
>> driver while the congestion is on the application side, but no symmetric
>> mechanism to pause the application when the driver is close to an overflow.
>> I don't know the behavior of Intel NICs on overflow, but in our NICs it's
>> considered a critical error, that is followed by a recovery procedure, so
>> it's not something that should happen under normal workloads.
> 
> I'm not sure I follow on this one. Feature is about overflowing the XSK
> receive ring, not the HW one, right?

Right. So we have this pipeline of buffers:

NIC--> [HW RX ring] --NAPI--> [XSK RX ring] --app--> consumes packets

Currently, when the NIC puts stuff in HW RX ring, NAPI always runs and 
drains it either to XSK RX ring or to /dev/null if XSK RX ring is full. 
The driver fulfills its responsibility to prevent overflows of HW RX 
ring. If the application doesn't consume quick enough, the frames will 
be leaked, but it's only the application's issue, the driver stays 
consistent.

After the feature, it's possible to pause NAPI from the userspace 
application, effectively disrupting the driver's consistency. I don't 
think an XSK application should have this power.

> Driver picks entries from fill ring
> that were produced by app, so if app is slow on producing those I believe
> this would be rather an underflow of ring, we would simply receive less
> frames. For HW Rx ring actually being full, I think that HW would be
> dropping the incoming frames, so I don't see the real reason to treat this
> as critical error that needs to go through recovery.

I'll double check regarding the hardware behavior, but it is what it is. 
If an overflow moves the queue to the fault state and requires a 
recovery, there is nothing I can do about that.

A few more thoughts I just had: mlx5e shares the same NAPI instance to 
serve all queues in a channel, that includes the XSK RQ and the regular 
RQ. The regular and XSK traffic can be configured to be isolated to 
different channels, or they may co-exist on the same channel. If they 
co-exist, and XSK asks to pause NAPI, the regular traffic will still run 
NAPI and drop 1 XSK packet per NAPI cycle, unless point 3 is fixed. It 
can also be reproduced if NAPI is woken up by XSK TX. Besides, (correct 
me if I'm wrong) your current implementation introduces extra latency to 
XSK TX if XSK RX asked to pause NAPI, because NAPI will be restarted 
anyway (by TX wakeup), and it could have been rescheduled by the kernel.

> Am I missing something? Maybe I have just misunderstood you.
> 
>>
>>> One might ask why it is still relevant even after having proper busy
>>> poll support in place - here is the justification.
>>>
>>> For xdpsock that was:
>>> - run for l2fwd scenario,
>>> - app/driver processing took place on the same core in busy poll
>>>     with 2048 budget,
>>> - HW ring sizes Tx 256, Rx 2048,
>>>
>>> this work improved throughput by 78% and reduced Rx queue full statistic
>>> bump by 99%.
>>>
>>> For testing ice, make sure that you have [1] present on your side.
>>>
>>> This set, besides the work described above, also carries also
>>> improvements around return codes in various XSK paths and lastly a minor
>>> optimization for xskq_cons_has_entries(), a helper that might be used
>>> when XSK Rx batching would make it to the kernel.
>>
>> Regarding error codes, I would like them to be consistent across all
>> drivers, otherwise all the debuggability improvements are not useful enough.
>> Your series only changed Intel drivers. Here also applies the backward
>> compatibility concern: the same error codes than were in use have been
>> repurposed, which may confuse some of existing applications.
> 
> I'll double check if ZC drivers are doing something unusual with return
> values from xdp_do_redirect(). Regarding backward comp, I suppose you
> refer only to changes in ndo_xsk_wakeup() callbacks as others are not
> exposed to user space? They're not crucial to me, but it improved my
> debugging experience.

Sorry if I wasn't clear enough. Yes, I meant the wakeup error codes. We 
aren't doing anything unusual with xdp_do_redirect codes (can't say for 
other drivers, though).

Last time I wanted to improve error codes returned from some BPF helpers 
(make the errors more distinguishable), my patch was blocked because of 
backward compatibility concerns. To be on the safe side (i.e. to avoid 
further bug reports from someone who actually relied on specific codes), 
you might want to use a new error code, rather than repurposing the 
existing ones.

I personally don't have objections about changing the error codes the 
way you did if you keep them consistent across all drivers, not only 
Intel ones.

> FYI, your mail landed in my junk folder

That has to be something with your email server. I just sent an email to 
gmail, and it arrived to inbox. If anyone else (other than @intel.com) 
can't receive my emails, please tell me, I'll open a support ticket then.

> and the links [0] [1] are messed up in
> the reply you sent. And this is true even on lore.kernel.org. They suddenly
> refer to "nam11.safelinks.protection.outlook.com".

I'm afraid I can't do anything with these links. Our outlook server 
mangles them in all incoming letters as soon as they arrive. The letter 
I received from you already has them "sanitized".

> Maybe something worth
> looking into if you have this problem in the future.
> 
>>
>>> Thanks!
>>> MF
>>>
>>> [0]: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fbpf%2F20200904135332.60259-1-bjorn.topel%40gmail.com%2F&data=04%7C01%7Cmaximmi%40nvidia.com%7Cc9cefaa3a1cd465ccdb908da16f45eaf%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C637847536077594100%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=sLpTcgboo9YU55wtUtaY1%2F%2FbeiYxeWP5ubk%2FQ6X8vB8%3D&reserved=0
>>> [1]: https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Flore.kernel.org%2Fnetdev%2F20220317175727.340251-1-maciej.fijalkowski%40intel.com%2F&data=04%7C01%7Cmaximmi%40nvidia.com%7Cc9cefaa3a1cd465ccdb908da16f45eaf%7C43083d15727340c1b7db39efd9ccc17a%7C0%7C0%7C637847536077594100%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000&sdata=OWXeZhc2Nouz%2FTMWBxvtTYbw%2FS8HWQfbfEqnVc5478k%3D&reserved=0
>>>
>>> Björn Töpel (1):
>>>     xsk: improve xdp_do_redirect() error codes
>>>
>>> Maciej Fijalkowski (9):
>>>     xsk: diversify return codes in xsk_rcv_check()
>>>     ice: xsk: terminate NAPI when XSK Rx queue gets full
>>>     i40e: xsk: terminate NAPI when XSK Rx queue gets full
>>>     ixgbe: xsk: terminate NAPI when XSK Rx queue gets full
>>>     ice: xsk: diversify return values from xsk_wakeup call paths
>>>     i40e: xsk: diversify return values from xsk_wakeup call paths
>>>     ixgbe: xsk: diversify return values from xsk_wakeup call paths
>>>     ice: xsk: avoid refilling single Rx descriptors
>>>     xsk: drop ternary operator from xskq_cons_has_entries
>>>
>>>    .../ethernet/intel/i40e/i40e_txrx_common.h    |  1 +
>>>    drivers/net/ethernet/intel/i40e/i40e_xsk.c    | 27 +++++++++------
>>>    drivers/net/ethernet/intel/ice/ice_txrx.h     |  1 +
>>>    drivers/net/ethernet/intel/ice/ice_xsk.c      | 34 ++++++++++++-------
>>>    .../ethernet/intel/ixgbe/ixgbe_txrx_common.h  |  1 +
>>>    drivers/net/ethernet/intel/ixgbe/ixgbe_xsk.c  | 29 ++++++++++------
>>>    net/xdp/xsk.c                                 |  4 +--
>>>    net/xdp/xsk_queue.h                           |  4 +--
>>>    8 files changed, 64 insertions(+), 37 deletions(-)
>>>
>>
Jakub Kicinski April 8, 2022, 6:17 p.m. UTC | #4
On Fri, 8 Apr 2022 15:48:44 +0300 Maxim Mikityanskiy wrote:
> >> 4. A slow or malicious AF_XDP application may easily cause an overflow of
> >> the hardware receive ring. Your feature introduces a mechanism to pause the
> >> driver while the congestion is on the application side, but no symmetric
> >> mechanism to pause the application when the driver is close to an overflow.
> >> I don't know the behavior of Intel NICs on overflow, but in our NICs it's
> >> considered a critical error, that is followed by a recovery procedure, so
> >> it's not something that should happen under normal workloads.  
> > 
> > I'm not sure I follow on this one. Feature is about overflowing the XSK
> > receive ring, not the HW one, right?  
> 
> Right. So we have this pipeline of buffers:
> 
> NIC--> [HW RX ring] --NAPI--> [XSK RX ring] --app--> consumes packets
> 
> Currently, when the NIC puts stuff in HW RX ring, NAPI always runs and 
> drains it either to XSK RX ring or to /dev/null if XSK RX ring is full. 
> The driver fulfills its responsibility to prevent overflows of HW RX 
> ring. If the application doesn't consume quick enough, the frames will 
> be leaked, but it's only the application's issue, the driver stays 
> consistent.
> 
> After the feature, it's possible to pause NAPI from the userspace 
> application, effectively disrupting the driver's consistency. I don't 
> think an XSK application should have this power.

+1
cover letter refers to busy poll, but did that test enable prefer busy
poll w/ the timeout configured right? It seems like similar goal can 
be achieved with just that.
Maciej Fijalkowski April 11, 2022, 3:35 p.m. UTC | #5
On Fri, Apr 08, 2022 at 03:48:44PM +0300, Maxim Mikityanskiy wrote:
> On 2022-04-08 12:08, Maciej Fijalkowski wrote:
> > On Thu, Apr 07, 2022 at 01:49:02PM +0300, Maxim Mikityanskiy wrote:
> > > On 2022-04-05 14:06, Maciej Fijalkowski wrote:
> > > > Hi!
> > > > 
> > > > This is a revival of Bjorn's idea [0] to break NAPI loop when XSK Rx
> > > > queue gets full which in turn makes it impossible to keep on
> > > > successfully producing descriptors to XSK Rx ring. By breaking out of
> > > > the driver side immediately we will give the user space opportunity for
> > > > consuming descriptors from XSK Rx ring and therefore provide room in the
> > > > ring so that HW Rx -> XSK Rx redirection can be done.
> > > > 
> > > > Maxim asked and Jesper agreed on simplifying Bjorn's original API used
> > > > for detecting the event of interest, so let's just simply check for
> > > > -ENOBUFS within Intel's ZC drivers after an attempt to redirect a buffer
> > > > to XSK Rx. No real need for redirect API extension.
> > > 
> > 
> > Hey Maxim!
> > 
> > > I believe some of the other comments under the old series [0] might be still
> > > relevant:
> > > 
> > > 1. need_wakeup behavior. If need_wakeup is disabled, the expected behavior
> > > is busy-looping in NAPI, you shouldn't break out early, as the application
> > > does not restart NAPI, and the driver restarts it itself, leading to a less
> > > efficient loop. If need_wakeup is enabled, it should be set on ENOBUFS - I
> > > believe this is the case here, right?
> > 
> > Good point. We currently set need_wakeup flag for -ENOBUFS case as it is
> > being done for failure == true. You are right that we shouldn't be
> > breaking the loop on -ENOBUFS if need_wakeup flag is not set on xsk_pool,
> > will fix!
> > 
> > > 
> > > 2. 50/50 AF_XDP and XDP_TX mix usecase. By breaking out early, you prevent
> > > further packets from being XDP_TXed, leading to unnecessary latency
> > > increase. The new feature should be opt-in, otherwise such usecases suffer.
> > 
> > Anyone performing a lot of XDP_TX (or XDP_PASS, etc) should be using the
> > regular copy-mode driver, while the zero-copy driver should be used when most
> > packets are sent up to user-space.
> 
> You generalized that easily, but how can you be so sure that all mixed use
> cases can live with the much slower copy mode? Also, how do you apply your
> rule of thumb to the 75/25 AF_XDP/XDP_TX use case? It's both "a lot of
> XDP_TX" and "most packets are sent up to user-space" at the same time.

We are not aware of a single user that has this use case. What we do know
is that we have a lot of users that care about zero packet loss
performance when redirecting to an AF_XDP socket when using the zero-copy
driver. And this work addresses one of the corner cases and therefore
makes ZC driver better overall. So we say, focus on the cases people care
about. BTW, we do have users using mainly XDP_TX, XDP_PASS and
XDP_REDIRECT, but they are all using the regular driver for a good reason.
So we should not destroy those latencies as you mention.

> 
> At the moment, the application is free to decide whether it wants zerocopy
> XDP_TX or zerocopy AF_XDP, depending on its needs. After your patchset the
> only valid XDP verdict on zerocopy AF_XDP basically becomes "XDP_REDIRECT to
> XSKMAP". I don't think it's valid to break an entire feature to speed up
> some very specific use case.

We disagree that it 'breaks an entire feature' - it is about hardening the
driver when user did not come up with an optimal combo of ring sizes vs
busy poll budget. Driver needs to be able to handle such cases in a
reasonable way. What is more, (at least Intel) zero-copy drivers are
written in a way that XDP_REDIRECT to XSKMAP is the most probable verdict
that can come out of XDP program. However, other actions are of course
supported, so with your arguments, you could even say that we currently
treat redir as 'only valid' action, which is not true. Just note that
Intel's regular drivers (copy-mode AF_XDP socket) are optimized for
XDP_PASS (as that is the default without an XDP program in place) as that
is the most probable verdict for that driver.

> 
> Moreover, in early days of AF_XDP there was an attempt to implement zerocopy
> XDP_TX on AF_XDP queues, meaning both XDP_TX and AF_XDP could be zerocopy.
> The implementation suffered from possible overflows in driver queues, thus
> wasn't upstreamed, but it's still a valid idea that potentially could be
> done if overflows are worked around somehow.
> 

That feature would be good to have, but it has not been worked on and
might never be worked on since there seems to be little interest in XDP_TX
for the zero-copy driver. This also makes your argument about disregarding
XDP_TX a bit exaggerated. As we stated before, we have not seen a use case
from a real user for this.

> > For the zero-copy driver, this opt in is not
> > necessary. But it sounds like a valid option for copy mode, though could we
> > think about the proper way as a follow up to this work?
> 
> My opinion is that the knob has to be part of initial submission, and the
> new feature should be disabled by default, otherwise we have huge issues
> with backward compatibility (if we delay it, the next update changes the
> behavior, breaking some existing use cases, and there is no way to work
> around it).
> 

We would not like to introduce knobs for every
feature/optimization/trade-off we could think of unless we really have to.
Let us keep it simple. Zero-copy is optimized for XDP_REDIRECT to an
AF_XDP socket. The regular, copy-mode driver is optimized for the case
when the packet is consumed by the kernel stack or XDP. That means that we
should not introduce this optimization for the regular driver, as you say,
but it is fine to do it for the zero-copy driver without a knob. If we
ever introduce this for the regular driver, yes, we would need a knob.

> > > 
> > > 3. When the driver receives ENOBUFS, it has to drop the packet before
> > > returning to the application. It would be better experience if your feature
> > > saved all N packets from being dropped, not just N-1.
> > 
> > Sure, I'll re-run tests and see if we can omit freeing the current
> > xdp_buff and ntc bump, so that we would come back later on to the same
> > entry.
> > 
> > > 
> > > 4. A slow or malicious AF_XDP application may easily cause an overflow of
> > > the hardware receive ring. Your feature introduces a mechanism to pause the
> > > driver while the congestion is on the application side, but no symmetric
> > > mechanism to pause the application when the driver is close to an overflow.
> > > I don't know the behavior of Intel NICs on overflow, but in our NICs it's
> > > considered a critical error, that is followed by a recovery procedure, so
> > > it's not something that should happen under normal workloads.
> > 
> > I'm not sure I follow on this one. Feature is about overflowing the XSK
> > receive ring, not the HW one, right?
> 
> Right. So we have this pipeline of buffers:
> 
> NIC--> [HW RX ring] --NAPI--> [XSK RX ring] --app--> consumes packets
> 
> Currently, when the NIC puts stuff in HW RX ring, NAPI always runs and
> drains it either to XSK RX ring or to /dev/null if XSK RX ring is full. The
> driver fulfills its responsibility to prevent overflows of HW RX ring. If
> the application doesn't consume quick enough, the frames will be leaked, but
> it's only the application's issue, the driver stays consistent.
> 
> After the feature, it's possible to pause NAPI from the userspace
> application, effectively disrupting the driver's consistency. I don't think
> an XSK application should have this power.

It already has this power when using an AF_XDP socket. Nothing new. Some
examples, when using busy-poll together with gro_flush_timeout and
napi_defer_hard_irqs you already have this power. Another example is not
feeding buffers into the fill ring from the application side in zero-copy
mode. Also, application does not have to be "slow" in order to cause the
XSK Rx queue overflow. It can be the matter of not optimal budget choice
when compared to ring lengths, as stated above.

Besides that, you are right, in copy-mode (without busy-poll), let us not
introduce this as this would provide the application with this power when
it does not have it today.

> 
> > Driver picks entries from fill ring
> > that were produced by app, so if app is slow on producing those I believe
> > this would be rather an underflow of ring, we would simply receive less
> > frames. For HW Rx ring actually being full, I think that HW would be
> > dropping the incoming frames, so I don't see the real reason to treat this
> > as critical error that needs to go through recovery.
> 
> I'll double check regarding the hardware behavior, but it is what it is. If
> an overflow moves the queue to the fault state and requires a recovery,
> there is nothing I can do about that.
> 
> A few more thoughts I just had: mlx5e shares the same NAPI instance to serve
> all queues in a channel, that includes the XSK RQ and the regular RQ. The
> regular and XSK traffic can be configured to be isolated to different
> channels, or they may co-exist on the same channel. If they co-exist, and
> XSK asks to pause NAPI, the regular traffic will still run NAPI and drop 1
> XSK packet per NAPI cycle, unless point 3 is fixed. It can also be

XSK does not pause the whole NAPI cycle, your HW XSK RQ just stops with
doing redirects to AF_XDP XSK RQ. Your regular RQ is not affected in any
way. Finally point 3 needs to be fixed.

FWIW we also support having a channel/queue vector carrying more than one
RQ that is associated with particular NAPI instance.

> reproduced if NAPI is woken up by XSK TX. Besides, (correct me if I'm wrong)
> your current implementation introduces extra latency to XSK TX if XSK RX
> asked to pause NAPI, because NAPI will be restarted anyway (by TX wakeup),
> and it could have been rescheduled by the kernel.

Again, we don't pause NAPI. Tx and Rx processing are separate.

As for Intel drivers, Tx is processed first. So even if we break at Rx due
to -ENOBUFS from xdp_do_redirect(), Tx work has already been done.

To reiterate, we agreed on fixing point 1 and 3 from your original mail.
Valid and good points.

> 
> > Am I missing something? Maybe I have just misunderstood you.
> > 
> > > 
> > > > One might ask why it is still relevant even after having proper busy
> > > > poll support in place - here is the justification.
> > > > 
> > > > For xdpsock that was:
> > > > - run for l2fwd scenario,
> > > > - app/driver processing took place on the same core in busy poll
> > > >     with 2048 budget,
> > > > - HW ring sizes Tx 256, Rx 2048,
> > > > 
> > > > this work improved throughput by 78% and reduced Rx queue full statistic
> > > > bump by 99%.
> > > > 
> > > > For testing ice, make sure that you have [1] present on your side.
> > > > 
> > > > This set, besides the work described above, also carries also
> > > > improvements around return codes in various XSK paths and lastly a minor
> > > > optimization for xskq_cons_has_entries(), a helper that might be used
> > > > when XSK Rx batching would make it to the kernel.
> > > 
> > > Regarding error codes, I would like them to be consistent across all
> > > drivers, otherwise all the debuggability improvements are not useful enough.
> > > Your series only changed Intel drivers. Here also applies the backward
> > > compatibility concern: the same error codes than were in use have been
> > > repurposed, which may confuse some of existing applications.
> > 
> > I'll double check if ZC drivers are doing something unusual with return
> > values from xdp_do_redirect(). Regarding backward comp, I suppose you
> > refer only to changes in ndo_xsk_wakeup() callbacks as others are not
> > exposed to user space? They're not crucial to me, but it improved my
> > debugging experience.
> 
> Sorry if I wasn't clear enough. Yes, I meant the wakeup error codes. We
> aren't doing anything unusual with xdp_do_redirect codes (can't say for
> other drivers, though).
> 
> Last time I wanted to improve error codes returned from some BPF helpers
> (make the errors more distinguishable), my patch was blocked because of
> backward compatibility concerns. To be on the safe side (i.e. to avoid
> further bug reports from someone who actually relied on specific codes), you
> might want to use a new error code, rather than repurposing the existing
> ones.
> 
> I personally don't have objections about changing the error codes the way
> you did if you keep them consistent across all drivers, not only Intel ones.

Got your point. So I'll either drop the patches or look through
ndo_xsk_wakeup() implementations and try to standardize the ret codes.
Hope this sounds fine.

MF
Maciej Fijalkowski April 11, 2022, 3:46 p.m. UTC | #6
On Fri, Apr 08, 2022 at 11:17:56AM -0700, Jakub Kicinski wrote:
> On Fri, 8 Apr 2022 15:48:44 +0300 Maxim Mikityanskiy wrote:
> > >> 4. A slow or malicious AF_XDP application may easily cause an overflow of
> > >> the hardware receive ring. Your feature introduces a mechanism to pause the
> > >> driver while the congestion is on the application side, but no symmetric
> > >> mechanism to pause the application when the driver is close to an overflow.
> > >> I don't know the behavior of Intel NICs on overflow, but in our NICs it's
> > >> considered a critical error, that is followed by a recovery procedure, so
> > >> it's not something that should happen under normal workloads.  
> > > 
> > > I'm not sure I follow on this one. Feature is about overflowing the XSK
> > > receive ring, not the HW one, right?  
> > 
> > Right. So we have this pipeline of buffers:
> > 
> > NIC--> [HW RX ring] --NAPI--> [XSK RX ring] --app--> consumes packets
> > 
> > Currently, when the NIC puts stuff in HW RX ring, NAPI always runs and 
> > drains it either to XSK RX ring or to /dev/null if XSK RX ring is full. 
> > The driver fulfills its responsibility to prevent overflows of HW RX 
> > ring. If the application doesn't consume quick enough, the frames will 
> > be leaked, but it's only the application's issue, the driver stays 
> > consistent.
> > 
> > After the feature, it's possible to pause NAPI from the userspace 
> > application, effectively disrupting the driver's consistency. I don't 
> > think an XSK application should have this power.
> 
> +1
> cover letter refers to busy poll, but did that test enable prefer busy
> poll w/ the timeout configured right? It seems like similar goal can 
> be achieved with just that.

AF_XDP busy poll where app and driver runs on same core, without
configuring gro_flush_timeout and napi_defer_hard_irqs does not bring much
value, so all of the busy poll tests were done with:

echo 2 | sudo tee /sys/class/net/ens4f1/napi_defer_hard_irqs
echo 200000 | sudo tee /sys/class/net/ens4f1/gro_flush_timeout

That said, performance can still suffer and packets would not make it up
to user space even with timeout being configured in the case I'm trying to
improve.
Jakub Kicinski April 11, 2022, 5:07 p.m. UTC | #7
On Mon, 11 Apr 2022 17:46:06 +0200 Maciej Fijalkowski wrote:
> > +1
> > cover letter refers to busy poll, but did that test enable prefer busy
> > poll w/ the timeout configured right? It seems like similar goal can 
> > be achieved with just that.  
> 
> AF_XDP busy poll where app and driver runs on same core, without
> configuring gro_flush_timeout and napi_defer_hard_irqs does not bring much
> value, so all of the busy poll tests were done with:
> 
> echo 2 | sudo tee /sys/class/net/ens4f1/napi_defer_hard_irqs
> echo 200000 | sudo tee /sys/class/net/ens4f1/gro_flush_timeout
> 
> That said, performance can still suffer and packets would not make it up
> to user space even with timeout being configured in the case I'm trying to
> improve.

Does the system not break out of busy poll then? See if the NAPI
hrtimer fires or not.

It's a 2k queue IIRC, with timeout of 200us, so 10Mpps at least.
What rate is l2fwd sustaining without these patches?

You may have to either increase the timeout or increase the frequency
of repoll from user space (with a smaller budget).
Maxim Mikityanskiy April 13, 2022, 10:40 a.m. UTC | #8
On 2022-04-11 18:35, Maciej Fijalkowski wrote:
> On Fri, Apr 08, 2022 at 03:48:44PM +0300, Maxim Mikityanskiy wrote:
>> On 2022-04-08 12:08, Maciej Fijalkowski wrote:
>>> On Thu, Apr 07, 2022 at 01:49:02PM +0300, Maxim Mikityanskiy wrote:
>>>> On 2022-04-05 14:06, Maciej Fijalkowski wrote:
>>>>> Hi!
>>>>>
>>>>> This is a revival of Bjorn's idea [0] to break NAPI loop when XSK Rx
>>>>> queue gets full which in turn makes it impossible to keep on
>>>>> successfully producing descriptors to XSK Rx ring. By breaking out of
>>>>> the driver side immediately we will give the user space opportunity for
>>>>> consuming descriptors from XSK Rx ring and therefore provide room in the
>>>>> ring so that HW Rx -> XSK Rx redirection can be done.
>>>>>
>>>>> Maxim asked and Jesper agreed on simplifying Bjorn's original API used
>>>>> for detecting the event of interest, so let's just simply check for
>>>>> -ENOBUFS within Intel's ZC drivers after an attempt to redirect a buffer
>>>>> to XSK Rx. No real need for redirect API extension.
>>>>
>>>
>>> Hey Maxim!
>>>
>>>> I believe some of the other comments under the old series [0] might be still
>>>> relevant:
>>>>
>>>> 1. need_wakeup behavior. If need_wakeup is disabled, the expected behavior
>>>> is busy-looping in NAPI, you shouldn't break out early, as the application
>>>> does not restart NAPI, and the driver restarts it itself, leading to a less
>>>> efficient loop. If need_wakeup is enabled, it should be set on ENOBUFS - I
>>>> believe this is the case here, right?
>>>
>>> Good point. We currently set need_wakeup flag for -ENOBUFS case as it is
>>> being done for failure == true. You are right that we shouldn't be
>>> breaking the loop on -ENOBUFS if need_wakeup flag is not set on xsk_pool,
>>> will fix!
>>>
>>>>
>>>> 2. 50/50 AF_XDP and XDP_TX mix usecase. By breaking out early, you prevent
>>>> further packets from being XDP_TXed, leading to unnecessary latency
>>>> increase. The new feature should be opt-in, otherwise such usecases suffer.
>>>
>>> Anyone performing a lot of XDP_TX (or XDP_PASS, etc) should be using the
>>> regular copy-mode driver, while the zero-copy driver should be used when most
>>> packets are sent up to user-space.
>>
>> You generalized that easily, but how can you be so sure that all mixed use
>> cases can live with the much slower copy mode? Also, how do you apply your
>> rule of thumb to the 75/25 AF_XDP/XDP_TX use case? It's both "a lot of
>> XDP_TX" and "most packets are sent up to user-space" at the same time.
> 
> We are not aware of a single user that has this use case.

Doesn't mean there aren't any ;)

Back in the original series, Björn said it was a valid use case:

 > I'm leaning towards a more explicit opt-in like Max suggested. As Max
 > pointed out, AF_XDP/XDP_TX is actually a non-insane(!) way of using
 > AF_XDP zero-copy, which will suffer from the early exit.

https://lore.kernel.org/bpf/75146564-2774-47ac-cc75-40d74bea50d8@intel.com/

What has changed since then?

In any case, it's a significant behavior change that breaks backward 
compatibility and affects the mentioned use case. Such changes should go 
as opt-in: we have need_wakeup and unaligned chunks as opt-in features, 
so I don't see any reason to introduce a breaking change this time.

> What we do know
> is that we have a lot of users that care about zero packet loss
> performance when redirecting to an AF_XDP socket when using the zero-copy
> driver. And this work addresses one of the corner cases and therefore
> makes ZC driver better overall. So we say, focus on the cases people care
> about. BTW, we do have users using mainly XDP_TX, XDP_PASS and
> XDP_REDIRECT, but they are all using the regular driver for a good reason.
> So we should not destroy those latencies as you mention.
> 
>>
>> At the moment, the application is free to decide whether it wants zerocopy
>> XDP_TX or zerocopy AF_XDP, depending on its needs. After your patchset the
>> only valid XDP verdict on zerocopy AF_XDP basically becomes "XDP_REDIRECT to
>> XSKMAP". I don't think it's valid to break an entire feature to speed up
>> some very specific use case.
> 
> We disagree that it 'breaks an entire feature' - it is about hardening the
> driver when user did not come up with an optimal combo of ring sizes vs
> busy poll budget. Driver needs to be able to handle such cases in a
> reasonable way.

XDP_TX is a valid verdict on an XSK RX queue, and stopping XDP_TX 
processing for an indefinite time sounds to me as breaking the feature. 
  Improving performance doesn't justify breaking other stuff. It's OK to 
do so if the application explicitly acks that it doesn't care about 
XDP_TX, or (arguably) if it was the behavior from day one.

> What is more, (at least Intel) zero-copy drivers are
> written in a way that XDP_REDIRECT to XSKMAP is the most probable verdict
> that can come out of XDP program. However, other actions are of course
> supported, so with your arguments, you could even say that we currently
> treat redir as 'only valid' action, which is not true.

I did not say that, please don't attribute your speculations to me. One 
thing is optimizing for the most likely use case, the other is breaking 
unlikely use cases to improve the likely ones.

> Just note that
> Intel's regular drivers (copy-mode AF_XDP socket) are optimized for
> XDP_PASS (as that is the default without an XDP program in place) as that
> is the most probable verdict for that driver.
> 
>>
>> Moreover, in early days of AF_XDP there was an attempt to implement zerocopy
>> XDP_TX on AF_XDP queues, meaning both XDP_TX and AF_XDP could be zerocopy.
>> The implementation suffered from possible overflows in driver queues, thus
>> wasn't upstreamed, but it's still a valid idea that potentially could be
>> done if overflows are worked around somehow.
>>
> 
> That feature would be good to have, but it has not been worked on and
> might never be worked on since there seems to be little interest in XDP_TX
> for the zero-copy driver. This also makes your argument about disregarding
> XDP_TX a bit exaggerated. As we stated before, we have not seen a use case
> from a real user for this.
> 
>>> For the zero-copy driver, this opt in is not
>>> necessary. But it sounds like a valid option for copy mode, though could we
>>> think about the proper way as a follow up to this work?
>>
>> My opinion is that the knob has to be part of initial submission, and the
>> new feature should be disabled by default, otherwise we have huge issues
>> with backward compatibility (if we delay it, the next update changes the
>> behavior, breaking some existing use cases, and there is no way to work
>> around it).
>>
> 
> We would not like to introduce knobs for every
> feature/optimization/trade-off we could think of unless we really have to.
> Let us keep it simple. Zero-copy is optimized for XDP_REDIRECT to an
> AF_XDP socket. The regular, copy-mode driver is optimized for the case
> when the packet is consumed by the kernel stack or XDP. That means that we
> should not introduce this optimization for the regular driver, as you say,
> but it is fine to do it for the zero-copy driver without a knob. If we
> ever introduce this for the regular driver, yes, we would need a knob.
> 
>>>>
>>>> 3. When the driver receives ENOBUFS, it has to drop the packet before
>>>> returning to the application. It would be better experience if your feature
>>>> saved all N packets from being dropped, not just N-1.
>>>
>>> Sure, I'll re-run tests and see if we can omit freeing the current
>>> xdp_buff and ntc bump, so that we would come back later on to the same
>>> entry.
>>>
>>>>
>>>> 4. A slow or malicious AF_XDP application may easily cause an overflow of
>>>> the hardware receive ring. Your feature introduces a mechanism to pause the
>>>> driver while the congestion is on the application side, but no symmetric
>>>> mechanism to pause the application when the driver is close to an overflow.
>>>> I don't know the behavior of Intel NICs on overflow, but in our NICs it's
>>>> considered a critical error, that is followed by a recovery procedure, so
>>>> it's not something that should happen under normal workloads.
>>>
>>> I'm not sure I follow on this one. Feature is about overflowing the XSK
>>> receive ring, not the HW one, right?
>>
>> Right. So we have this pipeline of buffers:
>>
>> NIC--> [HW RX ring] --NAPI--> [XSK RX ring] --app--> consumes packets
>>
>> Currently, when the NIC puts stuff in HW RX ring, NAPI always runs and
>> drains it either to XSK RX ring or to /dev/null if XSK RX ring is full. The
>> driver fulfills its responsibility to prevent overflows of HW RX ring. If
>> the application doesn't consume quick enough, the frames will be leaked, but
>> it's only the application's issue, the driver stays consistent.
>>
>> After the feature, it's possible to pause NAPI from the userspace
>> application, effectively disrupting the driver's consistency. I don't think
>> an XSK application should have this power.
> 
> It already has this power when using an AF_XDP socket. Nothing new. Some
> examples, when using busy-poll together with gro_flush_timeout and
> napi_defer_hard_irqs you already have this power. Another example is not
> feeding buffers into the fill ring from the application side in zero-copy
> mode. Also, application does not have to be "slow" in order to cause the
> XSK Rx queue overflow. It can be the matter of not optimal budget choice
> when compared to ring lengths, as stated above.

(*)

> Besides that, you are right, in copy-mode (without busy-poll), let us not
> introduce this as this would provide the application with this power when
> it does not have it today.
> 
>>
>>> Driver picks entries from fill ring
>>> that were produced by app, so if app is slow on producing those I believe
>>> this would be rather an underflow of ring, we would simply receive less
>>> frames. For HW Rx ring actually being full, I think that HW would be
>>> dropping the incoming frames, so I don't see the real reason to treat this
>>> as critical error that needs to go through recovery.
>>
>> I'll double check regarding the hardware behavior, but it is what it is. If
>> an overflow moves the queue to the fault state and requires a recovery,
>> there is nothing I can do about that.

I double-checked that, and it seems there is no problem I indicated in 
point 4. In the mlx5e case, if NAPI is delayed, there will be lack of RX 
WQEs, and hardware will start dropping packets, and it's an absolutely 
regular situation. Your arguments above (*) are valid.

>> A few more thoughts I just had: mlx5e shares the same NAPI instance to serve
>> all queues in a channel, that includes the XSK RQ and the regular RQ. The
>> regular and XSK traffic can be configured to be isolated to different
>> channels, or they may co-exist on the same channel. If they co-exist, and
>> XSK asks to pause NAPI, the regular traffic will still run NAPI and drop 1
>> XSK packet per NAPI cycle, unless point 3 is fixed. It can also be
> 
> XSK does not pause the whole NAPI cycle, your HW XSK RQ just stops with
> doing redirects to AF_XDP XSK RQ. Your regular RQ is not affected in any
> way. Finally point 3 needs to be fixed.
> 
> FWIW we also support having a channel/queue vector carrying more than one
> RQ that is associated with particular NAPI instance.
> 
>> reproduced if NAPI is woken up by XSK TX. Besides, (correct me if I'm wrong)
>> your current implementation introduces extra latency to XSK TX if XSK RX
>> asked to pause NAPI, because NAPI will be restarted anyway (by TX wakeup),
>> and it could have been rescheduled by the kernel.
> 
> Again, we don't pause NAPI. Tx and Rx processing are separate.
> 
> As for Intel drivers, Tx is processed first. So even if we break at Rx due
> to -ENOBUFS from xdp_do_redirect(), Tx work has already been done.
> 
> To reiterate, we agreed on fixing point 1 and 3 from your original mail.
> Valid and good points.

Great that we agreed on 1 and 3! Point 4 can be dropped. For point 2, I 
wrote my thoughts above.

>>
>>> Am I missing something? Maybe I have just misunderstood you.
>>>
>>>>
>>>>> One might ask why it is still relevant even after having proper busy
>>>>> poll support in place - here is the justification.
>>>>>
>>>>> For xdpsock that was:
>>>>> - run for l2fwd scenario,
>>>>> - app/driver processing took place on the same core in busy poll
>>>>>      with 2048 budget,
>>>>> - HW ring sizes Tx 256, Rx 2048,
>>>>>
>>>>> this work improved throughput by 78% and reduced Rx queue full statistic
>>>>> bump by 99%.
>>>>>
>>>>> For testing ice, make sure that you have [1] present on your side.
>>>>>
>>>>> This set, besides the work described above, also carries also
>>>>> improvements around return codes in various XSK paths and lastly a minor
>>>>> optimization for xskq_cons_has_entries(), a helper that might be used
>>>>> when XSK Rx batching would make it to the kernel.
>>>>
>>>> Regarding error codes, I would like them to be consistent across all
>>>> drivers, otherwise all the debuggability improvements are not useful enough.
>>>> Your series only changed Intel drivers. Here also applies the backward
>>>> compatibility concern: the same error codes than were in use have been
>>>> repurposed, which may confuse some of existing applications.
>>>
>>> I'll double check if ZC drivers are doing something unusual with return
>>> values from xdp_do_redirect(). Regarding backward comp, I suppose you
>>> refer only to changes in ndo_xsk_wakeup() callbacks as others are not
>>> exposed to user space? They're not crucial to me, but it improved my
>>> debugging experience.
>>
>> Sorry if I wasn't clear enough. Yes, I meant the wakeup error codes. We
>> aren't doing anything unusual with xdp_do_redirect codes (can't say for
>> other drivers, though).
>>
>> Last time I wanted to improve error codes returned from some BPF helpers
>> (make the errors more distinguishable), my patch was blocked because of
>> backward compatibility concerns. To be on the safe side (i.e. to avoid
>> further bug reports from someone who actually relied on specific codes), you
>> might want to use a new error code, rather than repurposing the existing
>> ones.
>>
>> I personally don't have objections about changing the error codes the way
>> you did if you keep them consistent across all drivers, not only Intel ones.
> 
> Got your point. So I'll either drop the patches or look through
> ndo_xsk_wakeup() implementations and try to standardize the ret codes.
> Hope this sounds fine.

Yes, either way sounds absolutely fine to me.

> 
> MF
Magnus Karlsson April 13, 2022, 3:12 p.m. UTC | #9
On Wed, Apr 13, 2022 at 1:40 PM Maxim Mikityanskiy <maximmi@nvidia.com> wrote:
>
> On 2022-04-11 18:35, Maciej Fijalkowski wrote:
> > On Fri, Apr 08, 2022 at 03:48:44PM +0300, Maxim Mikityanskiy wrote:
> >> On 2022-04-08 12:08, Maciej Fijalkowski wrote:
> >>> On Thu, Apr 07, 2022 at 01:49:02PM +0300, Maxim Mikityanskiy wrote:
> >>>> On 2022-04-05 14:06, Maciej Fijalkowski wrote:
> >>>>> Hi!
> >>>>>
> >>>>> This is a revival of Bjorn's idea [0] to break NAPI loop when XSK Rx
> >>>>> queue gets full which in turn makes it impossible to keep on
> >>>>> successfully producing descriptors to XSK Rx ring. By breaking out of
> >>>>> the driver side immediately we will give the user space opportunity for
> >>>>> consuming descriptors from XSK Rx ring and therefore provide room in the
> >>>>> ring so that HW Rx -> XSK Rx redirection can be done.
> >>>>>
> >>>>> Maxim asked and Jesper agreed on simplifying Bjorn's original API used
> >>>>> for detecting the event of interest, so let's just simply check for
> >>>>> -ENOBUFS within Intel's ZC drivers after an attempt to redirect a buffer
> >>>>> to XSK Rx. No real need for redirect API extension.
> >>>>
> >>>
> >>> Hey Maxim!
> >>>
> >>>> I believe some of the other comments under the old series [0] might be still
> >>>> relevant:
> >>>>
> >>>> 1. need_wakeup behavior. If need_wakeup is disabled, the expected behavior
> >>>> is busy-looping in NAPI, you shouldn't break out early, as the application
> >>>> does not restart NAPI, and the driver restarts it itself, leading to a less
> >>>> efficient loop. If need_wakeup is enabled, it should be set on ENOBUFS - I
> >>>> believe this is the case here, right?
> >>>
> >>> Good point. We currently set need_wakeup flag for -ENOBUFS case as it is
> >>> being done for failure == true. You are right that we shouldn't be
> >>> breaking the loop on -ENOBUFS if need_wakeup flag is not set on xsk_pool,
> >>> will fix!
> >>>
> >>>>
> >>>> 2. 50/50 AF_XDP and XDP_TX mix usecase. By breaking out early, you prevent
> >>>> further packets from being XDP_TXed, leading to unnecessary latency
> >>>> increase. The new feature should be opt-in, otherwise such usecases suffer.
> >>>
> >>> Anyone performing a lot of XDP_TX (or XDP_PASS, etc) should be using the
> >>> regular copy-mode driver, while the zero-copy driver should be used when most
> >>> packets are sent up to user-space.
> >>
> >> You generalized that easily, but how can you be so sure that all mixed use
> >> cases can live with the much slower copy mode? Also, how do you apply your
> >> rule of thumb to the 75/25 AF_XDP/XDP_TX use case? It's both "a lot of
> >> XDP_TX" and "most packets are sent up to user-space" at the same time.
> >
> > We are not aware of a single user that has this use case.
>
> Doesn't mean there aren't any ;)
>
> Back in the original series, Björn said it was a valid use case:
>
>  > I'm leaning towards a more explicit opt-in like Max suggested. As Max
>  > pointed out, AF_XDP/XDP_TX is actually a non-insane(!) way of using
>  > AF_XDP zero-copy, which will suffer from the early exit.
>
> https://lore.kernel.org/bpf/75146564-2774-47ac-cc75-40d74bea50d8@intel.com/
>
> What has changed since then?

We now have real use cases and have become wiser ;-).

> In any case, it's a significant behavior change that breaks backward
> compatibility and affects the mentioned use case. Such changes should go
> as opt-in: we have need_wakeup and unaligned chunks as opt-in features,
> so I don't see any reason to introduce a breaking change this time.

In my opinion, the existing flags you mentioned are different. The
unaligned flag changes the format of the descriptor and the
need_wakeup flag can stop the driver so user space needs to explicitly
wake it up. These options really change the uapi and not refactoring
the application for this would really break it, so an opt-in was a
must. What Maciej is suggesting is about changing the performance for
a case that I have never seen (does not mean it does not exist though
because I do not know all users of course, but it is at least
uncommon). Do we want to put an opt-in for every performance change we
commit. I say no. But at some point a performance change might of
course be so large that it is warranted. It should also be for a use
case that exists, or at least we believe exists. I do not think that
is the case for this one. But if someone out there really has this use
case, please let me know and I will be happy to change my opinion.

> > What we do know
> > is that we have a lot of users that care about zero packet loss
> > performance when redirecting to an AF_XDP socket when using the zero-copy
> > driver. And this work addresses one of the corner cases and therefore
> > makes ZC driver better overall. So we say, focus on the cases people care
> > about. BTW, we do have users using mainly XDP_TX, XDP_PASS and
> > XDP_REDIRECT, but they are all using the regular driver for a good reason.
> > So we should not destroy those latencies as you mention.
> >
> >>
> >> At the moment, the application is free to decide whether it wants zerocopy
> >> XDP_TX or zerocopy AF_XDP, depending on its needs. After your patchset the
> >> only valid XDP verdict on zerocopy AF_XDP basically becomes "XDP_REDIRECT to
> >> XSKMAP". I don't think it's valid to break an entire feature to speed up
> >> some very specific use case.
> >
> > We disagree that it 'breaks an entire feature' - it is about hardening the
> > driver when user did not come up with an optimal combo of ring sizes vs
> > busy poll budget. Driver needs to be able to handle such cases in a
> > reasonable way.
>
> XDP_TX is a valid verdict on an XSK RX queue, and stopping XDP_TX
> processing for an indefinite time sounds to me as breaking the feature.
>   Improving performance doesn't justify breaking other stuff. It's OK to
> do so if the application explicitly acks that it doesn't care about
> XDP_TX, or (arguably) if it was the behavior from day one.
>
> > What is more, (at least Intel) zero-copy drivers are
> > written in a way that XDP_REDIRECT to XSKMAP is the most probable verdict
> > that can come out of XDP program. However, other actions are of course
> > supported, so with your arguments, you could even say that we currently
> > treat redir as 'only valid' action, which is not true.
>
> I did not say that, please don't attribute your speculations to me. One
> thing is optimizing for the most likely use case, the other is breaking
> unlikely use cases to improve the likely ones.
>
> > Just note that
> > Intel's regular drivers (copy-mode AF_XDP socket) are optimized for
> > XDP_PASS (as that is the default without an XDP program in place) as that
> > is the most probable verdict for that driver.
> >
> >>
> >> Moreover, in early days of AF_XDP there was an attempt to implement zerocopy
> >> XDP_TX on AF_XDP queues, meaning both XDP_TX and AF_XDP could be zerocopy.
> >> The implementation suffered from possible overflows in driver queues, thus
> >> wasn't upstreamed, but it's still a valid idea that potentially could be
> >> done if overflows are worked around somehow.
> >>
> >
> > That feature would be good to have, but it has not been worked on and
> > might never be worked on since there seems to be little interest in XDP_TX
> > for the zero-copy driver. This also makes your argument about disregarding
> > XDP_TX a bit exaggerated. As we stated before, we have not seen a use case
> > from a real user for this.
> >
> >>> For the zero-copy driver, this opt in is not
> >>> necessary. But it sounds like a valid option for copy mode, though could we
> >>> think about the proper way as a follow up to this work?
> >>
> >> My opinion is that the knob has to be part of initial submission, and the
> >> new feature should be disabled by default, otherwise we have huge issues
> >> with backward compatibility (if we delay it, the next update changes the
> >> behavior, breaking some existing use cases, and there is no way to work
> >> around it).
> >>
> >
> > We would not like to introduce knobs for every
> > feature/optimization/trade-off we could think of unless we really have to.
> > Let us keep it simple. Zero-copy is optimized for XDP_REDIRECT to an
> > AF_XDP socket. The regular, copy-mode driver is optimized for the case
> > when the packet is consumed by the kernel stack or XDP. That means that we
> > should not introduce this optimization for the regular driver, as you say,
> > but it is fine to do it for the zero-copy driver without a knob. If we
> > ever introduce this for the regular driver, yes, we would need a knob.
> >
> >>>>
> >>>> 3. When the driver receives ENOBUFS, it has to drop the packet before
> >>>> returning to the application. It would be better experience if your feature
> >>>> saved all N packets from being dropped, not just N-1.
> >>>
> >>> Sure, I'll re-run tests and see if we can omit freeing the current
> >>> xdp_buff and ntc bump, so that we would come back later on to the same
> >>> entry.
> >>>
> >>>>
> >>>> 4. A slow or malicious AF_XDP application may easily cause an overflow of
> >>>> the hardware receive ring. Your feature introduces a mechanism to pause the
> >>>> driver while the congestion is on the application side, but no symmetric
> >>>> mechanism to pause the application when the driver is close to an overflow.
> >>>> I don't know the behavior of Intel NICs on overflow, but in our NICs it's
> >>>> considered a critical error, that is followed by a recovery procedure, so
> >>>> it's not something that should happen under normal workloads.
> >>>
> >>> I'm not sure I follow on this one. Feature is about overflowing the XSK
> >>> receive ring, not the HW one, right?
> >>
> >> Right. So we have this pipeline of buffers:
> >>
> >> NIC--> [HW RX ring] --NAPI--> [XSK RX ring] --app--> consumes packets
> >>
> >> Currently, when the NIC puts stuff in HW RX ring, NAPI always runs and
> >> drains it either to XSK RX ring or to /dev/null if XSK RX ring is full. The
> >> driver fulfills its responsibility to prevent overflows of HW RX ring. If
> >> the application doesn't consume quick enough, the frames will be leaked, but
> >> it's only the application's issue, the driver stays consistent.
> >>
> >> After the feature, it's possible to pause NAPI from the userspace
> >> application, effectively disrupting the driver's consistency. I don't think
> >> an XSK application should have this power.
> >
> > It already has this power when using an AF_XDP socket. Nothing new. Some
> > examples, when using busy-poll together with gro_flush_timeout and
> > napi_defer_hard_irqs you already have this power. Another example is not
> > feeding buffers into the fill ring from the application side in zero-copy
> > mode. Also, application does not have to be "slow" in order to cause the
> > XSK Rx queue overflow. It can be the matter of not optimal budget choice
> > when compared to ring lengths, as stated above.
>
> (*)
>
> > Besides that, you are right, in copy-mode (without busy-poll), let us not
> > introduce this as this would provide the application with this power when
> > it does not have it today.
> >
> >>
> >>> Driver picks entries from fill ring
> >>> that were produced by app, so if app is slow on producing those I believe
> >>> this would be rather an underflow of ring, we would simply receive less
> >>> frames. For HW Rx ring actually being full, I think that HW would be
> >>> dropping the incoming frames, so I don't see the real reason to treat this
> >>> as critical error that needs to go through recovery.
> >>
> >> I'll double check regarding the hardware behavior, but it is what it is. If
> >> an overflow moves the queue to the fault state and requires a recovery,
> >> there is nothing I can do about that.
>
> I double-checked that, and it seems there is no problem I indicated in
> point 4. In the mlx5e case, if NAPI is delayed, there will be lack of RX
> WQEs, and hardware will start dropping packets, and it's an absolutely
> regular situation. Your arguments above (*) are valid.
>
> >> A few more thoughts I just had: mlx5e shares the same NAPI instance to serve
> >> all queues in a channel, that includes the XSK RQ and the regular RQ. The
> >> regular and XSK traffic can be configured to be isolated to different
> >> channels, or they may co-exist on the same channel. If they co-exist, and
> >> XSK asks to pause NAPI, the regular traffic will still run NAPI and drop 1
> >> XSK packet per NAPI cycle, unless point 3 is fixed. It can also be
> >
> > XSK does not pause the whole NAPI cycle, your HW XSK RQ just stops with
> > doing redirects to AF_XDP XSK RQ. Your regular RQ is not affected in any
> > way. Finally point 3 needs to be fixed.
> >
> > FWIW we also support having a channel/queue vector carrying more than one
> > RQ that is associated with particular NAPI instance.
> >
> >> reproduced if NAPI is woken up by XSK TX. Besides, (correct me if I'm wrong)
> >> your current implementation introduces extra latency to XSK TX if XSK RX
> >> asked to pause NAPI, because NAPI will be restarted anyway (by TX wakeup),
> >> and it could have been rescheduled by the kernel.
> >
> > Again, we don't pause NAPI. Tx and Rx processing are separate.
> >
> > As for Intel drivers, Tx is processed first. So even if we break at Rx due
> > to -ENOBUFS from xdp_do_redirect(), Tx work has already been done.
> >
> > To reiterate, we agreed on fixing point 1 and 3 from your original mail.
> > Valid and good points.
>
> Great that we agreed on 1 and 3! Point 4 can be dropped. For point 2, I
> wrote my thoughts above.
>
> >>
> >>> Am I missing something? Maybe I have just misunderstood you.
> >>>
> >>>>
> >>>>> One might ask why it is still relevant even after having proper busy
> >>>>> poll support in place - here is the justification.
> >>>>>
> >>>>> For xdpsock that was:
> >>>>> - run for l2fwd scenario,
> >>>>> - app/driver processing took place on the same core in busy poll
> >>>>>      with 2048 budget,
> >>>>> - HW ring sizes Tx 256, Rx 2048,
> >>>>>
> >>>>> this work improved throughput by 78% and reduced Rx queue full statistic
> >>>>> bump by 99%.
> >>>>>
> >>>>> For testing ice, make sure that you have [1] present on your side.
> >>>>>
> >>>>> This set, besides the work described above, also carries also
> >>>>> improvements around return codes in various XSK paths and lastly a minor
> >>>>> optimization for xskq_cons_has_entries(), a helper that might be used
> >>>>> when XSK Rx batching would make it to the kernel.
> >>>>
> >>>> Regarding error codes, I would like them to be consistent across all
> >>>> drivers, otherwise all the debuggability improvements are not useful enough.
> >>>> Your series only changed Intel drivers. Here also applies the backward
> >>>> compatibility concern: the same error codes than were in use have been
> >>>> repurposed, which may confuse some of existing applications.
> >>>
> >>> I'll double check if ZC drivers are doing something unusual with return
> >>> values from xdp_do_redirect(). Regarding backward comp, I suppose you
> >>> refer only to changes in ndo_xsk_wakeup() callbacks as others are not
> >>> exposed to user space? They're not crucial to me, but it improved my
> >>> debugging experience.
> >>
> >> Sorry if I wasn't clear enough. Yes, I meant the wakeup error codes. We
> >> aren't doing anything unusual with xdp_do_redirect codes (can't say for
> >> other drivers, though).
> >>
> >> Last time I wanted to improve error codes returned from some BPF helpers
> >> (make the errors more distinguishable), my patch was blocked because of
> >> backward compatibility concerns. To be on the safe side (i.e. to avoid
> >> further bug reports from someone who actually relied on specific codes), you
> >> might want to use a new error code, rather than repurposing the existing
> >> ones.
> >>
> >> I personally don't have objections about changing the error codes the way
> >> you did if you keep them consistent across all drivers, not only Intel ones.
> >
> > Got your point. So I'll either drop the patches or look through
> > ndo_xsk_wakeup() implementations and try to standardize the ret codes.
> > Hope this sounds fine.
>
> Yes, either way sounds absolutely fine to me.
>
> >
> > MF
>
Maciej Fijalkowski April 13, 2022, 3:26 p.m. UTC | #10
On Wed, Apr 13, 2022 at 05:12:09PM +0200, Magnus Karlsson wrote:
> On Wed, Apr 13, 2022 at 1:40 PM Maxim Mikityanskiy <maximmi@nvidia.com> wrote:
> >
> > On 2022-04-11 18:35, Maciej Fijalkowski wrote:
> > > On Fri, Apr 08, 2022 at 03:48:44PM +0300, Maxim Mikityanskiy wrote:
> > >> On 2022-04-08 12:08, Maciej Fijalkowski wrote:
> > >>> On Thu, Apr 07, 2022 at 01:49:02PM +0300, Maxim Mikityanskiy wrote:
> > >>>> On 2022-04-05 14:06, Maciej Fijalkowski wrote:
> > >>>>> Hi!
> > >>>>>
> > >>>>> This is a revival of Bjorn's idea [0] to break NAPI loop when XSK Rx
> > >>>>> queue gets full which in turn makes it impossible to keep on
> > >>>>> successfully producing descriptors to XSK Rx ring. By breaking out of
> > >>>>> the driver side immediately we will give the user space opportunity for
> > >>>>> consuming descriptors from XSK Rx ring and therefore provide room in the
> > >>>>> ring so that HW Rx -> XSK Rx redirection can be done.
> > >>>>>
> > >>>>> Maxim asked and Jesper agreed on simplifying Bjorn's original API used
> > >>>>> for detecting the event of interest, so let's just simply check for
> > >>>>> -ENOBUFS within Intel's ZC drivers after an attempt to redirect a buffer
> > >>>>> to XSK Rx. No real need for redirect API extension.
> > >>>>
> > >>>
> > >>> Hey Maxim!
> > >>>
> > >>>> I believe some of the other comments under the old series [0] might be still
> > >>>> relevant:
> > >>>>
> > >>>> 1. need_wakeup behavior. If need_wakeup is disabled, the expected behavior
> > >>>> is busy-looping in NAPI, you shouldn't break out early, as the application
> > >>>> does not restart NAPI, and the driver restarts it itself, leading to a less
> > >>>> efficient loop. If need_wakeup is enabled, it should be set on ENOBUFS - I
> > >>>> believe this is the case here, right?
> > >>>
> > >>> Good point. We currently set need_wakeup flag for -ENOBUFS case as it is
> > >>> being done for failure == true. You are right that we shouldn't be
> > >>> breaking the loop on -ENOBUFS if need_wakeup flag is not set on xsk_pool,
> > >>> will fix!
> > >>>
> > >>>>
> > >>>> 2. 50/50 AF_XDP and XDP_TX mix usecase. By breaking out early, you prevent
> > >>>> further packets from being XDP_TXed, leading to unnecessary latency
> > >>>> increase. The new feature should be opt-in, otherwise such usecases suffer.
> > >>>
> > >>> Anyone performing a lot of XDP_TX (or XDP_PASS, etc) should be using the
> > >>> regular copy-mode driver, while the zero-copy driver should be used when most
> > >>> packets are sent up to user-space.
> > >>
> > >> You generalized that easily, but how can you be so sure that all mixed use
> > >> cases can live with the much slower copy mode? Also, how do you apply your
> > >> rule of thumb to the 75/25 AF_XDP/XDP_TX use case? It's both "a lot of
> > >> XDP_TX" and "most packets are sent up to user-space" at the same time.
> > >
> > > We are not aware of a single user that has this use case.
> >
> > Doesn't mean there aren't any ;)
> >
> > Back in the original series, Björn said it was a valid use case:
> >
> >  > I'm leaning towards a more explicit opt-in like Max suggested. As Max
> >  > pointed out, AF_XDP/XDP_TX is actually a non-insane(!) way of using
> >  > AF_XDP zero-copy, which will suffer from the early exit.
> >
> > https://lore.kernel.org/bpf/75146564-2774-47ac-cc75-40d74bea50d8@intel.com/
> >
> > What has changed since then?
> 
> We now have real use cases and have become wiser ;-).

Bjorn said it was valid use case but we still do not have any real life
example of it...

> 
> > In any case, it's a significant behavior change that breaks backward
> > compatibility and affects the mentioned use case. Such changes should go
> > as opt-in: we have need_wakeup and unaligned chunks as opt-in features,
> > so I don't see any reason to introduce a breaking change this time.
> 
> In my opinion, the existing flags you mentioned are different. The
> unaligned flag changes the format of the descriptor and the
> need_wakeup flag can stop the driver so user space needs to explicitly
> wake it up. These options really change the uapi and not refactoring
> the application for this would really break it, so an opt-in was a
> must. What Maciej is suggesting is about changing the performance for
> a case that I have never seen (does not mean it does not exist though
> because I do not know all users of course, but it is at least
> uncommon). Do we want to put an opt-in for every performance change we
> commit. I say no. But at some point a performance change might of
> course be so large that it is warranted. It should also be for a use
> case that exists, or at least we believe exists. I do not think that
> is the case for this one. But if someone out there really has this use
> case, please let me know and I will be happy to change my opinion.

FWIW, to get this going, I will send a v2 without opt-in but with points 1
and 3 addressed.  I also changed ENXIO to EINVAL in mlx5 and stmmac's
ndo_xsk_wakeup().

> 
> > > What we do know
> > > is that we have a lot of users that care about zero packet loss
> > > performance when redirecting to an AF_XDP socket when using the zero-copy
> > > driver. And this work addresses one of the corner cases and therefore
> > > makes ZC driver better overall. So we say, focus on the cases people care
> > > about. BTW, we do have users using mainly XDP_TX, XDP_PASS and
> > > XDP_REDIRECT, but they are all using the regular driver for a good reason.
> > > So we should not destroy those latencies as you mention.
> > >
> > >>
> > >> At the moment, the application is free to decide whether it wants zerocopy
> > >> XDP_TX or zerocopy AF_XDP, depending on its needs. After your patchset the
> > >> only valid XDP verdict on zerocopy AF_XDP basically becomes "XDP_REDIRECT to
> > >> XSKMAP". I don't think it's valid to break an entire feature to speed up
> > >> some very specific use case.
> > >
> > > We disagree that it 'breaks an entire feature' - it is about hardening the
> > > driver when user did not come up with an optimal combo of ring sizes vs
> > > busy poll budget. Driver needs to be able to handle such cases in a
> > > reasonable way.
> >
> > XDP_TX is a valid verdict on an XSK RX queue, and stopping XDP_TX
> > processing for an indefinite time sounds to me as breaking the feature.
> >   Improving performance doesn't justify breaking other stuff. It's OK to
> > do so if the application explicitly acks that it doesn't care about
> > XDP_TX, or (arguably) if it was the behavior from day one.
> >
> > > What is more, (at least Intel) zero-copy drivers are
> > > written in a way that XDP_REDIRECT to XSKMAP is the most probable verdict
> > > that can come out of XDP program. However, other actions are of course
> > > supported, so with your arguments, you could even say that we currently
> > > treat redir as 'only valid' action, which is not true.
> >
> > I did not say that, please don't attribute your speculations to me. One
> > thing is optimizing for the most likely use case, the other is breaking
> > unlikely use cases to improve the likely ones.
> >
> > > Just note that
> > > Intel's regular drivers (copy-mode AF_XDP socket) are optimized for
> > > XDP_PASS (as that is the default without an XDP program in place) as that
> > > is the most probable verdict for that driver.
> > >
> > >>
> > >> Moreover, in early days of AF_XDP there was an attempt to implement zerocopy
> > >> XDP_TX on AF_XDP queues, meaning both XDP_TX and AF_XDP could be zerocopy.
> > >> The implementation suffered from possible overflows in driver queues, thus
> > >> wasn't upstreamed, but it's still a valid idea that potentially could be
> > >> done if overflows are worked around somehow.
> > >>
> > >
> > > That feature would be good to have, but it has not been worked on and
> > > might never be worked on since there seems to be little interest in XDP_TX
> > > for the zero-copy driver. This also makes your argument about disregarding
> > > XDP_TX a bit exaggerated. As we stated before, we have not seen a use case
> > > from a real user for this.
> > >
> > >>> For the zero-copy driver, this opt in is not
> > >>> necessary. But it sounds like a valid option for copy mode, though could we
> > >>> think about the proper way as a follow up to this work?
> > >>
> > >> My opinion is that the knob has to be part of initial submission, and the
> > >> new feature should be disabled by default, otherwise we have huge issues
> > >> with backward compatibility (if we delay it, the next update changes the
> > >> behavior, breaking some existing use cases, and there is no way to work
> > >> around it).
> > >>
> > >
> > > We would not like to introduce knobs for every
> > > feature/optimization/trade-off we could think of unless we really have to.
> > > Let us keep it simple. Zero-copy is optimized for XDP_REDIRECT to an
> > > AF_XDP socket. The regular, copy-mode driver is optimized for the case
> > > when the packet is consumed by the kernel stack or XDP. That means that we
> > > should not introduce this optimization for the regular driver, as you say,
> > > but it is fine to do it for the zero-copy driver without a knob. If we
> > > ever introduce this for the regular driver, yes, we would need a knob.
> > >
> > >>>>
> > >>>> 3. When the driver receives ENOBUFS, it has to drop the packet before
> > >>>> returning to the application. It would be better experience if your feature
> > >>>> saved all N packets from being dropped, not just N-1.
> > >>>
> > >>> Sure, I'll re-run tests and see if we can omit freeing the current
> > >>> xdp_buff and ntc bump, so that we would come back later on to the same
> > >>> entry.
> > >>>
> > >>>>
> > >>>> 4. A slow or malicious AF_XDP application may easily cause an overflow of
> > >>>> the hardware receive ring. Your feature introduces a mechanism to pause the
> > >>>> driver while the congestion is on the application side, but no symmetric
> > >>>> mechanism to pause the application when the driver is close to an overflow.
> > >>>> I don't know the behavior of Intel NICs on overflow, but in our NICs it's
> > >>>> considered a critical error, that is followed by a recovery procedure, so
> > >>>> it's not something that should happen under normal workloads.
> > >>>
> > >>> I'm not sure I follow on this one. Feature is about overflowing the XSK
> > >>> receive ring, not the HW one, right?
> > >>
> > >> Right. So we have this pipeline of buffers:
> > >>
> > >> NIC--> [HW RX ring] --NAPI--> [XSK RX ring] --app--> consumes packets
> > >>
> > >> Currently, when the NIC puts stuff in HW RX ring, NAPI always runs and
> > >> drains it either to XSK RX ring or to /dev/null if XSK RX ring is full. The
> > >> driver fulfills its responsibility to prevent overflows of HW RX ring. If
> > >> the application doesn't consume quick enough, the frames will be leaked, but
> > >> it's only the application's issue, the driver stays consistent.
> > >>
> > >> After the feature, it's possible to pause NAPI from the userspace
> > >> application, effectively disrupting the driver's consistency. I don't think
> > >> an XSK application should have this power.
> > >
> > > It already has this power when using an AF_XDP socket. Nothing new. Some
> > > examples, when using busy-poll together with gro_flush_timeout and
> > > napi_defer_hard_irqs you already have this power. Another example is not
> > > feeding buffers into the fill ring from the application side in zero-copy
> > > mode. Also, application does not have to be "slow" in order to cause the
> > > XSK Rx queue overflow. It can be the matter of not optimal budget choice
> > > when compared to ring lengths, as stated above.
> >
> > (*)
> >
> > > Besides that, you are right, in copy-mode (without busy-poll), let us not
> > > introduce this as this would provide the application with this power when
> > > it does not have it today.
> > >
> > >>
> > >>> Driver picks entries from fill ring
> > >>> that were produced by app, so if app is slow on producing those I believe
> > >>> this would be rather an underflow of ring, we would simply receive less
> > >>> frames. For HW Rx ring actually being full, I think that HW would be
> > >>> dropping the incoming frames, so I don't see the real reason to treat this
> > >>> as critical error that needs to go through recovery.
> > >>
> > >> I'll double check regarding the hardware behavior, but it is what it is. If
> > >> an overflow moves the queue to the fault state and requires a recovery,
> > >> there is nothing I can do about that.
> >
> > I double-checked that, and it seems there is no problem I indicated in
> > point 4. In the mlx5e case, if NAPI is delayed, there will be lack of RX
> > WQEs, and hardware will start dropping packets, and it's an absolutely
> > regular situation. Your arguments above (*) are valid.
> >
> > >> A few more thoughts I just had: mlx5e shares the same NAPI instance to serve
> > >> all queues in a channel, that includes the XSK RQ and the regular RQ. The
> > >> regular and XSK traffic can be configured to be isolated to different
> > >> channels, or they may co-exist on the same channel. If they co-exist, and
> > >> XSK asks to pause NAPI, the regular traffic will still run NAPI and drop 1
> > >> XSK packet per NAPI cycle, unless point 3 is fixed. It can also be
> > >
> > > XSK does not pause the whole NAPI cycle, your HW XSK RQ just stops with
> > > doing redirects to AF_XDP XSK RQ. Your regular RQ is not affected in any
> > > way. Finally point 3 needs to be fixed.
> > >
> > > FWIW we also support having a channel/queue vector carrying more than one
> > > RQ that is associated with particular NAPI instance.
> > >
> > >> reproduced if NAPI is woken up by XSK TX. Besides, (correct me if I'm wrong)
> > >> your current implementation introduces extra latency to XSK TX if XSK RX
> > >> asked to pause NAPI, because NAPI will be restarted anyway (by TX wakeup),
> > >> and it could have been rescheduled by the kernel.
> > >
> > > Again, we don't pause NAPI. Tx and Rx processing are separate.
> > >
> > > As for Intel drivers, Tx is processed first. So even if we break at Rx due
> > > to -ENOBUFS from xdp_do_redirect(), Tx work has already been done.
> > >
> > > To reiterate, we agreed on fixing point 1 and 3 from your original mail.
> > > Valid and good points.
> >
> > Great that we agreed on 1 and 3! Point 4 can be dropped. For point 2, I
> > wrote my thoughts above.
> >
> > >>
> > >>> Am I missing something? Maybe I have just misunderstood you.
> > >>>
> > >>>>
> > >>>>> One might ask why it is still relevant even after having proper busy
> > >>>>> poll support in place - here is the justification.
> > >>>>>
> > >>>>> For xdpsock that was:
> > >>>>> - run for l2fwd scenario,
> > >>>>> - app/driver processing took place on the same core in busy poll
> > >>>>>      with 2048 budget,
> > >>>>> - HW ring sizes Tx 256, Rx 2048,
> > >>>>>
> > >>>>> this work improved throughput by 78% and reduced Rx queue full statistic
> > >>>>> bump by 99%.
> > >>>>>
> > >>>>> For testing ice, make sure that you have [1] present on your side.
> > >>>>>
> > >>>>> This set, besides the work described above, also carries also
> > >>>>> improvements around return codes in various XSK paths and lastly a minor
> > >>>>> optimization for xskq_cons_has_entries(), a helper that might be used
> > >>>>> when XSK Rx batching would make it to the kernel.
> > >>>>
> > >>>> Regarding error codes, I would like them to be consistent across all
> > >>>> drivers, otherwise all the debuggability improvements are not useful enough.
> > >>>> Your series only changed Intel drivers. Here also applies the backward
> > >>>> compatibility concern: the same error codes than were in use have been
> > >>>> repurposed, which may confuse some of existing applications.
> > >>>
> > >>> I'll double check if ZC drivers are doing something unusual with return
> > >>> values from xdp_do_redirect(). Regarding backward comp, I suppose you
> > >>> refer only to changes in ndo_xsk_wakeup() callbacks as others are not
> > >>> exposed to user space? They're not crucial to me, but it improved my
> > >>> debugging experience.
> > >>
> > >> Sorry if I wasn't clear enough. Yes, I meant the wakeup error codes. We
> > >> aren't doing anything unusual with xdp_do_redirect codes (can't say for
> > >> other drivers, though).
> > >>
> > >> Last time I wanted to improve error codes returned from some BPF helpers
> > >> (make the errors more distinguishable), my patch was blocked because of
> > >> backward compatibility concerns. To be on the safe side (i.e. to avoid
> > >> further bug reports from someone who actually relied on specific codes), you
> > >> might want to use a new error code, rather than repurposing the existing
> > >> ones.
> > >>
> > >> I personally don't have objections about changing the error codes the way
> > >> you did if you keep them consistent across all drivers, not only Intel ones.
> > >
> > > Got your point. So I'll either drop the patches or look through
> > > ndo_xsk_wakeup() implementations and try to standardize the ret codes.
> > > Hope this sounds fine.
> >
> > Yes, either way sounds absolutely fine to me.
> >
> > >
> > > MF
> >