Skip to content

Commit 39f61e0

Browse files
committed
feat(rss): optimize dynamic ff_rss_check via rte_thash_adjust_tuple (IPv4)
Add per-port thash ctx (ff_rss_thash_ctx_init) and ff_rss_adjust_sport that reverse-calcs a source port landing on the local queue, with a mandatory ff_rss_check re-verification (zero tolerance for wrong queue) and soft-scan fallback. Wire it as a fast path in in_pcb_lport_dest's table-miss branch, keeping the static-table hit path and macro-off native path byte-identical. Adds 0.3 unit tests incl. an EAL-backed toeplitz/softrss equivalence hit-rate probe (full-loop 100% landing).
1 parent 22462f5 commit 39f61e0

4 files changed

Lines changed: 436 additions & 0 deletions

File tree

freebsd/netinet/in_pcb.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,8 @@ in_pcb_lport_dest(const struct inpcb *inp, struct sockaddr *lsa,
780780
int rss_ret, rss_match = 0, dorandom;
781781
struct ifaddr *ifa = NULL;
782782
struct ifnet *ifp = NULL;
783+
uint16_t rss_sel;
784+
int rss_fast;
783785

784786
lookupflags &= ~INPLOOKUP_LPORT_RSS_CHECK;
785787
#endif
@@ -879,6 +881,32 @@ in_pcb_lport_dest(const struct inpcb *inp, struct sockaddr *lsa,
879881
return (EADDRNOTAVAIL);
880882
}
881883
ifp = ifa->ifa_ifp;
884+
885+
/*
886+
* 0.3 fast path: reverse-calc a local-queue source
887+
* port instead of scanning every port. LOOPBACK has no
888+
* RSS, so skip and let the scan loop handle it. On any
889+
* miss/occupied/unavailable, fall through to the R-A
890+
* soft scan below.
891+
*/
892+
if (!(ifp->if_softc == NULL &&
893+
(ifp->if_flags & IFF_LOOPBACK)) &&
894+
lsa->sa_family == AF_INET) {
895+
for (rss_fast = 0; rss_fast < 8; rss_fast++) {
896+
if (ff_rss_adjust_sport(ifp->if_softc,
897+
faddr.s_addr, laddr.s_addr, fport,
898+
&rss_sel) != 0)
899+
break;
900+
lport = htons(rss_sel);
901+
if (in_pcblookup_local(pcbinfo, laddr,
902+
lport, RT_ALL_FIBS, lookupflags,
903+
cred) == NULL) {
904+
*lastport = rss_sel;
905+
*lportp = lport;
906+
return (0);
907+
}
908+
}
909+
}
882910
}
883911
}
884912

lib/ff_dpdk_if.c

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,17 @@ static dispatch_func_context_t packet_dispatcher_with_context;
132132

133133
static uint16_t rss_reta_size[RTE_MAX_ETHPORTS];
134134

135+
/* 0.3: per-port rte_thash ctx for dynamic sport reverse-calc.
136+
* Built once at init; -1 means disabled (fall back to soft scan). */
137+
static struct rte_thash_ctx *rss_thash_ctx[RTE_MAX_ETHPORTS];
138+
static struct rte_thash_subtuple_helper *rss_thash_sport_h[RTE_MAX_ETHPORTS];
139+
static int rss_thash_ready[RTE_MAX_ETHPORTS];
140+
/* IPv4 tuple: saddr(4)|daddr(4)|sport(2)|dport(2); sport at byte 8 = bit 64. */
141+
#define FF_RSS_THASH_V4_TUPLE_LEN 12
142+
#define FF_RSS_THASH_V4_SPORT_OFF 64
143+
#define FF_RSS_THASH_SPORT_HELPER_LEN 16
144+
#define FF_RSS_THASH_ADJUST_ATTEMPTS 16
145+
135146
#define BOND_DRIVER_NAME "net_bonding"
136147

137148
static inline int send_single_packet(struct rte_mbuf *m, uint8_t port);
@@ -1433,6 +1444,7 @@ ff_dpdk_init(int argc, char **argv)
14331444
} else {
14341445
ff_log(FF_LOG_INFO, FF_LOGTYPE_FSTACK_LIB, "ff_rss_tbl_init successed\n");
14351446
}
1447+
ff_rss_thash_ctx_init();
14361448
}
14371449

14381450
init_clock();
@@ -2885,6 +2897,145 @@ ff_rss_check(void *softc, uint32_t saddr, uint32_t daddr,
28852897
return ((hash & (reta_size - 1)) % nb_queues) == queueid;
28862898
}
28872899

2900+
static int
2901+
ff_rss_reta_log2(uint16_t reta_size)
2902+
{
2903+
int log2 = 0;
2904+
2905+
while ((reta_size >>= 1) != 0)
2906+
log2++;
2907+
2908+
return log2;
2909+
}
2910+
2911+
/*
2912+
* 0.3: build per-port thash ctx once at init so the dynamic path can
2913+
* reverse-calc a source port via rte_thash_adjust_tuple. Any failure marks
2914+
* the port unready and the dynamic path falls back to soft scan.
2915+
*/
2916+
int
2917+
ff_rss_thash_ctx_init(void)
2918+
{
2919+
uint16_t port_id;
2920+
2921+
if (rsskey == NULL || rsskey_len == 0)
2922+
return -1;
2923+
2924+
for (port_id = 0; port_id < RTE_MAX_ETHPORTS; port_id++) {
2925+
char name[64];
2926+
uint16_t reta_size = rss_reta_size[port_id];
2927+
uint32_t reta_log2;
2928+
struct rte_thash_ctx *ctx;
2929+
2930+
rss_thash_ready[port_id] = 0;
2931+
2932+
if (reta_size < 2)
2933+
continue;
2934+
2935+
reta_log2 = ff_rss_reta_log2(reta_size);
2936+
2937+
snprintf(name, sizeof(name), "ff_rss_thash_%u", port_id);
2938+
ctx = rte_thash_init_ctx(name, rsskey_len, reta_log2, rsskey, 0);
2939+
if (ctx == NULL) {
2940+
ff_log(FF_LOG_WARNING, FF_LOGTYPE_FSTACK_LIB,
2941+
"rte_thash_init_ctx failed for port %u, dynamic rss path falls back to soft scan\n",
2942+
port_id);
2943+
continue;
2944+
}
2945+
2946+
if (rte_thash_add_helper(ctx, "sport",
2947+
FF_RSS_THASH_SPORT_HELPER_LEN,
2948+
FF_RSS_THASH_V4_SPORT_OFF) != 0) {
2949+
ff_log(FF_LOG_WARNING, FF_LOGTYPE_FSTACK_LIB,
2950+
"rte_thash_add_helper failed for port %u\n", port_id);
2951+
rte_thash_free_ctx(ctx);
2952+
continue;
2953+
}
2954+
2955+
rss_thash_sport_h[port_id] = rte_thash_get_helper(ctx, "sport");
2956+
if (rss_thash_sport_h[port_id] == NULL) {
2957+
rte_thash_free_ctx(ctx);
2958+
continue;
2959+
}
2960+
2961+
rss_thash_ctx[port_id] = ctx;
2962+
rss_thash_ready[port_id] = 1;
2963+
}
2964+
2965+
return 0;
2966+
}
2967+
2968+
/*
2969+
* 0.3: reverse-calc a host-order source port whose RSS hash lands on the
2970+
* caller's local queue. tuple layout mirrors ff_rss_check's hash input
2971+
* (saddr|daddr|sport|dport, host byte order). The result is always re-verified
2972+
* by ff_rss_check (zero tolerance for wrong queue); on any failure returns <0
2973+
* and the caller must fall back to the soft per-port scan.
2974+
*/
2975+
int
2976+
ff_rss_adjust_sport(void *softc, uint32_t saddr, uint32_t daddr,
2977+
uint16_t dport, uint16_t *out_sport)
2978+
{
2979+
struct lcore_conf *qconf = &lcore_conf;
2980+
struct ff_dpdk_if_context *ctx = ff_veth_softc_to_hostc(softc);
2981+
uint16_t port_id, nb_queues, reta_size, queueid;
2982+
uint32_t desired;
2983+
uint8_t tuple[FF_RSS_THASH_V4_TUPLE_LEN];
2984+
uint16_t sport;
2985+
int tries;
2986+
2987+
if (softc == NULL || out_sport == NULL)
2988+
return -1;
2989+
2990+
port_id = ctx->port_id;
2991+
if (!rss_thash_ready[port_id] || rss_thash_ctx[port_id] == NULL)
2992+
return -1;
2993+
2994+
nb_queues = qconf->nb_queue_list[port_id];
2995+
if (nb_queues <= 1)
2996+
return -1;
2997+
2998+
reta_size = rss_reta_size[port_id];
2999+
queueid = qconf->tx_queue_id[port_id];
3000+
3001+
/*
3002+
* desired_value picked from D(q) = { v in [0, reta_size) | v % Q == q }
3003+
* so (hash & (reta_size-1)) % nb_queues == queueid holds. Rotate the
3004+
* starting candidate to spread reta entries.
3005+
*/
3006+
desired = queueid + (arc4random() % ((reta_size + nb_queues - 1) / nb_queues)) * nb_queues;
3007+
if (desired >= reta_size)
3008+
desired = queueid;
3009+
3010+
sport = 0;
3011+
for (tries = 0; tries < (int)((reta_size + nb_queues - 1) / nb_queues); tries++) {
3012+
if (desired >= reta_size)
3013+
desired = queueid;
3014+
3015+
memset(tuple, 0, sizeof(tuple));
3016+
bcopy(&saddr, &tuple[0], sizeof(saddr));
3017+
bcopy(&daddr, &tuple[4], sizeof(daddr));
3018+
bcopy(&sport, &tuple[8], sizeof(sport));
3019+
bcopy(&dport, &tuple[10], sizeof(dport));
3020+
3021+
if (rte_thash_adjust_tuple(rss_thash_ctx[port_id],
3022+
rss_thash_sport_h[port_id], tuple, sizeof(tuple),
3023+
desired & (reta_size - 1), FF_RSS_THASH_ADJUST_ATTEMPTS,
3024+
NULL, NULL) == 0) {
3025+
bcopy(&tuple[8], &sport, sizeof(sport));
3026+
/* zero tolerance: confirm with the same soft hash. */
3027+
if (ff_rss_check(softc, saddr, daddr, sport, dport)) {
3028+
*out_sport = sport;
3029+
return 0;
3030+
}
3031+
}
3032+
3033+
desired += nb_queues;
3034+
}
3035+
3036+
return -1;
3037+
}
3038+
28883039
void
28893040
ff_regist_packet_dispatcher(dispatch_func_t func)
28903041
{

lib/ff_host_interface.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ int ff_rss_tbl_set_portrange(uint16_t first, uint16_t last);
8989
int ff_rss_tbl_get_portrange(uint32_t saddr, uint32_t daddr, uint16_t sport,
9090
uint16_t *rss_first, uint16_t *rss_last, uint16_t **rss_portrange);
9191

92+
int ff_rss_thash_ctx_init(void);
93+
int ff_rss_adjust_sport(void *softc, uint32_t saddr, uint32_t daddr,
94+
uint16_t dport, uint16_t *out_sport);
95+
9296
void ff_swi_net_excute(void);
9397

9498
#ifdef FF_KERNEL_COEXIST

0 commit comments

Comments
 (0)