Skip to content

Commit 8dcdc95

Browse files
author
Jakub Kicinski
committed
Merge branch 'sfc-ARFS-expiry-improvements'
Edward Cree says: ==================== A series of changes to how we check filters for expiry, manage how much of that work to do & when, etc. Prompted by some pathological behaviour under heavy load, which was Reported-by: David Ahern <[email protected]> ==================== Signed-off-by: Jakub Kicinski <[email protected]>
2 parents c4f2cbd + 6fbc05e commit 8dcdc95

File tree

6 files changed

+94
-41
lines changed

6 files changed

+94
-41
lines changed

drivers/net/ethernet/sfc/ef10.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4202,11 +4202,15 @@ static int efx_ef10_filter_push(struct efx_nic *efx,
42024202
{
42034203
MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN);
42044204
MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_EXT_OUT_LEN);
4205+
size_t outlen;
42054206
int rc;
42064207

42074208
efx_ef10_filter_push_prep(efx, spec, inbuf, *handle, ctx, replacing);
4208-
rc = efx_mcdi_rpc(efx, MC_CMD_FILTER_OP, inbuf, sizeof(inbuf),
4209-
outbuf, sizeof(outbuf), NULL);
4209+
rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FILTER_OP, inbuf, sizeof(inbuf),
4210+
outbuf, sizeof(outbuf), &outlen);
4211+
if (rc && spec->priority != EFX_FILTER_PRI_HINT)
4212+
efx_mcdi_display_error(efx, MC_CMD_FILTER_OP, sizeof(inbuf),
4213+
outbuf, outlen, rc);
42104214
if (rc == 0)
42114215
*handle = MCDI_QWORD(outbuf, FILTER_OP_OUT_HANDLE);
42124216
if (rc == -ENOSPC)

drivers/net/ethernet/sfc/efx.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ static int efx_poll(struct napi_struct *napi, int budget)
355355

356356
#ifdef CONFIG_RFS_ACCEL
357357
/* Perhaps expire some ARFS filters */
358-
schedule_work(&channel->filter_work);
358+
mod_delayed_work(system_wq, &channel->filter_work, 0);
359359
#endif
360360

361361
/* There is no race here; although napi_disable() will
@@ -487,7 +487,7 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
487487
}
488488

489489
#ifdef CONFIG_RFS_ACCEL
490-
INIT_WORK(&channel->filter_work, efx_filter_rfs_expire);
490+
INIT_DELAYED_WORK(&channel->filter_work, efx_filter_rfs_expire);
491491
#endif
492492

493493
rx_queue = &channel->rx_queue;
@@ -533,7 +533,7 @@ efx_copy_channel(const struct efx_channel *old_channel)
533533
memset(&rx_queue->rxd, 0, sizeof(rx_queue->rxd));
534534
timer_setup(&rx_queue->slow_fill, efx_rx_slow_fill, 0);
535535
#ifdef CONFIG_RFS_ACCEL
536-
INIT_WORK(&channel->filter_work, efx_filter_rfs_expire);
536+
INIT_DELAYED_WORK(&channel->filter_work, efx_filter_rfs_expire);
537537
#endif
538538

539539
return channel;
@@ -1969,6 +1969,8 @@ static int efx_probe_filters(struct efx_nic *efx)
19691969
++i)
19701970
channel->rps_flow_id[i] =
19711971
RPS_FLOW_ID_INVALID;
1972+
channel->rfs_expire_index = 0;
1973+
channel->rfs_filter_count = 0;
19721974
}
19731975

19741976
if (!success) {
@@ -1978,8 +1980,6 @@ static int efx_probe_filters(struct efx_nic *efx)
19781980
rc = -ENOMEM;
19791981
goto out_unlock;
19801982
}
1981-
1982-
efx->rps_expire_index = efx->rps_expire_channel = 0;
19831983
}
19841984
#endif
19851985
out_unlock:
@@ -1993,8 +1993,10 @@ static void efx_remove_filters(struct efx_nic *efx)
19931993
#ifdef CONFIG_RFS_ACCEL
19941994
struct efx_channel *channel;
19951995

1996-
efx_for_each_channel(channel, efx)
1996+
efx_for_each_channel(channel, efx) {
1997+
cancel_delayed_work_sync(&channel->filter_work);
19971998
kfree(channel->rps_flow_id);
1999+
}
19982000
#endif
19992001
down_write(&efx->filter_sem);
20002002
efx->type->filter_table_remove(efx);

drivers/net/ethernet/sfc/efx.h

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -166,15 +166,20 @@ static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx,
166166
#ifdef CONFIG_RFS_ACCEL
167167
int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
168168
u16 rxq_index, u32 flow_id);
169-
bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned quota);
169+
bool __efx_filter_rfs_expire(struct efx_channel *channel, unsigned int quota);
170170
static inline void efx_filter_rfs_expire(struct work_struct *data)
171171
{
172-
struct efx_channel *channel = container_of(data, struct efx_channel,
173-
filter_work);
174-
175-
if (channel->rfs_filters_added >= 60 &&
176-
__efx_filter_rfs_expire(channel->efx, 100))
177-
channel->rfs_filters_added -= 60;
172+
struct delayed_work *dwork = to_delayed_work(data);
173+
struct efx_channel *channel;
174+
unsigned int time, quota;
175+
176+
channel = container_of(dwork, struct efx_channel, filter_work);
177+
time = jiffies - channel->rfs_last_expiry;
178+
quota = channel->rfs_filter_count * time / (30 * HZ);
179+
if (quota > 20 && __efx_filter_rfs_expire(channel, min(channel->rfs_filter_count, quota)))
180+
channel->rfs_last_expiry += time;
181+
/* Ensure we do more work eventually even if NAPI poll is not happening */
182+
schedule_delayed_work(dwork, 30 * HZ);
178183
}
179184
#define efx_filter_rfs_enabled() 1
180185
#else

drivers/net/ethernet/sfc/ethtool.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ static u64 efx_get_atomic_stat(void *field)
5656
#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field) \
5757
EFX_ETHTOOL_STAT(field, channel, n_##field, \
5858
unsigned int, efx_get_uint_stat)
59+
#define EFX_ETHTOOL_UINT_CHANNEL_STAT_NO_N(field) \
60+
EFX_ETHTOOL_STAT(field, channel, field, \
61+
unsigned int, efx_get_uint_stat)
5962

6063
#define EFX_ETHTOOL_UINT_TXQ_STAT(field) \
6164
EFX_ETHTOOL_STAT(tx_##field, tx_queue, field, \
@@ -87,6 +90,9 @@ static const struct efx_sw_stat_desc efx_sw_stat_desc[] = {
8790
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_bad_drops),
8891
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_tx),
8992
EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_xdp_redirect),
93+
EFX_ETHTOOL_UINT_CHANNEL_STAT_NO_N(rfs_filter_count),
94+
EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_succeeded),
95+
EFX_ETHTOOL_UINT_CHANNEL_STAT(rfs_failed),
9096
};
9197

9298
#define EFX_ETHTOOL_SW_STAT_COUNT ARRAY_SIZE(efx_sw_stat_desc)

drivers/net/ethernet/sfc/net_driver.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,13 @@ enum efx_sync_events_state {
439439
* @event_test_cpu: Last CPU to handle interrupt or test event for this channel
440440
* @irq_count: Number of IRQs since last adaptive moderation decision
441441
* @irq_mod_score: IRQ moderation score
442+
* @rfs_filter_count: number of accelerated RFS filters currently in place;
443+
* equals the count of @rps_flow_id slots filled
444+
* @rfs_last_expiry: value of jiffies last time some accelerated RFS filters
445+
* were checked for expiry
446+
* @rfs_expire_index: next accelerated RFS filter ID to check for expiry
447+
* @n_rfs_succeeded: number of successful accelerated RFS filter insertions
448+
* @n_rfs_failed; number of failed accelerated RFS filter insertions
442449
* @filter_work: Work item for efx_filter_rfs_expire()
443450
* @rps_flow_id: Flow IDs of filters allocated for accelerated RFS,
444451
* indexed by filter ID
@@ -489,8 +496,12 @@ struct efx_channel {
489496
unsigned int irq_count;
490497
unsigned int irq_mod_score;
491498
#ifdef CONFIG_RFS_ACCEL
492-
unsigned int rfs_filters_added;
493-
struct work_struct filter_work;
499+
unsigned int rfs_filter_count;
500+
unsigned int rfs_last_expiry;
501+
unsigned int rfs_expire_index;
502+
unsigned int n_rfs_succeeded;
503+
unsigned int n_rfs_failed;
504+
struct delayed_work filter_work;
494505
#define RPS_FLOW_ID_INVALID 0xFFFFFFFF
495506
u32 *rps_flow_id;
496507
#endif
@@ -923,9 +934,6 @@ struct efx_async_filter_insertion {
923934
* @filter_sem: Filter table rw_semaphore, protects existence of @filter_state
924935
* @filter_state: Architecture-dependent filter table state
925936
* @rps_mutex: Protects RPS state of all channels
926-
* @rps_expire_channel: Next channel to check for expiry
927-
* @rps_expire_index: Next index to check for expiry in
928-
* @rps_expire_channel's @rps_flow_id
929937
* @rps_slot_map: bitmap of in-flight entries in @rps_slot
930938
* @rps_slot: array of ARFS insertion requests for efx_filter_rfs_work()
931939
* @rps_hash_lock: Protects ARFS filter mapping state (@rps_hash_table and
@@ -1096,8 +1104,6 @@ struct efx_nic {
10961104
void *filter_state;
10971105
#ifdef CONFIG_RFS_ACCEL
10981106
struct mutex rps_mutex;
1099-
unsigned int rps_expire_channel;
1100-
unsigned int rps_expire_index;
11011107
unsigned long rps_slot_map;
11021108
struct efx_async_filter_insertion rps_slot[EFX_RPS_MAX_IN_FLIGHT];
11031109
spinlock_t rps_hash_lock;

drivers/net/ethernet/sfc/rx.c

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,7 @@ static void efx_filter_rfs_work(struct work_struct *data)
988988

989989
rc = efx->type->filter_insert(efx, &req->spec, true);
990990
if (rc >= 0)
991+
/* Discard 'priority' part of EF10+ filter ID (mcdi_filters) */
991992
rc %= efx->type->max_rx_ip_filters;
992993
if (efx->rps_hash_table) {
993994
spin_lock_bh(&efx->rps_hash_lock);
@@ -1012,8 +1013,9 @@ static void efx_filter_rfs_work(struct work_struct *data)
10121013
* later.
10131014
*/
10141015
mutex_lock(&efx->rps_mutex);
1016+
if (channel->rps_flow_id[rc] == RPS_FLOW_ID_INVALID)
1017+
channel->rfs_filter_count++;
10151018
channel->rps_flow_id[rc] = req->flow_id;
1016-
++channel->rfs_filters_added;
10171019
mutex_unlock(&efx->rps_mutex);
10181020

10191021
if (req->spec.ether_type == htons(ETH_P_IP))
@@ -1030,6 +1032,28 @@ static void efx_filter_rfs_work(struct work_struct *data)
10301032
req->spec.rem_host, ntohs(req->spec.rem_port),
10311033
req->spec.loc_host, ntohs(req->spec.loc_port),
10321034
req->rxq_index, req->flow_id, rc, arfs_id);
1035+
channel->n_rfs_succeeded++;
1036+
} else {
1037+
if (req->spec.ether_type == htons(ETH_P_IP))
1038+
netif_dbg(efx, rx_status, efx->net_dev,
1039+
"failed to steer %s %pI4:%u:%pI4:%u to queue %u [flow %u rc %d id %u]\n",
1040+
(req->spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP",
1041+
req->spec.rem_host, ntohs(req->spec.rem_port),
1042+
req->spec.loc_host, ntohs(req->spec.loc_port),
1043+
req->rxq_index, req->flow_id, rc, arfs_id);
1044+
else
1045+
netif_dbg(efx, rx_status, efx->net_dev,
1046+
"failed to steer %s [%pI6]:%u:[%pI6]:%u to queue %u [flow %u rc %d id %u]\n",
1047+
(req->spec.ip_proto == IPPROTO_TCP) ? "TCP" : "UDP",
1048+
req->spec.rem_host, ntohs(req->spec.rem_port),
1049+
req->spec.loc_host, ntohs(req->spec.loc_port),
1050+
req->rxq_index, req->flow_id, rc, arfs_id);
1051+
channel->n_rfs_failed++;
1052+
/* We're overloading the NIC's filter tables, so let's do a
1053+
* chunk of extra expiry work.
1054+
*/
1055+
__efx_filter_rfs_expire(channel, min(channel->rfs_filter_count,
1056+
100u));
10331057
}
10341058

10351059
/* Release references */
@@ -1139,38 +1163,44 @@ int efx_filter_rfs(struct net_device *net_dev, const struct sk_buff *skb,
11391163
return rc;
11401164
}
11411165

1142-
bool __efx_filter_rfs_expire(struct efx_nic *efx, unsigned int quota)
1166+
bool __efx_filter_rfs_expire(struct efx_channel *channel, unsigned int quota)
11431167
{
11441168
bool (*expire_one)(struct efx_nic *efx, u32 flow_id, unsigned int index);
1145-
unsigned int channel_idx, index, size;
1169+
struct efx_nic *efx = channel->efx;
1170+
unsigned int index, size, start;
11461171
u32 flow_id;
11471172

11481173
if (!mutex_trylock(&efx->rps_mutex))
11491174
return false;
11501175
expire_one = efx->type->filter_rfs_expire_one;
1151-
channel_idx = efx->rps_expire_channel;
1152-
index = efx->rps_expire_index;
1176+
index = channel->rfs_expire_index;
1177+
start = index;
11531178
size = efx->type->max_rx_ip_filters;
1154-
while (quota--) {
1155-
struct efx_channel *channel = efx_get_channel(efx, channel_idx);
1179+
while (quota) {
11561180
flow_id = channel->rps_flow_id[index];
11571181

1158-
if (flow_id != RPS_FLOW_ID_INVALID &&
1159-
expire_one(efx, flow_id, index)) {
1160-
netif_info(efx, rx_status, efx->net_dev,
1161-
"expired filter %d [queue %u flow %u]\n",
1162-
index, channel_idx, flow_id);
1163-
channel->rps_flow_id[index] = RPS_FLOW_ID_INVALID;
1182+
if (flow_id != RPS_FLOW_ID_INVALID) {
1183+
quota--;
1184+
if (expire_one(efx, flow_id, index)) {
1185+
netif_info(efx, rx_status, efx->net_dev,
1186+
"expired filter %d [channel %u flow %u]\n",
1187+
index, channel->channel, flow_id);
1188+
channel->rps_flow_id[index] = RPS_FLOW_ID_INVALID;
1189+
channel->rfs_filter_count--;
1190+
}
11641191
}
1165-
if (++index == size) {
1166-
if (++channel_idx == efx->n_channels)
1167-
channel_idx = 0;
1192+
if (++index == size)
11681193
index = 0;
1169-
}
1194+
/* If we were called with a quota that exceeds the total number
1195+
* of filters in the table (which shouldn't happen, but could
1196+
* if two callers race), ensure that we don't loop forever -
1197+
* stop when we've examined every row of the table.
1198+
*/
1199+
if (index == start)
1200+
break;
11701201
}
1171-
efx->rps_expire_channel = channel_idx;
1172-
efx->rps_expire_index = index;
11731202

1203+
channel->rfs_expire_index = index;
11741204
mutex_unlock(&efx->rps_mutex);
11751205
return true;
11761206
}

0 commit comments

Comments
 (0)