Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions e2e_test/phases/phase16_rcu_concurrency.sh
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
#!/usr/bin/env bash
# shellcheck shell=bash
# ---------------------------------------------------------------------------
# Phase 16 — RCU reader/writer concurrency under data-plane load
# Phase 16 — subscriber-count churn under data-plane load
#
# Exercises the per-lcore persistent-online RCU getter fast path: a high-rate
# iperf3 flow keeps the data-plane lcores hammering PPPD_GET_CCB / DHCP / stats
# getters (RCU readers on the fast path, reporting quiescent once per burst),
# while SetSubscriberCount is fired repeatedly — each call makes fastrg realloc
# the ppp_ccb / dhcp_ccb / per_subscriber_stats arrays and run
# rte_rcu_qsbr_synchronize (the RCU writer).
#
# If fast-path readers stopped reporting quiescent, synchronize would block and
# SetSubscriberCount would hang; if a reader saw a freed array the node would
# crash. Both steps passing under sustained load confirms reader/writer
# concurrency is correct.
# A high-rate iperf3 flow keeps the data-plane lcores busy while
# SetSubscriberCount is fired repeatedly; each change enables or disables
# preallocated subscriber slots on the control thread. The node must not hang
# or crash, and the data plane must keep forwarding afterwards.
# ---------------------------------------------------------------------------
# Helper: restore the subscriber count churned by the Step 67 loop below +
# stop the iperf3 server. Idempotent (set_subscriber_count/pkill both tolerate
Expand Down
16 changes: 6 additions & 10 deletions src/dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,6 @@ static struct rte_eth_conf port_conf_default = {
.intr_conf = {
.lsc = 1, /**< link status interrupt feature enabled */ },
};
/* Per-lcore persistent-online flag for the RCU getter fast path (see fastrg.h). */
BOOL fastrg_rcu_persistent[RTE_MAX_LCORE];

static int lsi_event_callback(U16 port_id, enum rte_eth_event_type type, void *param);

Expand Down Expand Up @@ -2227,11 +2225,10 @@ void wan_ctrl_tx(FastRG_t *fastrg_ccb, U16 ccb_id, U8 *mu, U16 mulen)
pkt->pkt_len = mulen;
count_tx_packet(fastrg_ccb, pkt, WAN_PORT, ccb_id);
unsigned int lcore_id = rte_lcore_id();
/* Control TX callers must run on an EAL lcore. Persistent data-plane
* lcores are already pdump_rcu-online. Callback removal does not wait, so
* this window covers ctrl_thread's queue-0 TX burst in teardown's
/* Control TX callers must run on an EAL lcore. Callback removal does not
* wait, so this window covers ctrl_thread's queue-0 TX burst in teardown's
* synchronize-before-free grace period. */
BOOL rcu_toggle = (lcore_id != LCORE_ID_ANY) && !fastrg_rcu_persistent[lcore_id];
BOOL rcu_toggle = (lcore_id != LCORE_ID_ANY);
if (rcu_toggle)
rte_rcu_qsbr_thread_online(fastrg_ccb->pdump_rcu, lcore_id);
U16 cp_tx_q = fastrg_ccb->dp_ctrl_txq_cp[WAN_PORT];
Expand Down Expand Up @@ -2271,11 +2268,10 @@ void lan_ctrl_tx(FastRG_t *fastrg_ccb, U16 ccb_id, U8 *mu, U16 mulen)
pkt->pkt_len = mulen;
count_tx_packet(fastrg_ccb, pkt, LAN_PORT, ccb_id);
unsigned int lcore_id = rte_lcore_id();
/* Control TX callers must run on an EAL lcore. Persistent data-plane
* lcores are already pdump_rcu-online. Callback removal does not wait, so
* this window covers ctrl_thread's queue-0 TX burst in teardown's
/* Control TX callers must run on an EAL lcore. Callback removal does not
* wait, so this window covers ctrl_thread's queue-0 TX burst in teardown's
* synchronize-before-free grace period. */
BOOL rcu_toggle = (lcore_id != LCORE_ID_ANY) && !fastrg_rcu_persistent[lcore_id];
BOOL rcu_toggle = (lcore_id != LCORE_ID_ANY);
if (rcu_toggle)
rte_rcu_qsbr_thread_online(fastrg_ccb->pdump_rcu, lcore_id);
U16 cp_tx_q = fastrg_ccb->dp_ctrl_txq_cp[LAN_PORT];
Expand Down
6 changes: 2 additions & 4 deletions src/dp.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,6 @@ static inline void fastrg_rcu_dp_online(FastRG_t *fastrg_ccb)
static inline void fastrg_rcu_dp_register(FastRG_t *fastrg_ccb)
{
fastrg_rcu_dp_online(fastrg_ccb);
fastrg_rcu_persistent[rte_lcore_id()] = TRUE; /* online first, then flip flag */
}

/**
Expand All @@ -557,8 +556,8 @@ static inline void fastrg_rcu_dp_quiescent(FastRG_t *fastrg_ccb)
/**
* @fn fastrg_rcu_dp_unregister
*
* @brief Report QSBR-offline on both RCUs for the calling data-plane lcore
* and clear its persistent flag. MUST be called once when the thread
* @brief Report QSBR-offline on both RCUs for the calling data-plane lcore.
* MUST be called once when the thread
* leaves its poll loop (on stop_flag), before returning. Without this
* the thread exits while still recorded online, and the cleanup-path
* rte_rcu_qsbr_synchronize() waits on it forever (it never reports
Expand All @@ -570,7 +569,6 @@ static inline void fastrg_rcu_dp_quiescent(FastRG_t *fastrg_ccb)
*/
static inline void fastrg_rcu_dp_unregister(FastRG_t *fastrg_ccb)
{
fastrg_rcu_persistent[rte_lcore_id()] = FALSE; /* flag first, then go offline */
fastrg_rcu_dp_offline(fastrg_ccb);
}

Expand Down
7 changes: 0 additions & 7 deletions src/fastrg.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,6 @@ enum {
extern rte_atomic16_t stop_flag;
extern rte_atomic16_t start_flag;

/* Set TRUE per data-plane lcore at thread startup (fastrg_rcu_dp_register).
* When set, the RCU ccb/stats getters take a lean load-only fast path: the lcore
* stays QSBR-online for its whole life and reports quiescent once per burst,
* instead of entering/exiting a critical section on every getter call.
* Control-plane / metrics threads leave it FALSE and use the full path. */
extern BOOL fastrg_rcu_persistent[RTE_MAX_LCORE];

#define NIC_MODEL_MAX_LEN 128

struct nic_info {
Expand Down
2 changes: 0 additions & 2 deletions unit_test/dnsd/dnsd_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,6 @@ static void dns_tcp_env_init(FastRG_t *fastrg_ccb)
}
memset(fastrg_ccb->per_subscriber_stats, 0,
sizeof(fastrg_ccb->per_subscriber_stats));
fastrg_rcu_persistent[rte_lcore_id()] = TRUE;
}

static void dns_tcp_ctx_init(dns_tcp_ctx_t *c, FastRG_t *fastrg_ccb)
Expand Down Expand Up @@ -765,7 +764,6 @@ static void dns_udp_env_init(FastRG_t *fastrg_ccb)
memset(fastrg_ccb->per_subscriber_stats, 0,
sizeof(fastrg_ccb->per_subscriber_stats));
fastrg_ccb->per_subscriber_stats[rte_lcore_id()][WAN_PORT] = &dns_udp_wan_stats;
fastrg_rcu_persistent[rte_lcore_id()] = TRUE;
}

static void dns_udp_packet_init(dns_udp_ctx_t *c, FastRG_t *fastrg_ccb)
Expand Down
4 changes: 0 additions & 4 deletions unit_test/dp_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ static void test_send2cp(FastRG_t *fastrg_ccb)
tFastRG_MBX *received = NULL;
void *object = NULL;
unsigned int lcore_id = rte_lcore_id();
BOOL old_persistent;
struct per_ccb_stats *old_lan_stats;
struct per_ccb_stats *old_wan_stats;
unsigned int available_before;
Expand All @@ -218,10 +217,8 @@ static void test_send2cp(FastRG_t *fastrg_ccb)
printf("\nTesting send2cp function:\n");

TEST_ASSERT(lcore_id != LCORE_ID_ANY, "send2cp runs on an EAL lcore", "unit test should run on EAL lcore 0");
old_persistent = fastrg_rcu_persistent[lcore_id];
old_lan_stats = fastrg_ccb->per_subscriber_stats[lcore_id][LAN_PORT];
old_wan_stats = fastrg_ccb->per_subscriber_stats[lcore_id][WAN_PORT];
fastrg_rcu_persistent[lcore_id] = TRUE;
fastrg_ccb->per_subscriber_stats[lcore_id][LAN_PORT] = NULL;
fastrg_ccb->per_subscriber_stats[lcore_id][WAN_PORT] = NULL;

Expand Down Expand Up @@ -282,7 +279,6 @@ static void test_send2cp(FastRG_t *fastrg_ccb)
fastrg_ccb->free_mail_ring = old_free_mail_ring;
fastrg_ccb->per_subscriber_stats[lcore_id][LAN_PORT] = old_lan_stats;
fastrg_ccb->per_subscriber_stats[lcore_id][WAN_PORT] = old_wan_stats;
fastrg_rcu_persistent[lcore_id] = old_persistent;
}

/* Two lcores writing one TX queue corrupt its ring, so the layout must never
Expand Down
4 changes: 1 addition & 3 deletions unit_test/pppd/codec_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -1443,12 +1443,10 @@ static void decode_env_init(FastRG_t *fastrg_ccb)
}

/* The mock FastRG_t is malloc'd, so the per-lcore stats grid is garbage —
* wipe it and install one WAN row. The persistent-RCU flag makes the
* stats getter skip the (unset) stats qsbr on this lcore. */
* wipe it and install one WAN row. */
memset(fastrg_ccb->per_subscriber_stats, 0,
sizeof(fastrg_ccb->per_subscriber_stats));
fastrg_ccb->per_subscriber_stats[rte_lcore_id()][WAN_PORT] = &decode_wan_stats;
fastrg_rcu_persistent[rte_lcore_id()] = TRUE;
}

static void decode_ccb_reset(FastRG_t *fastrg_ccb, U8 phase)
Expand Down
1 change: 0 additions & 1 deletion unit_test/pppd/pppd_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ static void pppd_env_init(FastRG_t *fastrg_ccb)
}
memset(fastrg_ccb->per_subscriber_stats, 0,
sizeof(fastrg_ccb->per_subscriber_stats));
fastrg_rcu_persistent[rte_lcore_id()] = TRUE;
rte_timer_subsystem_init();
fastrg_ccb->lcore.ctrl_thread = rte_lcore_id();

Expand Down
13 changes: 13 additions & 0 deletions unit_test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ void free_ccb(FastRG_t *ccb)
}
if (ccb->ppp_ccb) fastrg_mfree(ccb->ppp_ccb);
if (ccb->dhcp_ccb) fastrg_mfree(ccb->dhcp_ccb);
if (ccb->pdump_rcu) fastrg_mfree(ccb->pdump_rcu);
fastrg_mfree(ccb);
}

Expand Down Expand Up @@ -57,6 +58,18 @@ FastRG_t *init_ccb(int user_count)
rte_rcu_qsbr_thread_register(ppp_rcu, 0);
ccb->ppp_ccb_rcu = ppp_rcu;

/* ---- pdump_rcu ---------------------------------------------------- */
ccb->pdump_rcu = fastrg_calloc(struct rte_rcu_qsbr, 1, rcu_sz, RTE_CACHE_LINE_SIZE);
if (ccb->pdump_rcu == NULL)
goto err;
if (rte_rcu_qsbr_init(ccb->pdump_rcu, RTE_MAX_LCORE) != 0)
goto err;
unsigned int lcore_id;
RTE_LCORE_FOREACH(lcore_id) {
if (rte_rcu_qsbr_thread_register(ccb->pdump_rcu, lcore_id) != 0)
goto err;
}

/* ---- ppp_ccb pointer array + individual CCBs --------------------- */
ccb->ppp_ccb = fastrg_calloc(ppp_ccb_t *, user_count, sizeof(ppp_ccb_t *), 0);
if (ccb->ppp_ccb == NULL) goto err;
Expand Down
Loading