From 9eb521a185be8b9130db3d7f69e8e3f816c8757e Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Sun, 1 Feb 2026 18:22:38 +0100 Subject: [PATCH 1/6] treewide: use UINT_NUM_VALUES for edge registration arrays Replace hardcoded array sizes and *_COUNT enum values with UINT_NUM_VALUES() macro for all edge registration arrays. This makes the array sizing explicit based on the index type and eliminates tautological comparison warnings. Update registration functions to use name-based validation instead of bounds checking where applicable. Use gr_iface_type_name(), gr_iface_mode_name(), and gr_nh_type_name() for better log messages and consistent error reporting. Signed-off-by: Robin Jarry --- docs/graph.svg | 18 +++++++++--------- modules/infra/datapath/eth_input.c | 2 +- modules/infra/datapath/iface_output.c | 11 ++++++----- modules/infra/datapath/loop_input.c | 2 +- modules/infra/datapath/port_rx.c | 8 ++++++-- modules/ip/datapath/ip_input.c | 9 +++++---- modules/ip/datapath/ip_local.c | 2 +- modules/ip/datapath/ip_output.c | 18 ++++++++++-------- modules/ip6/datapath/ip6_input.c | 9 +++++---- modules/ip6/datapath/ip6_local.c | 2 +- modules/ip6/datapath/ip6_output.c | 18 ++++++++++-------- modules/l4/l4_input_local.c | 2 +- 12 files changed, 56 insertions(+), 45 deletions(-) diff --git a/docs/graph.svg b/docs/graph.svg index 514a71ba6..9bada694d 100644 --- a/docs/graph.svg +++ b/docs/graph.svg @@ -699,7 +699,7 @@ - + icmp6_output icmp6_output @@ -746,24 +746,24 @@ - - -icmp6_output->ip6_output - - - - + icmp6_local_send icmp6_local_send - + icmp6_local_send->icmp6_output + + +icmp6_output->ip6_output + + + ndp_na_output diff --git a/modules/infra/datapath/eth_input.c b/modules/infra/datapath/eth_input.c index 7cd45adc2..971a2d9a7 100644 --- a/modules/infra/datapath/eth_input.c +++ b/modules/infra/datapath/eth_input.c @@ -22,7 +22,7 @@ enum { NB_EDGES, }; -static rte_edge_t l2l3_edges[1 << 16] = {UNKNOWN_ETHER_TYPE}; +static rte_edge_t l2l3_edges[UINT_NUM_VALUES(rte_be16_t)] = {UNKNOWN_ETHER_TYPE}; void gr_eth_input_add_type(rte_be16_t eth_type, const char *next_node) { LOG(DEBUG, "eth_input: type=0x%04x -> %s", rte_be_to_cpu_16(eth_type), next_node); diff --git a/modules/infra/datapath/iface_output.c b/modules/infra/datapath/iface_output.c index 169677644..c7ca03014 100644 --- a/modules/infra/datapath/iface_output.c +++ b/modules/infra/datapath/iface_output.c @@ -16,14 +16,15 @@ enum { NB_EDGES, }; -static rte_edge_t iface_type_edges[GR_IFACE_TYPE_COUNT] = {INVAL}; +static rte_edge_t iface_type_edges[UINT_NUM_VALUES(gr_iface_type_t)] = {INVAL}; void iface_output_type_register(gr_iface_type_t type, const char *next_node) { - LOG(DEBUG, "iface_output: iface_type=%s -> %s", gr_iface_type_name(type), next_node); - if (type == GR_IFACE_TYPE_UNDEF || type >= ARRAY_DIM(iface_type_edges)) + const char *type_name = gr_iface_type_name(type); + if (strcmp(type_name, "?") == 0) ABORT("invalid iface type=%u", type); if (iface_type_edges[type] != INVAL) - ABORT("next node already registered for iface type=%s", gr_iface_type_name(type)); + ABORT("next node already registered for iface type=%s", type_name); + LOG(DEBUG, "iface_output: iface_type=%s -> %s", type_name, next_node); iface_type_edges[type] = gr_node_attach_parent("iface_output", next_node); } @@ -42,7 +43,7 @@ static uint16_t iface_output_process( m = objs[i]; iface = mbuf_data(m)->iface; - if (iface == NULL || iface->type >= ARRAY_DIM(iface_type_edges)) { + if (iface == NULL) { edge = INVAL; goto next; } diff --git a/modules/infra/datapath/loop_input.c b/modules/infra/datapath/loop_input.c index 003b06439..5b92ac8cd 100644 --- a/modules/infra/datapath/loop_input.c +++ b/modules/infra/datapath/loop_input.c @@ -22,7 +22,7 @@ enum { EDGE_COUNT, }; -static rte_edge_t l3_edges[1 << 16] = {UNKNOWN_PROTO}; +static rte_edge_t l3_edges[UINT_NUM_VALUES(rte_be16_t)] = {UNKNOWN_PROTO}; void loopback_input_add_type(rte_be16_t eth_type, const char *next_node) { LOG(DEBUG, "loopback_input: type=0x%04x -> %s", rte_be_to_cpu_16(eth_type), next_node); diff --git a/modules/infra/datapath/port_rx.c b/modules/infra/datapath/port_rx.c index 21bd315e2..c72b2c782 100644 --- a/modules/infra/datapath/port_rx.c +++ b/modules/infra/datapath/port_rx.c @@ -28,11 +28,15 @@ int rxtx_trace_format(char *buf, size_t len, const void *data, size_t /*data_len return snprintf(buf, len, "port=%u queue=%u", t->port_id, t->queue_id); } -static rte_edge_t edges[GR_IFACE_MODE_COUNT] = {IFACE_MODE_UNKNOWN}; +static rte_edge_t edges[UINT_NUM_VALUES(gr_iface_mode_t)] = {IFACE_MODE_UNKNOWN}; void iface_input_mode_register(gr_iface_mode_t mode, const char *next_node) { + const char *mode_name = gr_iface_mode_name(mode); + if (strcmp(mode_name, "?") == 0) + ABORT("invalid iface mode=%u", mode); if (edges[mode] != IFACE_MODE_UNKNOWN) - ABORT("next node already registered for interface mode %u", mode); + ABORT("next node already registered for interface mode %s", mode_name); + LOG(DEBUG, "iface_input: mode=%s -> %s", mode_name, next_node); edges[mode] = gr_node_attach_parent(RX_NODE_BASE, next_node); } diff --git a/modules/ip/datapath/ip_input.c b/modules/ip/datapath/ip_input.c index 57bbafbc7..cce8842b7 100644 --- a/modules/ip/datapath/ip_input.c +++ b/modules/ip/datapath/ip_input.c @@ -32,14 +32,15 @@ enum edges { EDGE_COUNT, }; -static rte_edge_t nh_type_edges[256] = {FORWARD}; +static rte_edge_t nh_type_edges[UINT_NUM_VALUES(gr_nh_type_t)] = {FORWARD}; void ip_input_register_nexthop_type(gr_nh_type_t type, const char *next_node) { - LOG(DEBUG, "ip_input: nexthop type=%u -> %s", type, next_node); - if (type == 0) + const char *type_name = gr_nh_type_name(type); + if (strcmp(type_name, "?") == 0) ABORT("invalid nexthop type=%u", type); if (nh_type_edges[type] != FORWARD) - ABORT("next node already registered for nexthop type=%u", type); + ABORT("next node already registered for nexthop type=%s", type_name); + LOG(DEBUG, "ip_input: nh_type=%s -> %s", type_name, next_node); nh_type_edges[type] = gr_node_attach_parent("ip_input", next_node); } diff --git a/modules/ip/datapath/ip_local.c b/modules/ip/datapath/ip_local.c index e52a84846..4be3f1b4f 100644 --- a/modules/ip/datapath/ip_local.c +++ b/modules/ip/datapath/ip_local.c @@ -11,7 +11,7 @@ #include #define UNKNOWN_PROTO 0 -static rte_edge_t edges[256] = {UNKNOWN_PROTO}; +static rte_edge_t edges[UINT_NUM_VALUES(uint8_t)] = {UNKNOWN_PROTO}; void ip_input_local_add_proto(uint8_t proto, const char *next_node) { LOG(DEBUG, "ip_input_local: proto=%hhu -> %s", proto, next_node); diff --git a/modules/ip/datapath/ip_output.c b/modules/ip/datapath/ip_output.c index 0871eefd4..a505dd0bf 100644 --- a/modules/ip/datapath/ip_output.c +++ b/modules/ip/datapath/ip_output.c @@ -31,25 +31,27 @@ enum { EDGE_COUNT, }; -static rte_edge_t iface_type_edges[GR_IFACE_TYPE_COUNT] = {ETH_OUTPUT}; +static rte_edge_t iface_type_edges[UINT_NUM_VALUES(gr_iface_type_t)] = {ETH_OUTPUT}; void ip_output_register_interface_type(gr_iface_type_t type, const char *next_node) { - LOG(DEBUG, "ip_output: iface_type=%u -> %s", type, next_node); - if (type == GR_IFACE_TYPE_UNDEF || type >= ARRAY_DIM(iface_type_edges)) + const char *type_name = gr_iface_type_name(type); + if (strcmp(type_name, "?") == 0) ABORT("invalid iface type=%u", type); if (iface_type_edges[type] != ETH_OUTPUT) - ABORT("next node already registered for iface type=%u", type); + ABORT("next node already registered for iface type=%s", type_name); + LOG(DEBUG, "ip_output: iface_type=%s -> %s", type_name, next_node); iface_type_edges[type] = gr_node_attach_parent("ip_output", next_node); } -static rte_edge_t nh_type_edges[256] = {ETH_OUTPUT}; +static rte_edge_t nh_type_edges[UINT_NUM_VALUES(gr_nh_type_t)] = {ETH_OUTPUT}; void ip_output_register_nexthop_type(gr_nh_type_t type, const char *next_node) { - LOG(DEBUG, "ip_output: nexthop type=%u -> %s", type, next_node); - if (type == 0) + const char *type_name = gr_nh_type_name(type); + if (strcmp(type_name, "?") == 0) ABORT("invalid nexthop type=%u", type); if (nh_type_edges[type] != ETH_OUTPUT) - ABORT("next node already registered for nexthop type=%u", type); + ABORT("next node already registered for nexthop type=%s", type_name); + LOG(DEBUG, "ip_output: nh_type=%s -> %s", type_name, next_node); nh_type_edges[type] = gr_node_attach_parent("ip_output", next_node); } diff --git a/modules/ip6/datapath/ip6_input.c b/modules/ip6/datapath/ip6_input.c index e64f77385..a71318b75 100644 --- a/modules/ip6/datapath/ip6_input.c +++ b/modules/ip6/datapath/ip6_input.c @@ -30,14 +30,15 @@ enum edges { EDGE_COUNT, }; -static rte_edge_t nh_type_edges[256] = {FORWARD}; +static rte_edge_t nh_type_edges[UINT_NUM_VALUES(gr_nh_type_t)] = {FORWARD}; void ip6_input_register_nexthop_type(gr_nh_type_t type, const char *next_node) { - LOG(DEBUG, "ip6_input: nexthop type=%u -> %s", type, next_node); - if (type == 0) + const char *type_name = gr_nh_type_name(type); + if (strcmp(type_name, "?") == 0) ABORT("invalid nexthop type=%u", type); if (nh_type_edges[type] != FORWARD) - ABORT("next node already registered for nexthop type=%u", type); + ABORT("next node already registered for nexthop type=%s", type_name); + LOG(DEBUG, "ip6_input: nh_type=%s -> %s", type_name, next_node); nh_type_edges[type] = gr_node_attach_parent("ip6_input", next_node); } diff --git a/modules/ip6/datapath/ip6_local.c b/modules/ip6/datapath/ip6_local.c index fed24c59d..14aabbbe3 100644 --- a/modules/ip6/datapath/ip6_local.c +++ b/modules/ip6/datapath/ip6_local.c @@ -17,7 +17,7 @@ enum { ERROR, EDGE_COUNT, }; -static rte_edge_t edges[256] = {UNKNOWN_PROTO}; +static rte_edge_t edges[UINT_NUM_VALUES(uint8_t)] = {UNKNOWN_PROTO}; void ip6_input_local_add_proto(uint8_t proto, const char *next_node) { LOG(DEBUG, "ip6_input_local: proto=%hhu -> %s", proto, next_node); diff --git a/modules/ip6/datapath/ip6_output.c b/modules/ip6/datapath/ip6_output.c index 6f335c7f5..58cea8119 100644 --- a/modules/ip6/datapath/ip6_output.c +++ b/modules/ip6/datapath/ip6_output.c @@ -25,25 +25,27 @@ enum { EDGE_COUNT, }; -static rte_edge_t iface_type_edges[GR_IFACE_TYPE_COUNT] = {ETH_OUTPUT}; +static rte_edge_t iface_type_edges[UINT_NUM_VALUES(gr_iface_type_t)] = {ETH_OUTPUT}; void ip6_output_register_interface_type(gr_iface_type_t type, const char *next_node) { - LOG(DEBUG, "ip6_output: iface type=%u -> %s", type, next_node); - if (type == GR_IFACE_TYPE_UNDEF || type >= ARRAY_DIM(iface_type_edges)) + const char *type_name = gr_iface_type_name(type); + if (strcmp(type_name, "?") == 0) ABORT("invalid iface type=%u", type); if (iface_type_edges[type] != ETH_OUTPUT) - ABORT("next node already registered for iface type=%u", type); + ABORT("next node already registered for iface type=%s", type_name); + LOG(DEBUG, "ip6_output: iface_type=%s -> %s", type_name, next_node); iface_type_edges[type] = gr_node_attach_parent("ip6_output", next_node); } -static rte_edge_t nh_type_edges[256] = {ETH_OUTPUT}; +static rte_edge_t nh_type_edges[UINT_NUM_VALUES(gr_nh_type_t)] = {ETH_OUTPUT}; void ip6_output_register_nexthop_type(gr_nh_type_t type, const char *next_node) { - LOG(DEBUG, "ip6_output: nexthop type=%u -> %s", type, next_node); - if (type == 0) + const char *type_name = gr_nh_type_name(type); + if (strcmp(type_name, "?") == 0) ABORT("invalid nexthop type=%u", type); if (nh_type_edges[type] != ETH_OUTPUT) - ABORT("next node already registered for nexthop type=%u", type); + ABORT("next node already registered for nexthop type=%s", type_name); + LOG(DEBUG, "ip6_output: nh_type=%s -> %s", type_name, next_node); nh_type_edges[type] = gr_node_attach_parent("ip6_output", next_node); } diff --git a/modules/l4/l4_input_local.c b/modules/l4/l4_input_local.c index 0654eafc3..e8fe50a3d 100644 --- a/modules/l4/l4_input_local.c +++ b/modules/l4/l4_input_local.c @@ -20,7 +20,7 @@ enum edges { EDGE_COUNT, }; -static rte_edge_t udp_edges[65536] = {MANAGEMENT}; +static rte_edge_t udp_edges[UINT_NUM_VALUES(rte_be16_t)] = {MANAGEMENT}; void l4_input_register_port(uint8_t proto, rte_be16_t port, const char *next_node) { uint16_t p = rte_be_to_cpu_16(port); From f6f5c43e8d2fdac888ee2f689d6fd89e5811c1b1 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Mon, 2 Feb 2026 14:28:59 +0100 Subject: [PATCH 2/6] iface: remove redundant type name field The interface type name is already available via gr_iface_type_name() which derives it from the type ID. Storing it again in struct iface_type is redundant. This field is unused anyway. Remove the name field from iface_type. Signed-off-by: Robin Jarry --- modules/infra/control/bond.c | 1 - modules/infra/control/gr_iface.h | 1 - modules/infra/control/loopback.c | 1 - modules/infra/control/port.c | 1 - modules/infra/control/vlan.c | 1 - modules/ipip/control.c | 1 - 6 files changed, 6 deletions(-) diff --git a/modules/infra/control/bond.c b/modules/infra/control/bond.c index 6432c4c53..0e82e5605 100644 --- a/modules/infra/control/bond.c +++ b/modules/infra/control/bond.c @@ -417,7 +417,6 @@ static void bond_to_api(void *info, const struct iface *iface) { static struct iface_type iface_type_bond = { .id = GR_IFACE_TYPE_BOND, - .name = "bond", .pub_size = sizeof(struct gr_iface_info_bond), .priv_size = sizeof(struct iface_info_bond), .init = bond_init, diff --git a/modules/infra/control/gr_iface.h b/modules/infra/control/gr_iface.h index e7b3d7cb8..9fa354652 100644 --- a/modules/infra/control/gr_iface.h +++ b/modules/infra/control/gr_iface.h @@ -57,7 +57,6 @@ struct iface_type { int (*set_promisc)(struct iface *, bool enabled); void (*to_api)(void *api_info, const struct iface *); void (*metrics_collect)(struct gr_metrics_ctx *, const struct iface *); - const char *name; STAILQ_ENTRY(iface_type) next; }; diff --git a/modules/infra/control/loopback.c b/modules/infra/control/loopback.c index a52e523a8..593c8f9d6 100644 --- a/modules/infra/control/loopback.c +++ b/modules/infra/control/loopback.c @@ -309,7 +309,6 @@ static void iface_loopback_to_api(void * /* info */, const struct iface * /* ifa static struct iface_type iface_type_loopback = { .id = GR_IFACE_TYPE_LOOPBACK, - .name = "loopback", .pub_size = 0, .priv_size = sizeof(struct iface_info_loopback), .init = iface_loopback_init, diff --git a/modules/infra/control/port.c b/modules/infra/control/port.c index dab5acc87..157570006 100644 --- a/modules/infra/control/port.c +++ b/modules/infra/control/port.c @@ -812,7 +812,6 @@ static void port_fini(struct event_base *) { static struct iface_type iface_type_port = { .id = GR_IFACE_TYPE_PORT, - .name = "port", .pub_size = sizeof(struct gr_iface_info_port), .priv_size = sizeof(struct iface_info_port), .init = iface_port_init, diff --git a/modules/infra/control/vlan.c b/modules/infra/control/vlan.c index 0b9c9fe39..d08ce0836 100644 --- a/modules/infra/control/vlan.c +++ b/modules/infra/control/vlan.c @@ -186,7 +186,6 @@ static void vlan_to_api(void *info, const struct iface *iface) { static struct iface_type iface_type_vlan = { .id = GR_IFACE_TYPE_VLAN, - .name = "vlan", .pub_size = sizeof(struct gr_iface_info_vlan), .priv_size = sizeof(struct iface_info_vlan), .init = iface_vlan_init, diff --git a/modules/ipip/control.c b/modules/ipip/control.c index fdfbf0ea4..5e580ab93 100644 --- a/modules/ipip/control.c +++ b/modules/ipip/control.c @@ -115,7 +115,6 @@ static void ipip_to_api(void *info, const struct iface *iface) { static struct iface_type iface_type_ipip = { .id = GR_IFACE_TYPE_IPIP, - .name = "ipip", .pub_size = sizeof(struct gr_iface_info_ipip), .priv_size = sizeof(struct iface_info_ipip), .init = iface_ipip_init, From df2e50d6f20c8e902941b2a297396854a57d9c69 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Mon, 2 Feb 2026 14:34:35 +0100 Subject: [PATCH 3/6] iface: store types in a static array Replace the linked list of interface types with a static array indexed by type ID. This makes iface_type_get() an O(1) array lookup instead of O(n) linked list traversal. This benefits iface_get_eth_addr() which is called in the eth_input hot path and needs to look up the interface type to find the get_eth_addr callback. Since interface types are no longer linked, the STAILQ_ENTRY field is removed and the iface_type structs can be declared const. Substituting pointer chasing with direct array indexing reduces LLC cache misses by 9% and increases throughput from 11.6M to 11.8M pkt/s (+1.7%). Signed-off-by: Robin Jarry --- modules/infra/control/bond.c | 2 +- modules/infra/control/gr_iface.h | 3 +-- modules/infra/control/iface.c | 16 +++++++--------- modules/infra/control/loopback.c | 2 +- modules/infra/control/port.c | 2 +- modules/infra/control/port_test.c | 2 +- modules/infra/control/vlan.c | 2 +- modules/infra/control/worker_test.c | 2 +- modules/ipip/control.c | 2 +- 9 files changed, 15 insertions(+), 18 deletions(-) diff --git a/modules/infra/control/bond.c b/modules/infra/control/bond.c index 0e82e5605..2c0c913a0 100644 --- a/modules/infra/control/bond.c +++ b/modules/infra/control/bond.c @@ -415,7 +415,7 @@ static void bond_to_api(void *info, const struct iface *iface) { } } -static struct iface_type iface_type_bond = { +static const struct iface_type iface_type_bond = { .id = GR_IFACE_TYPE_BOND, .pub_size = sizeof(struct gr_iface_info_bond), .priv_size = sizeof(struct iface_info_bond), diff --git a/modules/infra/control/gr_iface.h b/modules/infra/control/gr_iface.h index 9fa354652..038a78deb 100644 --- a/modules/infra/control/gr_iface.h +++ b/modules/infra/control/gr_iface.h @@ -57,10 +57,9 @@ struct iface_type { int (*set_promisc)(struct iface *, bool enabled); void (*to_api)(void *api_info, const struct iface *); void (*metrics_collect)(struct gr_metrics_ctx *, const struct iface *); - STAILQ_ENTRY(iface_type) next; }; -void iface_type_register(struct iface_type *); +void iface_type_register(const struct iface_type *); const struct iface_type *iface_type_get(gr_iface_type_t type_id); struct iface *iface_create(const struct gr_iface *conf, const void *api_info); int iface_reconfig( diff --git a/modules/infra/control/iface.c b/modules/infra/control/iface.c index d54874fad..d81a84422 100644 --- a/modules/infra/control/iface.c +++ b/modules/infra/control/iface.c @@ -22,7 +22,7 @@ #include #include -static STAILQ_HEAD(, iface_type) types = STAILQ_HEAD_INITIALIZER(types); +static const struct iface_type *iface_types[UINT_NUM_VALUES(gr_iface_type_t)]; struct iface_stats iface_stats[MAX_IFACES][RTE_MAX_LCORE]; @@ -42,19 +42,15 @@ static bool iface_type_valid(gr_iface_type_t type) { } const struct iface_type *iface_type_get(gr_iface_type_t type_id) { - struct iface_type *t; - STAILQ_FOREACH (t, &types, next) - if (t->id == type_id) - return t; - return errno_set_null(ENODEV); + return iface_types[type_id]; } -void iface_type_register(struct iface_type *type) { +void iface_type_register(const struct iface_type *type) { if (!iface_type_valid(type->id)) ABORT("invalid iface type id: %u", type->id); if (iface_type_get(type->id) != NULL) ABORT("duplicate iface type id: %u", type->id); - STAILQ_INSERT_TAIL(&types, type, next); + iface_types[type->id] = type; } #define IFACE_ID_FIRST GR_IFACE_ID_UNDEF + 1 @@ -93,8 +89,10 @@ struct iface *iface_create(const struct gr_iface *conf, const void *api_info) { bool vrf_ref = false; uint16_t ifid; - if (type == NULL) + if (type == NULL) { + errno = ENODEV; goto fail; + } if (charset_check(conf->name, GR_IFACE_NAME_SIZE) < 0) goto fail; while ((iface = iface_next(GR_IFACE_TYPE_UNDEF, iface)) != NULL) { diff --git a/modules/infra/control/loopback.c b/modules/infra/control/loopback.c index 593c8f9d6..7369d91e0 100644 --- a/modules/infra/control/loopback.c +++ b/modules/infra/control/loopback.c @@ -307,7 +307,7 @@ static void loopback_module_fini(struct event_base *) { static void iface_loopback_to_api(void * /* info */, const struct iface * /* iface */) { } -static struct iface_type iface_type_loopback = { +static const struct iface_type iface_type_loopback = { .id = GR_IFACE_TYPE_LOOPBACK, .pub_size = 0, .priv_size = sizeof(struct iface_info_loopback), diff --git a/modules/infra/control/port.c b/modules/infra/control/port.c index 157570006..08190ff55 100644 --- a/modules/infra/control/port.c +++ b/modules/infra/control/port.c @@ -810,7 +810,7 @@ static void port_fini(struct event_base *) { gr_vec_free(reset_ports); } -static struct iface_type iface_type_port = { +static const struct iface_type iface_type_port = { .id = GR_IFACE_TYPE_PORT, .pub_size = sizeof(struct gr_iface_info_port), .priv_size = sizeof(struct iface_info_port), diff --git a/modules/infra/control/port_test.c b/modules/infra/control/port_test.c index 317a78964..cb35a8907 100644 --- a/modules/infra/control/port_test.c +++ b/modules/infra/control/port_test.c @@ -20,7 +20,7 @@ struct gr_config gr_config; struct workers workers; void gr_register_api_handler(struct gr_api_handler *) { } void gr_register_module(struct gr_module *) { } -void iface_type_register(struct iface_type *) { } +void iface_type_register(const struct iface_type *) { } void gr_event_push(uint32_t, const void *) { } void gr_event_subscribe(struct gr_event_subscription *) { } mock_func(struct rte_mempool *, gr_pktmbuf_pool_get(int8_t, uint32_t)); diff --git a/modules/infra/control/vlan.c b/modules/infra/control/vlan.c index d08ce0836..b1beb8c2f 100644 --- a/modules/infra/control/vlan.c +++ b/modules/infra/control/vlan.c @@ -184,7 +184,7 @@ static void vlan_to_api(void *info, const struct iface *iface) { *api = vlan->base; } -static struct iface_type iface_type_vlan = { +static const struct iface_type iface_type_vlan = { .id = GR_IFACE_TYPE_VLAN, .pub_size = sizeof(struct gr_iface_info_vlan), .priv_size = sizeof(struct iface_info_vlan), diff --git a/modules/infra/control/worker_test.c b/modules/infra/control/worker_test.c index 6a9df56a6..d4ccd90a1 100644 --- a/modules/infra/control/worker_test.c +++ b/modules/infra/control/worker_test.c @@ -39,7 +39,7 @@ struct gr_config gr_config; void gr_register_api_handler(struct gr_api_handler *) { } void gr_register_module(struct gr_module *) { } void gr_event_subscribe(struct gr_event_subscription *) { } -void iface_type_register(struct iface_type *) { } +void iface_type_register(const struct iface_type *) { } void gr_metrics_ctx_init(struct gr_metrics_ctx *, struct gr_metrics_writer *, ...) { } void gr_metrics_labels_add(struct gr_metrics_ctx *, ...) { } void gr_metric_emit(struct gr_metrics_ctx *, const struct gr_metric *, uint64_t) { } diff --git a/modules/ipip/control.c b/modules/ipip/control.c index 5e580ab93..b6defe3c8 100644 --- a/modules/ipip/control.c +++ b/modules/ipip/control.c @@ -113,7 +113,7 @@ static void ipip_to_api(void *info, const struct iface *iface) { *api = ipip->base; } -static struct iface_type iface_type_ipip = { +static const struct iface_type iface_type_ipip = { .id = GR_IFACE_TYPE_IPIP, .pub_size = sizeof(struct gr_iface_info_ipip), .priv_size = sizeof(struct iface_info_ipip), From 4da99a633def70e2fdc90ab7b26dacd6b290d74a Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Mon, 2 Feb 2026 14:56:21 +0100 Subject: [PATCH 4/6] infra: accumulate interface stats before flushing Instead of updating the shared iface_stats structure for every packet, accumulate packets and bytes in local variables and flush to the stats structure only when the interface changes or at the end of the batch. This reduces memory writes from O(n) to O(number of unique interfaces) per batch, which is typically O(1) for homogeneous traffic. The shared stats structure is accessed less frequently, reducing cache line pressure and store buffer usage. Reduces LLC cache misses by 11% (3.20M to 2.86M) and eth_input cycles from 48.0 to 46.2 per packet (-4%). Throughput remains at 11.8M pkt/s as ip_input (88 cycles/pkt) dominates the critical path. Signed-off-by: Robin Jarry --- modules/infra/datapath/bond_output.c | 34 ++++++++++++---- modules/infra/datapath/eth_input.c | 58 ++++++++++++++++----------- modules/infra/datapath/iface_output.c | 27 +++++++++++-- modules/infra/datapath/loop_xvrf.c | 28 +++++++++++-- modules/infra/datapath/xconnect.c | 52 +++++++++++++++++++++--- modules/ipip/datapath_in.c | 30 +++++++++++--- modules/ipip/datapath_out.c | 29 ++++++++++++-- 7 files changed, 208 insertions(+), 50 deletions(-) diff --git a/modules/infra/datapath/bond_output.c b/modules/infra/datapath/bond_output.c index 13c7a701b..6f6abb214 100644 --- a/modules/infra/datapath/bond_output.c +++ b/modules/infra/datapath/bond_output.c @@ -202,13 +202,19 @@ bond_select_tx_member(const struct rte_mbuf *m, const struct iface_info_bond *bo static uint16_t bond_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { const struct iface_info_bond *bond; - const struct iface *iface, *member; + uint16_t packets, last_iface_id; + const struct iface *member; + struct iface_stats *stats; rte_edge_t edge; + uint64_t bytes; + + last_iface_id = GR_IFACE_ID_UNDEF; + packets = 0; + bytes = 0; for (unsigned i = 0; i < nb_objs; i++) { struct rte_mbuf *mbuf = objs[i]; - iface = mbuf_data(mbuf)->iface; - bond = iface_info_bond(iface); + bond = iface_info_bond(mbuf_data(mbuf)->iface); // Select output member port member = bond_select_tx_member(mbuf, bond); @@ -224,16 +230,30 @@ bond_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, t->member_iface_id = member->id; } - // Update bond statistics - struct iface_stats *stats = iface_get_stats(rte_lcore_id(), iface->id); - stats->tx_packets += 1; - stats->tx_bytes += rte_pktmbuf_pkt_len(mbuf); + if (member->id != last_iface_id) { + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } + last_iface_id = member->id; + packets = 0; + bytes = 0; + } + packets += 1; + bytes += rte_pktmbuf_pkt_len(mbuf); edge = PORT_OUTPUT; next: rte_node_enqueue_x1(graph, node, edge, mbuf); } + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } + return nb_objs; } diff --git a/modules/infra/datapath/eth_input.c b/modules/infra/datapath/eth_input.c index 971a2d9a7..f37248f86 100644 --- a/modules/infra/datapath/eth_input.c +++ b/modules/infra/datapath/eth_input.c @@ -34,7 +34,7 @@ void gr_eth_input_add_type(rte_be16_t eth_type, const char *next_node) { static uint16_t eth_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { - uint16_t vlan_id, last_iface_id, last_vlan_id; + uint16_t vlan_id, last_iface_id, last_vlan_id, packets; const struct iface *vlan_iface, *iface; struct eth_input_mbuf_data *eth_in; struct rte_ether_addr iface_mac; @@ -45,11 +45,14 @@ eth_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u struct rte_mbuf *m; size_t l2_hdr_size; rte_edge_t edge; + uint64_t bytes; iface = NULL; vlan_iface = NULL; - last_iface_id = UINT16_MAX; + last_iface_id = GR_IFACE_ID_UNDEF; last_vlan_id = UINT16_MAX; + packets = 0; + bytes = 0; for (uint16_t i = 0; i < nb_objs; i++) { m = objs[i]; @@ -86,34 +89,38 @@ eth_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u eth_in->iface = vlan_iface; } - if (unlikely(rte_be_to_cpu_16(eth_type) < SNAP_MAX_LEN)) { - edge = SNAP; - goto snap; - } - - edge = l2l3_edges[eth_type]; - if (iface == NULL || iface->id != eth_in->iface->id) { if (iface_get_eth_addr(eth_in->iface, &iface_mac) < 0) { edge = INVALID_IFACE; goto next; } + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), iface->id); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + } iface = eth_in->iface; - stats = iface_get_stats(rte_lcore_id(), eth_in->iface->id); + packets = 0; + bytes = 0; } + packets += 1; + bytes += rte_pktmbuf_pkt_len(m); - stats->rx_packets += 1; - stats->rx_bytes += rte_pktmbuf_pkt_len(m); - - if (unlikely(rte_is_multicast_ether_addr(ð->dst_addr))) { - if (rte_is_broadcast_ether_addr(ð->dst_addr)) - eth_in->domain = ETH_DOMAIN_BROADCAST; - else - eth_in->domain = ETH_DOMAIN_MULTICAST; - } else if (rte_is_same_ether_addr(ð->dst_addr, &iface_mac)) { - eth_in->domain = ETH_DOMAIN_LOCAL; + if (unlikely(rte_be_to_cpu_16(eth_type) < SNAP_MAX_LEN)) { + edge = SNAP; } else { - eth_in->domain = ETH_DOMAIN_OTHER; + if (unlikely(rte_is_multicast_ether_addr(ð->dst_addr))) { + if (rte_is_broadcast_ether_addr(ð->dst_addr)) + eth_in->domain = ETH_DOMAIN_BROADCAST; + else + eth_in->domain = ETH_DOMAIN_MULTICAST; + } else if (rte_is_same_ether_addr(ð->dst_addr, &iface_mac)) { + eth_in->domain = ETH_DOMAIN_LOCAL; + } else { + eth_in->domain = ETH_DOMAIN_OTHER; + } + rte_pktmbuf_adj(m, l2_hdr_size); + edge = l2l3_edges[eth_type]; } next: if (gr_mbuf_is_traced(m) @@ -125,10 +132,15 @@ eth_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u t->vlan_id = vlan_id; t->iface_id = eth_in->iface->id; } - rte_pktmbuf_adj(m, l2_hdr_size); -snap: rte_node_enqueue_x1(graph, node, edge, m); } + + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), iface->id); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + } + return nb_objs; } diff --git a/modules/infra/datapath/iface_output.c b/modules/infra/datapath/iface_output.c index c7ca03014..256b6c456 100644 --- a/modules/infra/datapath/iface_output.c +++ b/modules/infra/datapath/iface_output.c @@ -34,10 +34,16 @@ static uint16_t iface_output_process( void **objs, uint16_t nb_objs ) { + uint16_t last_iface_id, packets; const struct iface *iface; struct iface_stats *stats; struct rte_mbuf *m; rte_edge_t edge; + uint64_t bytes; + + last_iface_id = GR_IFACE_ID_UNDEF; + packets = 0; + bytes = 0; for (uint16_t i = 0; i < nb_objs; i++) { m = objs[i]; @@ -53,9 +59,18 @@ static uint16_t iface_output_process( goto next; } - stats = iface_get_stats(rte_lcore_id(), iface->id); - stats->tx_packets += 1; - stats->tx_bytes += rte_pktmbuf_pkt_len(m); + if (iface->id != last_iface_id) { + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } + last_iface_id = iface->id; + packets = 0; + bytes = 0; + } + packets += 1; + bytes += rte_pktmbuf_pkt_len(m); edge = iface_type_edges[iface->type]; @@ -67,6 +82,12 @@ static uint16_t iface_output_process( rte_node_enqueue_x1(graph, node, edge, m); } + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } + return nb_objs; } diff --git a/modules/infra/datapath/loop_xvrf.c b/modules/infra/datapath/loop_xvrf.c index 68c95bd92..6acf36648 100644 --- a/modules/infra/datapath/loop_xvrf.c +++ b/modules/infra/datapath/loop_xvrf.c @@ -28,9 +28,15 @@ static int trace_vrf_format(char *buf, size_t len, const void *data, size_t /*da static uint16_t loop_xvrf_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { struct eth_input_mbuf_data *eth_data; + uint16_t packets, last_iface_id; struct iface_stats *stats; struct rte_mbuf *m; rte_edge_t edge; + uint64_t bytes; + + last_iface_id = GR_IFACE_ID_UNDEF; + packets = 0; + bytes = 0; for (uint16_t i = 0; i < nb_objs; i++) { m = objs[i]; @@ -44,9 +50,18 @@ loop_xvrf_process(struct rte_graph *graph, struct rte_node *node, void **objs, u eth_data->domain = ETH_DOMAIN_LOCAL; // XXX: increment tx stats of gr-loopX on initial vrf - stats = iface_get_stats(rte_lcore_id(), eth_data->iface->id); - stats->rx_packets += 1; - stats->rx_bytes += rte_pktmbuf_pkt_len(m); + if (last_iface_id != eth_data->iface->id) { + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + } + last_iface_id = eth_data->iface->id; + packets = 0; + bytes = 0; + } + packets += 1; + bytes += rte_pktmbuf_pkt_len(m); if (gr_mbuf_is_traced(m) || (eth_data->iface->flags & GR_IFACE_F_PACKET_TRACE)) { struct trace_vrf_data *t = gr_mbuf_trace_add(m, node, sizeof(*t)); @@ -55,6 +70,13 @@ loop_xvrf_process(struct rte_graph *graph, struct rte_node *node, void **objs, u rte_node_enqueue_x1(graph, node, edge, m); } + + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + } + return nb_objs; } diff --git a/modules/infra/datapath/xconnect.c b/modules/infra/datapath/xconnect.c index 0126bd755..171d17a85 100644 --- a/modules/infra/datapath/xconnect.c +++ b/modules/infra/datapath/xconnect.c @@ -19,28 +19,57 @@ enum edges { static uint16_t xconnect_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { + uint16_t last_rx_iface_id, last_tx_iface_id; const struct iface_info_port *port; const struct iface *iface, *peer; + uint16_t rx_packets, tx_packets; + uint64_t rx_bytes, tx_bytes; + struct iface_stats *stats; struct rte_mbuf *mbuf; rte_edge_t edge; + last_rx_iface_id = GR_IFACE_ID_UNDEF; + last_tx_iface_id = GR_IFACE_ID_UNDEF; + rx_packets = 0; + tx_packets = 0; + rx_bytes = 0; + tx_bytes = 0; + for (uint16_t i = 0; i < nb_objs; i++) { mbuf = objs[i]; iface = mbuf_data(mbuf)->iface; peer = iface_from_id(iface->domain_id); - struct iface_stats *rx_stats = iface_get_stats(rte_lcore_id(), iface->id); - rx_stats->rx_packets++; - rx_stats->rx_bytes += rte_pktmbuf_pkt_len(mbuf); + if (iface->id != last_rx_iface_id) { + if (rx_packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_rx_iface_id); + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + } + last_rx_iface_id = iface->id; + rx_packets = 0; + rx_bytes = 0; + } + rx_packets++; + rx_bytes += rte_pktmbuf_pkt_len(mbuf); if (peer->type == GR_IFACE_TYPE_PORT) { port = iface_info_port(peer); mbuf->port = port->port_id; edge = OUTPUT; - struct iface_stats *tx_stats = iface_get_stats(rte_lcore_id(), peer->id); - tx_stats->tx_packets++; - tx_stats->tx_bytes += rte_pktmbuf_pkt_len(mbuf); + if (peer->id != last_tx_iface_id) { + if (tx_packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_tx_iface_id); + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + } + last_tx_iface_id = peer->id; + tx_packets = 0; + tx_bytes = 0; + } + tx_packets++; + tx_bytes += rte_pktmbuf_pkt_len(mbuf); } else { edge = NO_PORT; } @@ -51,6 +80,17 @@ xconnect_process(struct rte_graph *graph, struct rte_node *node, void **objs, ui rte_node_enqueue_x1(graph, node, edge, mbuf); } + if (rx_packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_rx_iface_id); + stats->rx_packets += rx_packets; + stats->rx_bytes += rx_bytes; + } + if (tx_packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_tx_iface_id); + stats->tx_packets += tx_packets; + stats->tx_bytes += tx_bytes; + } + return nb_objs; } diff --git a/modules/ipip/datapath_in.c b/modules/ipip/datapath_in.c index 1e1b3552e..66f3599b5 100644 --- a/modules/ipip/datapath_in.c +++ b/modules/ipip/datapath_in.c @@ -37,15 +37,21 @@ ipip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, struct ip_local_mbuf_data *ip_data; ip4_addr_t last_src, last_dst; struct iface_stats *stats; + uint16_t last_iface_id; struct rte_mbuf *mbuf; uint16_t last_vrf_id; struct iface *ipip; + uint16_t packets; rte_edge_t edge; + uint64_t bytes; - ipip = NULL; + last_iface_id = GR_IFACE_ID_UNDEF; + last_vrf_id = GR_VRF_ID_ALL; last_src = 0; last_dst = 0; - last_vrf_id = GR_VRF_ID_ALL; + packets = 0; + ipip = NULL; + bytes = 0; for (uint16_t i = 0; i < nb_objs; i++) { mbuf = objs[i]; @@ -53,10 +59,19 @@ ipip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, if (ip_data->dst != last_dst || ip_data->src != last_src || ip_data->vrf_id != last_vrf_id) { + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + packets = 0; + bytes = 0; + } ipip = ipip_get_iface(ip_data->dst, ip_data->src, ip_data->vrf_id); last_dst = ip_data->dst; last_src = ip_data->src; last_vrf_id = ip_data->vrf_id; + if (ipip != NULL) + last_iface_id = ipip->id; } if (ipip == NULL) { edge = NO_TUNNEL; @@ -73,9 +88,8 @@ ipip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, eth_data->iface = ipip; eth_data->domain = ETH_DOMAIN_LOCAL; edge = IP_INPUT; - stats = iface_get_stats(rte_lcore_id(), ipip->id); - stats->rx_packets += 1; - stats->rx_bytes += rte_pktmbuf_pkt_len(mbuf); + packets += 1; + bytes += rte_pktmbuf_pkt_len(mbuf); next: if (gr_mbuf_is_traced(mbuf) || (ipip && ipip->flags & GR_IFACE_F_PACKET_TRACE)) { struct trace_ipip_data *t = gr_mbuf_trace_add(mbuf, node, sizeof(*t)); @@ -84,6 +98,12 @@ ipip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, rte_node_enqueue_x1(graph, node, edge, mbuf); } + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + } + return nb_objs; } diff --git a/modules/ipip/datapath_out.c b/modules/ipip/datapath_out.c index 8db594e9e..c345be8c6 100644 --- a/modules/ipip/datapath_out.c +++ b/modules/ipip/datapath_out.c @@ -35,8 +35,16 @@ ipip_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, const struct rte_ipv4_hdr *inner; struct rte_ipv4_hdr *outer; const struct iface *iface; + struct iface_stats *stats; + uint16_t last_iface_id; struct rte_mbuf *mbuf; + uint16_t packets; rte_edge_t edge; + uint64_t bytes; + + last_iface_id = GR_IFACE_ID_UNDEF; + packets = 0; + bytes = 0; for (uint16_t i = 0; i < nb_objs; i++) { mbuf = objs[i]; @@ -74,9 +82,18 @@ ipip_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, } ip_set_fields(outer, &tunnel); - struct iface_stats *stats = iface_get_stats(rte_lcore_id(), iface->id); - stats->tx_packets += 1; - stats->tx_bytes += rte_pktmbuf_pkt_len(mbuf); + if (iface->id != last_iface_id) { + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } + last_iface_id = iface->id; + packets = 0; + bytes = 0; + } + packets += 1; + bytes += rte_pktmbuf_pkt_len(mbuf); // Resolve nexthop for the encapsulated packet. ip_data->nh = fib4_lookup(iface->vrf_id, ipip->remote); @@ -86,6 +103,12 @@ ipip_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, rte_node_enqueue_x1(graph, node, edge, mbuf); } + if (packets > 0) { + stats = iface_get_stats(rte_lcore_id(), last_iface_id); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } + return nb_objs; } From 14c2d86b2d2a5727d9b26d602725474fa70f08e9 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Tue, 3 Feb 2026 16:01:44 +0100 Subject: [PATCH 5/6] infra: move RCU quiescent state report to housekeeping interval RCU quiescent state only needs to be reported periodically to signal that the thread has passed through a quiescent period. Reporting it on every graph walk iteration is unnecessarily frequent and adds overhead from the memory barriers involved. Move rte_rcu_qsbr_quiescent() from the main loop body into the housekeeping block that runs every 256 iterations. This reduces the frequency of memory barriers while still ensuring timely RCU grace period completion. Reduces LLC cache misses by 7% (2.86M to 2.67M) and L1 cache misses by 6% (2.14B to 2.01B). Throughput remains at 11.8M pkt/s as ip_input dominates the critical path. Signed-off-by: Robin Jarry --- modules/infra/datapath/main_loop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/infra/datapath/main_loop.c b/modules/infra/datapath/main_loop.c index 1c56676b1..8a9002950 100644 --- a/modules/infra/datapath/main_loop.c +++ b/modules/infra/datapath/main_loop.c @@ -250,9 +250,9 @@ void *gr_datapath_loop(void *priv) { timestamp = rte_rdtsc(); for (;;) { rte_graph_walk(graph); - rte_rcu_qsbr_quiescent(rcu, rte_lcore_id()); if (++loop == HOUSEKEEPING_INTERVAL) { + rte_rcu_qsbr_quiescent(rcu, rte_lcore_id()); if (atomic_load(&w->shutdown) || atomic_load(&w->next_config) != cur) { rte_rcu_qsbr_thread_offline(rcu, rte_lcore_id()); goto reconfig; From ad404b0d9596b7e0a4f38d79f486fb0453fd1750 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Tue, 3 Feb 2026 17:03:27 +0100 Subject: [PATCH 6/6] port_rx: only access ether type when port is bonded The rx_process function was checking the ether_type of every received packet to detect LACP slow protocol frames (0x8809). This check is only relevant for bonded interfaces, yet it was performed unconditionally on all ports. Move the ether_type check outside the main loop and only execute it when the interface mode is GR_IFACE_MODE_BOND. For non-bonded ports, the loop now simply stores the iface pointer without accessing packet data. This reduces L1 cache misses by 6% (2.26B to 2.13B) and port_rx node cycles per packet by 10% (47.0 to 42.1). The perf annotate data shows that the ether_type comparison accounted for 59% of L1 cache misses within rx_process. Eliminating this access for non-bonded ports cuts rx_process cache miss samples by 61%. Signed-off-by: Robin Jarry --- modules/infra/datapath/port_rx.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/modules/infra/datapath/port_rx.c b/modules/infra/datapath/port_rx.c index c72b2c782..824e20c50 100644 --- a/modules/infra/datapath/port_rx.c +++ b/modules/infra/datapath/port_rx.c @@ -46,7 +46,6 @@ rx_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t const struct rx_node_ctx *ctx = rx_node_ctx(node); const struct iface_info_port *port; const struct rte_ether_hdr *eth; - struct eth_input_mbuf_data *d; const struct iface *iface; uint16_t rx; unsigned r; @@ -70,14 +69,19 @@ rx_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t return 0; rx = rte_eth_rx_burst(ctx->rxq.port_id, ctx->rxq.queue_id, mbufs, ctx->burst_size); - for (r = 0; r < rx; r++) { - eth = rte_pktmbuf_mtod(mbufs[r], const struct rte_ether_hdr *); - d = eth_input_mbuf_data(mbufs[r]); - if (unlikely(eth->ether_type == RTE_BE16(RTE_ETHER_TYPE_SLOW))) - d->iface = ctx->iface; - else - d->iface = iface; - d->domain = ETH_DOMAIN_UNKNOWN; + if (rx == 0) + return 0; + if (ctx->iface->mode == GR_IFACE_MODE_BOND) { + for (r = 0; r < rx; r++) { + eth = rte_pktmbuf_mtod(mbufs[r], const struct rte_ether_hdr *); + if (unlikely(eth->ether_type == RTE_BE16(RTE_ETHER_TYPE_SLOW))) + mbuf_data(mbufs[r])->iface = ctx->iface; + else + mbuf_data(mbufs[r])->iface = iface; + } + } else { + for (r = 0; r < rx; r++) + mbuf_data(mbufs[r])->iface = iface; } if (unlikely(ctx->iface->flags & GR_IFACE_F_PACKET_TRACE)) {