Skip to content

Commit 8745ecb

Browse files
committed
infra: add API and CLI command to obtain iface stats
Display interface statistics (rx_packets, rx_bytes, tx_packets and tx_bytes) per interface using 'show interface stats' grcli command. Sample output: grout# show interface <return> Validate command. type Show interface details. stats Show interface statistics. name Show interface details. grout# show interface stats INTERFACE RX_PACKETS RX_BYTES TX_PACKETS TX_BYTES p0 7 2757 2 100 gr-loop0 0 0 0 0 Signed-off-by: Spoorthi K <spk@redhat.com>
1 parent 1082673 commit 8745ecb

3 files changed

Lines changed: 134 additions & 3 deletions

File tree

modules/infra/api/gr_infra.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,23 @@ struct gr_infra_iface_set_req {
193193
uint64_t set_attrs;
194194
};
195195

196+
#define GR_INFRA_IFACE_STATS_GET REQUEST_TYPE(GR_INFRA_MODULE, 0x0006)
197+
198+
struct gr_infra_iface_stats_get_req { };
199+
200+
struct gr_iface_stats {
201+
char name[GR_IFACE_NAME_SIZE];
202+
uint64_t rx_packets;
203+
uint64_t rx_bytes;
204+
uint64_t tx_packets;
205+
uint64_t tx_bytes;
206+
};
207+
208+
struct gr_infra_iface_stats_get_resp {
209+
uint16_t n_stats;
210+
struct gr_iface_stats stats[/* n_stats */];
211+
};
212+
196213
// struct gr_infra_iface_set_resp { };
197214

198215
// port rxqs ///////////////////////////////////////////////////////////////////

modules/infra/api/stats.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,54 @@ static struct api_out stats_reset(const void * /*request*/, void ** /*response*/
211211
return api_out(0, 0);
212212
}
213213

214+
static struct api_out iface_stats_get(const void * /*request*/, void **response) {
215+
struct gr_infra_iface_stats_get_resp *resp = NULL;
216+
struct gr_iface_stats *stats_vec = NULL;
217+
struct iface *iface = NULL;
218+
int ret = 0;
219+
220+
while ((iface = iface_next(GR_IFACE_TYPE_UNDEF, iface)) != NULL) {
221+
struct iface_stats *sw_stats = iface_get_stats(iface->id);
222+
if (sw_stats == NULL)
223+
continue;
224+
225+
// Create a single stats object per interface
226+
struct gr_iface_stats s;
227+
memccpy(s.name, iface->name, 0, sizeof(s.name));
228+
s.rx_packets = 0;
229+
s.rx_bytes = 0;
230+
s.tx_packets = 0;
231+
s.tx_bytes = 0;
232+
233+
// Aggregate per-core stats
234+
for (int i = 0; i < RTE_MAX_LCORE; i++) {
235+
s.rx_packets += sw_stats->rx_packets[i];
236+
s.rx_bytes += sw_stats->rx_bytes[i];
237+
s.tx_packets += sw_stats->tx_packets[i];
238+
s.tx_bytes += sw_stats->tx_bytes[i];
239+
}
240+
gr_vec_add(stats_vec, s);
241+
}
242+
243+
size_t n_stats = gr_vec_len(stats_vec);
244+
size_t len = sizeof(*resp) + n_stats * sizeof(struct gr_iface_stats);
245+
if ((resp = calloc(1, len)) == NULL) {
246+
ret = -ENOMEM;
247+
goto err;
248+
}
249+
250+
resp->n_stats = n_stats;
251+
memcpy(resp->stats, stats_vec, n_stats * sizeof(struct gr_iface_stats));
252+
253+
gr_vec_free(stats_vec);
254+
*response = resp;
255+
return api_out(0, len);
256+
err:
257+
gr_vec_free(stats_vec);
258+
free(resp);
259+
return api_out(-ret, 0);
260+
}
261+
214262
static int
215263
telemetry_sw_stats_get(const char * /*cmd*/, const char * /*params*/, struct rte_tel_data *d) {
216264
struct stat *stats = NULL, *s;
@@ -415,9 +463,16 @@ static struct gr_api_handler stats_reset_handler = {
415463
.callback = stats_reset,
416464
};
417465

466+
static struct gr_api_handler iface_stats_get_handler = {
467+
.name = "iface stats get",
468+
.request_type = GR_INFRA_IFACE_STATS_GET,
469+
.callback = iface_stats_get,
470+
};
471+
418472
RTE_INIT(infra_stats_init) {
419473
gr_register_api_handler(&stats_get_handler);
420474
gr_register_api_handler(&stats_reset_handler);
475+
gr_register_api_handler(&iface_stats_get_handler);
421476
rte_telemetry_register_cmd(
422477
"/grout/stats/graph",
423478
telemetry_sw_stats_get,

modules/infra/cli/iface.c

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,12 +327,70 @@ static cmd_status_t iface_list(const struct gr_api_client *c, const struct ec_pn
327327
return CMD_ERROR;
328328
}
329329

330+
static cmd_status_t iface_stats(const struct gr_api_client *c, const struct ec_pnode * /*p*/) {
331+
struct gr_infra_iface_stats_get_resp *resp = NULL;
332+
struct gr_infra_iface_stats_get_req req;
333+
struct libscols_table *table = NULL;
334+
cmd_status_t status = CMD_ERROR;
335+
void *resp_ptr = NULL;
336+
int ret;
337+
338+
// Send the new API request and wait for the response
339+
ret = gr_api_client_send_recv(c, GR_INFRA_IFACE_STATS_GET, sizeof(req), &req, &resp_ptr);
340+
if (ret < 0) {
341+
errorf("failed to get interface stats: %s", strerror(-ret));
342+
goto end;
343+
}
344+
345+
resp = resp_ptr;
346+
347+
table = scols_new_table();
348+
if (table == NULL) {
349+
errorf("failed to create table: %s", strerror(errno));
350+
goto end;
351+
}
352+
353+
scols_table_new_column(table, "INTERFACE", 0, 0);
354+
scols_table_new_column(table, "RX_PACKETS", SCOLS_FL_RIGHT, 0);
355+
scols_table_new_column(table, "RX_BYTES", SCOLS_FL_RIGHT, 0);
356+
scols_table_new_column(table, "TX_PACKETS", SCOLS_FL_RIGHT, 0);
357+
scols_table_new_column(table, "TX_BYTES", SCOLS_FL_RIGHT, 0);
358+
scols_table_set_column_separator(table, " ");
359+
360+
for (uint16_t i = 0; i < resp->n_stats; i++) {
361+
struct libscols_line *line = scols_table_new_line(table, NULL);
362+
if (line == NULL) {
363+
errorf("failed to create line: %s", strerror(errno));
364+
goto end;
365+
}
366+
scols_line_set_data(line, 0, resp->stats[i].name);
367+
scols_line_sprintf(line, 1, "%lu", resp->stats[i].rx_packets);
368+
scols_line_sprintf(line, 2, "%lu", resp->stats[i].rx_bytes);
369+
scols_line_sprintf(line, 3, "%lu", resp->stats[i].tx_packets);
370+
scols_line_sprintf(line, 4, "%lu", resp->stats[i].tx_bytes);
371+
}
372+
373+
scols_print_table(table);
374+
status = CMD_SUCCESS;
375+
376+
end:
377+
if (table)
378+
scols_unref_table(table);
379+
free(resp_ptr);
380+
return status;
381+
}
382+
330383
static cmd_status_t iface_show(const struct gr_api_client *c, const struct ec_pnode *p) {
331384
const struct cli_iface_type *type;
332385
struct gr_iface iface;
333386

334-
if (arg_str(p, "NAME") == NULL || arg_str(p, "TYPE") != NULL)
387+
if (arg_str(p, "stats") != NULL) {
388+
return iface_stats(c, p);
389+
}
390+
391+
if (arg_str(p, "NAME") == NULL || arg_str(p, "TYPE") != NULL) {
335392
return iface_list(c, p);
393+
}
336394

337395
if (iface_from_name(c, arg_str(p, "NAME"), &iface) < 0)
338396
return CMD_ERROR;
@@ -385,7 +443,7 @@ static int ctx_init(struct ec_node *root) {
385443
return ret;
386444
ret = CLI_COMMAND(
387445
CLI_CONTEXT(root, CTX_SHOW, CTX_ARG("interface", "Display interface details.")),
388-
"[(name NAME)|(type TYPE)]",
446+
"[(name NAME)|(type TYPE)|stats]",
389447
iface_show,
390448
"Show interface details.",
391449
with_help(
@@ -395,7 +453,8 @@ static int ctx_init(struct ec_node *root) {
395453
with_help(
396454
"Show only this type of interface.",
397455
ec_node_dyn("TYPE", complete_iface_types, NULL)
398-
)
456+
),
457+
with_help("Show interface statistics.", ec_node_str("stats", "stats"))
399458
);
400459

401460
return ret;

0 commit comments

Comments
 (0)