Skip to content

Commit 80f6391

Browse files
committed
test(rss): add rss_ct connect harness + ff_rss_self_queue_info for on-machine queue verification
rss_ct issues N connects and prints the kernel-selected source ports per process/queue; ff_rss_self_queue_info exposes proc/queueid/nb_queues/reta_size (read-only). Used to verify on real NIC that selected sports land on the owning RSS queue.
1 parent fe7d190 commit 80f6391

4 files changed

Lines changed: 251 additions & 0 deletions

File tree

example/rss_ct.c

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
* rss_ct.c - RSS connect test (self-check carrier for RSS lport selection).
3+
*
4+
* Purpose: example/ has only servers; in_pcb_lport_dest RSS lport selection
5+
* (0.1/0.3/0.2) only fires on connect(). This minimal F-Stack app issues N
6+
* connects to a given dst and prints the locally selected source ports plus
7+
* this process's RSS queue info, so the deployer can verify each process's
8+
* connect-selected sport hashes onto its own RSS queue.
9+
*
10+
* Usage:
11+
* ./rss_ct <EAL/ff args...> --dst=<ip>:<port> [--dst6=<ip6>:<port>] [--num=N]
12+
* --dst / --dst6 / --num are app args, stripped before ff_init() so they do
13+
* not collide with EAL parsing. At least one of --dst/--dst6 is required.
14+
*/
15+
16+
#include <stdio.h>
17+
#include <stdlib.h>
18+
#include <stdint.h>
19+
#include <string.h>
20+
#include <strings.h>
21+
#include <sys/types.h>
22+
#include <sys/socket.h>
23+
#include <netinet/in.h>
24+
#include <arpa/inet.h>
25+
#include <errno.h>
26+
#include <sys/ioctl.h>
27+
28+
#include "ff_config.h"
29+
#include "ff_api.h"
30+
#include "ff_log.h"
31+
32+
#define RSS_CT_DEFAULT_NUM 200
33+
#define RSS_CT_MAX_NUM 4096
34+
35+
static char rss_ct_dst4[64];
36+
static char rss_ct_dst6[128];
37+
static int rss_ct_num = RSS_CT_DEFAULT_NUM;
38+
static int rss_ct_done = 0;
39+
40+
/* Split "addr:port" at the LAST ':' (so IPv6 colons stay in addr). */
41+
static int
42+
parse_addr_port(const char *s, char *addr_out, size_t addr_sz, uint16_t *port_out)
43+
{
44+
const char *colon = strrchr(s, ':');
45+
size_t alen;
46+
47+
if (colon == NULL)
48+
return -1;
49+
alen = (size_t)(colon - s);
50+
if (alen == 0 || alen >= addr_sz)
51+
return -1;
52+
memcpy(addr_out, s, alen);
53+
addr_out[alen] = '\0';
54+
*port_out = (uint16_t)atoi(colon + 1);
55+
if (*port_out == 0)
56+
return -1;
57+
return 0;
58+
}
59+
60+
/*
61+
* Strip app args (--dst=, --dst6=, --num=) from argv so the remaining argv is
62+
* pure EAL/ff args for ff_init. Returns the trimmed argc.
63+
*/
64+
static int
65+
extract_app_args(int argc, char **argv)
66+
{
67+
int i, n = 0;
68+
69+
for (i = 0; i < argc; i++) {
70+
if (strncmp(argv[i], "--dst=", 6) == 0) {
71+
snprintf(rss_ct_dst4, sizeof(rss_ct_dst4), "%s", argv[i] + 6);
72+
} else if (strncmp(argv[i], "--dst6=", 7) == 0) {
73+
snprintf(rss_ct_dst6, sizeof(rss_ct_dst6), "%s", argv[i] + 7);
74+
} else if (strncmp(argv[i], "--num=", 6) == 0) {
75+
rss_ct_num = atoi(argv[i] + 6);
76+
if (rss_ct_num <= 0 || rss_ct_num > RSS_CT_MAX_NUM)
77+
rss_ct_num = RSS_CT_DEFAULT_NUM;
78+
} else {
79+
argv[n++] = argv[i];
80+
}
81+
}
82+
argv[n] = NULL;
83+
return n;
84+
}
85+
86+
static void
87+
run_connects4(uint16_t proc_id)
88+
{
89+
char addr[64];
90+
uint16_t dport;
91+
int i;
92+
93+
if (parse_addr_port(rss_ct_dst4, addr, sizeof(addr), &dport) != 0) {
94+
ff_log(FF_LOG_ERR, FF_LOGTYPE_FSTACK_APP,
95+
"rss_ct: bad --dst=%s\n", rss_ct_dst4);
96+
return;
97+
}
98+
99+
printf("rss_ct v4: proc=%u dst=%s:%u num=%d sports:", proc_id, addr, dport,
100+
rss_ct_num);
101+
102+
for (i = 0; i < rss_ct_num; i++) {
103+
int fd, on = 1;
104+
struct sockaddr_in sin;
105+
struct sockaddr_in local;
106+
socklen_t llen = sizeof(local);
107+
108+
fd = ff_socket(AF_INET, SOCK_STREAM, 0);
109+
if (fd < 0)
110+
continue;
111+
ff_ioctl(fd, FIONBIO, &on);
112+
113+
bzero(&sin, sizeof(sin));
114+
sin.sin_family = AF_INET;
115+
sin.sin_port = htons(dport);
116+
inet_pton(AF_INET, addr, &sin.sin_addr);
117+
118+
/* connect may return EINPROGRESS; lport is already selected by then. */
119+
ff_connect(fd, (struct linux_sockaddr *)&sin, sizeof(sin));
120+
121+
bzero(&local, sizeof(local));
122+
if (ff_getsockname(fd, (struct linux_sockaddr *)&local, &llen) == 0)
123+
printf(" %u", ntohs(local.sin_port));
124+
125+
ff_close(fd);
126+
}
127+
printf("\n");
128+
}
129+
130+
#ifdef INET6
131+
static void
132+
run_connects6(uint16_t proc_id)
133+
{
134+
char addr[128];
135+
uint16_t dport;
136+
int i;
137+
138+
if (parse_addr_port(rss_ct_dst6, addr, sizeof(addr), &dport) != 0) {
139+
ff_log(FF_LOG_ERR, FF_LOGTYPE_FSTACK_APP,
140+
"rss_ct: bad --dst6=%s\n", rss_ct_dst6);
141+
return;
142+
}
143+
144+
printf("rss_ct v6: proc=%u dst=[%s]:%u num=%d sports:", proc_id, addr,
145+
dport, rss_ct_num);
146+
147+
for (i = 0; i < rss_ct_num; i++) {
148+
int fd, on = 1;
149+
struct sockaddr_in6 sin6;
150+
struct sockaddr_in6 local6;
151+
socklen_t llen = sizeof(local6);
152+
153+
fd = ff_socket(AF_INET6, SOCK_STREAM, 0);
154+
if (fd < 0)
155+
continue;
156+
ff_ioctl(fd, FIONBIO, &on);
157+
158+
bzero(&sin6, sizeof(sin6));
159+
sin6.sin6_family = AF_INET6;
160+
sin6.sin6_port = htons(dport);
161+
inet_pton(AF_INET6, addr, &sin6.sin6_addr);
162+
163+
ff_connect(fd, (struct linux_sockaddr *)&sin6, sizeof(sin6));
164+
165+
bzero(&local6, sizeof(local6));
166+
if (ff_getsockname(fd, (struct linux_sockaddr *)&local6, &llen) == 0)
167+
printf(" %u", ntohs(local6.sin6_port));
168+
169+
ff_close(fd);
170+
}
171+
printf("\n");
172+
}
173+
#endif
174+
175+
static int
176+
loop(void *arg)
177+
{
178+
uint16_t proc_id = 0, queueid = 0, nb_queues = 0, reta_size = 0;
179+
180+
if (rss_ct_done)
181+
return 0;
182+
rss_ct_done = 1;
183+
184+
if (ff_rss_self_queue_info(&proc_id, &queueid, &nb_queues, &reta_size) != 0) {
185+
ff_log(FF_LOG_ERR, FF_LOGTYPE_FSTACK_APP,
186+
"rss_ct: ff_rss_self_queue_info failed\n");
187+
return 0;
188+
}
189+
190+
printf("rss_ct info: proc=%u queueid=%u nb_queues=%u reta_size=%u\n",
191+
proc_id, queueid, nb_queues, reta_size);
192+
193+
if (rss_ct_dst4[0] != '\0')
194+
run_connects4(proc_id);
195+
#ifdef INET6
196+
if (rss_ct_dst6[0] != '\0')
197+
run_connects6(proc_id);
198+
#endif
199+
200+
printf("rss_ct done: proc=%u (verify each sport hashes to queueid=%u)\n",
201+
proc_id, queueid);
202+
fflush(stdout);
203+
204+
return 0;
205+
}
206+
207+
int
208+
main(int argc, char *argv[])
209+
{
210+
argc = extract_app_args(argc, argv);
211+
212+
if (rss_ct_dst4[0] == '\0' && rss_ct_dst6[0] == '\0') {
213+
fprintf(stderr,
214+
"rss_ct: need --dst=<ip>:<port> and/or --dst6=<ip6>:<port>\n");
215+
return 1;
216+
}
217+
218+
ff_init(argc, argv);
219+
ff_run(loop, NULL);
220+
221+
return 0;
222+
}

lib/ff_api.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ int ff_getpeername(int s, struct linux_sockaddr *name,
121121
int ff_getsockname(int s, struct linux_sockaddr *name,
122122
socklen_t *namelen);
123123

124+
/* Read-only: this process's RSS queue info (for self-check tools). */
125+
int ff_rss_self_queue_info(uint16_t *proc_id, uint16_t *queueid,
126+
uint16_t *nb_queues, uint16_t *reta_size);
127+
124128
ssize_t ff_read(int d, void *buf, size_t nbytes);
125129
ssize_t ff_readv(int fd, const struct iovec *iov, int iovcnt);
126130

lib/ff_api.symlist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ ff_bind
2828
ff_connect
2929
ff_getpeername
3030
ff_getsockname
31+
ff_rss_self_queue_info
3132
ff_shutdown
3233
ff_sysctl
3334
ff_kqueue

lib/ff_dpdk_if.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2891,6 +2891,30 @@ ff_rss_tbl_get_portrange(uint32_t saddr, uint32_t daddr, uint16_t sport,
28912891
return -ENOENT;
28922892
}
28932893

2894+
int
2895+
ff_rss_self_queue_info(uint16_t *proc_id, uint16_t *queueid,
2896+
uint16_t *nb_queues, uint16_t *reta_size)
2897+
{
2898+
struct lcore_conf *qconf = &lcore_conf;
2899+
uint16_t port_id;
2900+
2901+
if (qconf->nb_tx_port == 0)
2902+
return -1;
2903+
2904+
port_id = qconf->tx_port_id[0];
2905+
2906+
if (proc_id)
2907+
*proc_id = (uint16_t)qconf->proc_id;
2908+
if (queueid)
2909+
*queueid = qconf->tx_queue_id[port_id];
2910+
if (nb_queues)
2911+
*nb_queues = qconf->nb_queue_list[port_id];
2912+
if (reta_size)
2913+
*reta_size = rss_reta_size[port_id];
2914+
2915+
return 0;
2916+
}
2917+
28942918
int
28952919
ff_rss_check(void *softc, uint32_t saddr, uint32_t daddr,
28962920
uint16_t sport, uint16_t dport)

0 commit comments

Comments
 (0)