From db3a87b83c1463b51274302f311aecdb2a7b1009 Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 11 Oct 2024 09:46:48 +0000 Subject: [PATCH 01/10] infra: packet tracing Add packet tracing infrastructure, to log packet traversal on nodes. Add CLI to enable/disable packet tracing per interface. Signed-off-by: Christophe Fontaine --- modules/infra/api/gr_infra.h | 24 +++++ modules/infra/api/meson.build | 1 + modules/infra/api/trace.c | 98 ++++++++++++++++++ modules/infra/cli/iface.c | 15 ++- modules/infra/cli/meson.build | 1 + modules/infra/cli/trace.c | 139 ++++++++++++++++++++++++++ modules/infra/control/gr_graph.h | 8 ++ modules/infra/control/graph.c | 6 ++ modules/infra/datapath/drop.c | 13 +++ modules/infra/datapath/gr_mbuf.h | 31 +++++- modules/infra/datapath/gr_trace.h | 21 ++++ modules/infra/datapath/rx.c | 30 ++++++ modules/infra/datapath/trace.c | 160 ++++++++++++++++++++++++++++++ modules/infra/datapath/tx.c | 23 +++++ smoke/_init.sh | 3 + 15 files changed, 570 insertions(+), 3 deletions(-) create mode 100644 modules/infra/api/trace.c create mode 100644 modules/infra/cli/trace.c create mode 100644 modules/infra/datapath/gr_trace.h diff --git a/modules/infra/api/gr_infra.h b/modules/infra/api/gr_infra.h index 3eb28650..b8b0f68e 100644 --- a/modules/infra/api/gr_infra.h +++ b/modules/infra/api/gr_infra.h @@ -25,6 +25,7 @@ #define GR_IFACE_F_UP GR_BIT16(0) #define GR_IFACE_F_PROMISC GR_BIT16(1) #define GR_IFACE_F_ALLMULTI GR_BIT16(2) +#define GR_IFACE_F_PACKET_TRACE GR_BIT16(3) // Interface state flags #define GR_IFACE_S_RUNNING GR_BIT16(0) @@ -203,4 +204,27 @@ struct gr_infra_graph_dump_resp { char dot[/* len */]; }; +// packet tracing ////////////////////////////////////////////////////////////// +#define GR_INFRA_PACKET_TRACE_CLEAR REQUEST_TYPE(GR_INFRA_MODULE, 0x0040) + +// struct gr_infra_trace_clear_req { }; +// struct gr_infra_trace_clear_resp { }; + +#define GR_INFRA_PACKET_TRACE_SHOW REQUEST_TYPE(GR_INFRA_MODULE, 0x0041) + +// struct gr_infra_trace_dump_req { }; + +struct gr_infra_packet_trace_resp { + uint32_t len; + char trace[/* len */]; +}; + +#define GR_INFRA_PACKET_TRACE_SET REQUEST_TYPE(GR_INFRA_MODULE, 0x0042) + +struct gr_infra_packet_trace_set_req { + bool enabled; + bool all; + uint16_t iface_id; +}; + #endif diff --git a/modules/infra/api/meson.build b/modules/infra/api/meson.build index a3467969..9cf70590 100644 --- a/modules/infra/api/meson.build +++ b/modules/infra/api/meson.build @@ -4,6 +4,7 @@ src += files( 'graph.c', 'iface.c', + 'trace.c', 'rxq.c', 'stats.c', ) diff --git a/modules/infra/api/trace.c b/modules/infra/api/trace.c new file mode 100644 index 00000000..795f5f33 --- /dev/null +++ b/modules/infra/api/trace.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024 Christophe Fontaine + +#include "gr_infra.h" + +#include +#include +#include +#include + +#define TRACE_STR (6 * 1024) // 64 nodes, 80 cols per node: ~5120 bytes. + +static bool trace_enabled = true; + +static void iface_callback(iface_event_t event, struct iface *iface) { + if (event == IFACE_EVENT_POST_ADD && trace_enabled) + iface->flags |= GR_IFACE_F_PACKET_TRACE; +} + +static struct api_out set_trace(const void *request, void **) { + const struct gr_infra_packet_trace_set_req *req = request; + struct iface *iface = NULL; + + if (req->all == false) { + if ((iface = iface_from_id(req->iface_id)) == NULL) + return api_out(ENODEV, 0); + + if (req->enabled) + iface->flags |= GR_IFACE_F_PACKET_TRACE; + else + iface->flags &= ~GR_IFACE_F_PACKET_TRACE; + + } else { + trace_enabled = req->enabled; + while ((iface = iface_next(GR_IFACE_TYPE_UNDEF, iface)) != NULL) { + if (req->enabled) + iface->flags |= GR_IFACE_F_PACKET_TRACE; + else + iface->flags &= ~GR_IFACE_F_PACKET_TRACE; + } + } + + return api_out(0, 0); +} + +static struct api_out show_trace(const void * /*request*/, void **response) { + struct gr_infra_packet_trace_resp *resp; + size_t resp_len = sizeof(*resp); + int len = 0; + + resp = calloc(1, sizeof(*resp) + TRACE_STR); + if (resp == NULL) { + return api_out(ENOMEM, 0); + } + len = trace_print(resp->trace, TRACE_STR); + if (len < 0) { + return api_out(-len, 0); + } + resp->len = len; + resp_len = sizeof(*resp) + len; + + *response = resp; + return api_out(0, resp_len); +} + +static struct api_out clear_trace(const void * /*request */, void ** /*response*/) { + trace_clear(); + return api_out(0, 0); +} + +static struct gr_api_handler set_trace_handler = { + .name = "set trace", + .request_type = GR_INFRA_PACKET_TRACE_SET, + .callback = set_trace, +}; + +static struct gr_api_handler show_trace_handler = { + .name = "show trace", + .request_type = GR_INFRA_PACKET_TRACE_SHOW, + .callback = show_trace, +}; + +static struct gr_api_handler clear_trace_handler = { + .name = "clear trace", + .request_type = GR_INFRA_PACKET_TRACE_CLEAR, + .callback = clear_trace, +}; + +static struct iface_event_handler iface_event_trace_handler = { + .callback = iface_callback, +}; + +RTE_INIT(trace_init) { + gr_register_api_handler(&set_trace_handler); + gr_register_api_handler(&show_trace_handler); + gr_register_api_handler(&clear_trace_handler); + iface_event_register_handler(&iface_event_trace_handler); +} diff --git a/modules/infra/cli/iface.c b/modules/infra/cli/iface.c index 5491530b..7a1b9cb7 100644 --- a/modules/infra/cli/iface.c +++ b/modules/infra/cli/iface.c @@ -148,7 +148,7 @@ uint64_t parse_iface_args( struct gr_iface *iface, bool update ) { - const char *name, *promisc, *allmulti; + const char *name, *promisc, *allmulti, *trace; uint64_t set_attrs = 0; name = arg_str(p, "NAME"); @@ -192,6 +192,15 @@ uint64_t parse_iface_args( set_attrs |= GR_IFACE_SET_FLAGS; } + trace = arg_str(p, "TRACE"); + if (trace != NULL && strcmp(trace, "on") == 0) { + iface->flags |= GR_IFACE_F_PACKET_TRACE; + set_attrs |= GR_IFACE_SET_FLAGS; + } else if (trace != NULL && strcmp(trace, "off") == 0) { + iface->flags &= ~GR_IFACE_F_PACKET_TRACE; + set_attrs |= GR_IFACE_SET_FLAGS; + } + if (arg_u16(p, "MTU", &iface->mtu) == 0) set_attrs |= GR_IFACE_SET_MTU; @@ -280,6 +289,8 @@ static cmd_status_t iface_list(const struct gr_api_client *c, const struct ec_pn n += snprintf(buf + n, sizeof(buf) - n, " promisc"); if (iface->flags & GR_IFACE_F_ALLMULTI) n += snprintf(buf + n, sizeof(buf) - n, " allmulti"); + if (iface->flags & GR_IFACE_F_PACKET_TRACE) + n += snprintf(buf + n, sizeof(buf) - n, " tracing"); scols_line_set_data(line, 2, buf); // vrf @@ -332,6 +343,8 @@ static cmd_status_t iface_show(const struct gr_api_client *c, const struct ec_pn printf(" promisc"); if (iface.flags & GR_IFACE_F_ALLMULTI) printf(" allmulti"); + if (iface.flags & GR_IFACE_F_PACKET_TRACE) + printf(" tracing"); printf("\n"); printf("vrf: %u\n", iface.vrf_id); printf("mtu: %u\n", iface.mtu); diff --git a/modules/infra/cli/meson.build b/modules/infra/cli/meson.build index e1bd883c..22dac35d 100644 --- a/modules/infra/cli/meson.build +++ b/modules/infra/cli/meson.build @@ -4,6 +4,7 @@ cli_src += files( 'graph.c', 'iface.c', + 'trace.c', 'port.c', 'vlan.c', 'stats.c', diff --git a/modules/infra/cli/trace.c b/modules/infra/cli/trace.c new file mode 100644 index 00000000..344cb84a --- /dev/null +++ b/modules/infra/cli/trace.c @@ -0,0 +1,139 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024 Christophe Fontaine + +#include "gr_cli_iface.h" + +#include +#include +#include +#include + +#include + +#include +#include + +static cmd_status_t trace_set(const struct gr_api_client *c, const struct ec_pnode *p) { + struct gr_infra_packet_trace_set_req req; + struct gr_iface iface; + + req.enabled = true; + + if (arg_str(p, "all") != NULL) + req.all = true; + else if (iface_from_name(c, arg_str(p, "NAME"), &iface) < 0) + return CMD_ERROR; + else + req.iface_id = iface.id; + + if (gr_api_client_send_recv(c, GR_INFRA_PACKET_TRACE_SET, sizeof(req), &req, NULL) < 0) + return CMD_ERROR; + + return CMD_SUCCESS; +} + +static cmd_status_t trace_del(const struct gr_api_client *c, const struct ec_pnode *p) { + struct gr_infra_packet_trace_set_req req; + struct gr_iface iface; + + req.enabled = false; + if (arg_str(p, "all") != NULL) + req.all = true; + else if (iface_from_name(c, arg_str(p, "NAME"), &iface) < 0) + return CMD_ERROR; + else + req.iface_id = iface.id; + + if (gr_api_client_send_recv(c, GR_INFRA_PACKET_TRACE_SET, sizeof(req), &req, NULL) < 0) + return CMD_ERROR; + + return CMD_SUCCESS; +} + +static cmd_status_t trace_show(const struct gr_api_client *c, const struct ec_pnode *) { + const struct gr_infra_packet_trace_resp *resp = NULL; + void *resp_ptr = NULL; + size_t len = 0; + + do { + if (gr_api_client_send_recv(c, GR_INFRA_PACKET_TRACE_SHOW, 0, NULL, &resp_ptr) < 0) + return CMD_ERROR; + + resp = resp_ptr; + len = resp->len; + if (len > 1) { + fwrite(resp->trace, 1, resp->len, stdout); + } + free(resp_ptr); + } while (len > 0); + + return CMD_SUCCESS; +} + +static cmd_status_t trace_clear(const struct gr_api_client *c, const struct ec_pnode *) { + if (gr_api_client_send_recv(c, GR_INFRA_PACKET_TRACE_CLEAR, 0, NULL, NULL) < 0) + return CMD_ERROR; + + return CMD_SUCCESS; +} + +static int ctx_init(struct ec_node *root) { + int ret; + + ret = CLI_COMMAND( + CLI_CONTEXT( + root, + CTX_SET, + CTX_ARG("trace", "Enable packet tracing for specified interface") + ), + "all|(iface NAME)", + trace_set, + "Enable packet tracing for all or specified interface.", + with_help("all interfaces.", ec_node_str("all", "all")), + with_help( + "Interface name.", + ec_node_dyn("NAME", complete_iface_names, INT2PTR(GR_IFACE_TYPE_UNDEF)) + ) + ); + if (ret < 0) + return ret; + + ret = CLI_COMMAND( + CLI_CONTEXT( + root, + CTX_DEL, + CTX_ARG("trace", "Disable packet tracing for specified interface") + ), + "all|(iface NAME)", + trace_del, + "Enable packet tracing for all or specified interface.", + with_help("all interfaces.", ec_node_str("all", "all")), + with_help( + "Interface name.", + ec_node_dyn("NAME", complete_iface_names, INT2PTR(GR_IFACE_TYPE_UNDEF)) + ) + ); + if (ret < 0) + return ret; + + ret = CLI_COMMAND(CLI_CONTEXT(root, CTX_SHOW), "trace", trace_show, "Show traced packets."); + if (ret < 0) + return ret; + + ret = CLI_COMMAND( + CLI_CONTEXT(root, CTX_CLEAR), "trace", trace_clear, "Clear packet tracing buffer.", + ); + if (ret < 0) + return ret; + + return 0; +} + +static struct gr_cli_context ctx = { + .name = "trace", + .init = ctx_init, +}; + +static void __attribute__((constructor, used)) init(void) { + register_context(&ctx); +} diff --git a/modules/infra/control/gr_graph.h b/modules/infra/control/gr_graph.h index 205f0fce..f75b3055 100644 --- a/modules/infra/control/gr_graph.h +++ b/modules/infra/control/gr_graph.h @@ -16,11 +16,18 @@ int gr_node_data_set(const char *graph, const char *node, void *data); rte_edge_t gr_node_attach_parent(const char *parent, const char *node); uint16_t drop_packets(struct rte_graph *, struct rte_node *, void **, uint16_t); +int format_drop(void *data, char *buf, size_t buf_len); + +struct node_ext_funcs { + int (*format_trace)(void *data, char *buf, size_t buf_len); +}; +struct node_ext_funcs *gr_get_node_ext_funcs(uint16_t node); struct gr_node_info { struct rte_node_register *node; void (*register_callback)(void); void (*unregister_callback)(void); + struct node_ext_funcs ext_funcs; STAILQ_ENTRY(gr_node_info) next; }; @@ -39,6 +46,7 @@ extern struct node_infos node_infos; }; \ static struct gr_node_info drop_info_##node_name = { \ .node = &drop_node_##node_name, \ + .ext_funcs.format_trace = format_drop, \ }; \ RTE_INIT(gr_drop_register_##node_name) { \ STAILQ_INSERT_TAIL(&node_infos, &drop_info_##node_name, next); \ diff --git a/modules/infra/control/graph.c b/modules/infra/control/graph.c index 7d885f0d..fbc1ea9a 100644 --- a/modules/infra/control/graph.c +++ b/modules/infra/control/graph.c @@ -260,6 +260,11 @@ int worker_graph_reload_all(void) { return 0; } +static struct node_ext_funcs node_funcs[UINT16_MAX]; +struct node_ext_funcs *gr_get_node_ext_funcs(uint16_t node) { + return &node_funcs[node]; +} + static void graph_init(struct event_base *) { struct rte_node_register *reg; struct gr_node_info *info; @@ -274,6 +279,7 @@ static void graph_init(struct event_base *) { if (reg->id == RTE_NODE_ID_INVALID) ABORT("__rte_node_register(%s): %s", reg->name, rte_strerror(rte_errno)); arrpush(node_names, reg->name); + node_funcs[reg->id].format_trace = info->ext_funcs.format_trace; } // then, invoke all registration callbacks where applicable diff --git a/modules/infra/datapath/drop.c b/modules/infra/datapath/drop.c index d7265fb4..4fc87a5b 100644 --- a/modules/infra/datapath/drop.c +++ b/modules/infra/datapath/drop.c @@ -1,6 +1,8 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2024 Robin Jarry +#include "gr_trace.h" + #include #include @@ -11,10 +13,21 @@ uint16_t drop_packets(struct rte_graph *, struct rte_node *node, void **objs, ui if (unlikely(packet_trace_enabled)) { LOG(NOTICE, "[%s] %u packets", node->name, nb_objs); } + for (int i = 0; i < nb_objs; i++) { + struct rte_mbuf *mbuf = (struct rte_mbuf *)objs[i]; + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + gr_trace_add(node, mbuf, 0); + gr_trace_aggregate(mbuf); + } + } rte_pktmbuf_free_bulk((struct rte_mbuf **)objs, nb_objs); return nb_objs; } +int format_drop(void *, char *buf, size_t len) { + return snprintf(buf, len, "DROP"); +} + // Global drop counters, used by multiple nodes GR_DROP_REGISTER(error_no_headroom); diff --git a/modules/infra/datapath/gr_mbuf.h b/modules/infra/datapath/gr_mbuf.h index d933ff46..7cea1913 100644 --- a/modules/infra/datapath/gr_mbuf.h +++ b/modules/infra/datapath/gr_mbuf.h @@ -4,18 +4,45 @@ #ifndef _GR_MBUF #define _GR_MBUF +#include + #include +#include #include -#define GR_MBUF_PRIV_MAX_SIZE RTE_CACHE_LINE_MIN_SIZE +#include + +#define GR_TRACE_DATA_SIZE 128 +struct gr_trace_item { + STAILQ_ENTRY(gr_trace_item) next; + struct timespec ts; + uint16_t cpu_id; + rte_node_t node_id; + uint16_t len; + uint8_t data[GR_TRACE_DATA_SIZE]; +}; + +STAILQ_HEAD(gr_trace_items, gr_trace_item); + +#define GR_MBUF_PRIV_MAX_SIZE RTE_CACHE_LINE_MIN_SIZE * 2 #define GR_MBUF_PRIV_DATA_TYPE(type_name, fields) \ - struct type_name fields; \ + struct type_name { \ + uint32_t flags; \ + struct gr_trace_items traces; \ + struct fields; \ + }; \ static inline struct type_name *type_name(struct rte_mbuf *m) { \ static_assert(sizeof(struct type_name) <= GR_MBUF_PRIV_MAX_SIZE); \ return rte_mbuf_to_priv(m); \ } GR_MBUF_PRIV_DATA_TYPE(queue_mbuf_data, { struct rte_mbuf *next; }); +GR_MBUF_PRIV_DATA_TYPE(gr_mbuf, {}); + +#define GR_MBUF_F_PKT_TRACE GR_BIT32(0) +static inline bool gr_mbuf_trace_is_set(struct rte_mbuf *mbuf) { + return !!(gr_mbuf(mbuf)->flags & GR_MBUF_F_PKT_TRACE); +} #endif diff --git a/modules/infra/datapath/gr_trace.h b/modules/infra/datapath/gr_trace.h new file mode 100644 index 00000000..9c2357f0 --- /dev/null +++ b/modules/infra/datapath/gr_trace.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024 Christophe Fontaine + +#ifndef _GR_INFRA_PACKET_TRACE +#define _GR_INFRA_PACKET_TRACE + +#include + +#include + +// Only source nodes should use gr_trace_begin +void *gr_trace_begin(struct rte_node *node, struct rte_mbuf *m, uint16_t data_len); + +void *gr_trace_add(struct rte_node *node, struct rte_mbuf *m, uint16_t data_len); + +// Only drop and TX nodes should use gr_trace_aggregate +void gr_trace_aggregate(struct rte_mbuf *m); + +int trace_print(char *buf, size_t len); +void trace_clear(void); +#endif diff --git a/modules/infra/datapath/rx.c b/modules/infra/datapath/rx.c index c35ee40c..dee36001 100644 --- a/modules/infra/datapath/rx.c +++ b/modules/infra/datapath/rx.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,19 @@ struct rx_ctx { struct rx_port_queue queues[/* n_queues */]; }; +struct trace_rx_data { + uint16_t iface_id; + uint16_t port_id; + uint16_t queue_id; +}; + +static int format_rx_input(void *data, char *buf, size_t len) { + struct trace_rx_data *t = data; + const struct iface *iface = iface_from_id(t->iface_id); + const char *ifname = iface ? iface->name : "[deleted]"; + return snprintf(buf, len, "p%dq%d iface %s", t->port_id, t->queue_id, ifname); +} + static uint16_t rx_process(struct rte_graph *graph, struct rte_node *node, void ** /*objs*/, uint16_t count) { const struct rx_ctx *ctx = node->ctx_ptr; @@ -48,15 +62,30 @@ rx_process(struct rte_graph *graph, struct rte_node *node, void ** /*objs*/, uin q.port_id, q.rxq_id, (struct rte_mbuf **)&node->objs[count], ctx->burst_size ); iface = port_get_iface(q.port_id); + if (rx > 0 && iface == NULL) { rte_node_enqueue(graph, node, NO_IFACE, &node->objs[count], rx); continue; } + for (r = count; r < count + rx; r++) { d = eth_input_mbuf_data(node->objs[r]); d->iface = iface; d->eth_dst = ETH_DST_UNKNOWN; } + + if (unlikely(iface && iface->flags & GR_IFACE_F_PACKET_TRACE)) { + struct trace_rx_data *t; + for (r = count; r < count + rx; r++) { + t = gr_trace_begin(node, node->objs[r], sizeof(*t)); + if (t) { + t->port_id = q.port_id; + t->queue_id = q.rxq_id; + t->iface_id = iface->id; + } + } + } + if (unlikely(packet_trace_enabled)) { for (r = count; r < count + rx; r++) { trace_packet("rx", iface->name, node->objs[r]); @@ -114,6 +143,7 @@ static struct rte_node_register node = { static struct gr_node_info info = { .node = &node, + .ext_funcs.format_trace = format_rx_input, }; GR_NODE_REGISTER(info); diff --git a/modules/infra/datapath/trace.c b/modules/infra/datapath/trace.c index f4a7bfff..391e81aa 100644 --- a/modules/infra/datapath/trace.c +++ b/modules/infra/datapath/trace.c @@ -3,7 +3,10 @@ #include "gr_datapath.h" #include "gr_icmp6.h" +#include "gr_trace.h" +#include +#include #include #include @@ -11,11 +14,14 @@ #include #include #include +#include #include #include #include #include #include +#include +#include static ssize_t trace_icmp6( char *buf, @@ -347,3 +353,157 @@ static ssize_t trace_icmp6( return n; } + +#define PACKET_COUNT_MAX RTE_GRAPH_BURST_SIZE + +static struct rte_mempool *trace_pool; +static struct rte_ring *traced_packets; + +void *gr_trace_begin(struct rte_node *node, struct rte_mbuf *m, uint16_t data_len) { + struct gr_mbuf *gm = gr_mbuf(m); + struct gr_trace_item *pt; + void *data; + + if (rte_mempool_get(trace_pool, &data) < 0) + return NULL; + + gm->flags |= GR_MBUF_F_PKT_TRACE; + STAILQ_INIT(&gm->traces); + pt = data; + + clock_gettime(CLOCK_REALTIME_COARSE, &pt->ts); + pt->cpu_id = rte_lcore_id(); + + pt->node_id = node->id; + pt->len = data_len; + + STAILQ_INSERT_HEAD(&gm->traces, pt, next); + + return pt->data; +} + +void *gr_trace_add(struct rte_node *node, struct rte_mbuf *m, uint16_t data_len) { + struct gr_mbuf *gm = gr_mbuf(m); + struct gr_trace_item *pt; + void *data; + + if (rte_mempool_get(trace_pool, &data) < 0) + return NULL; + + pt = data; + pt->node_id = node->id; + pt->len = data_len; + + STAILQ_INSERT_TAIL(&gm->traces, pt, next); + return pt->data; +} + +static void free_trace(struct gr_trace_item *t) { + struct gr_trace_item *next; + while (t != NULL) { + next = STAILQ_NEXT(t, next); + rte_mempool_put(trace_pool, t); + t = next; + } +} + +void gr_trace_aggregate(struct rte_mbuf *mbuf) { + struct gr_trace_item *t = NULL; + struct gr_mbuf *gm = gr_mbuf(mbuf); + + gm->flags &= ~GR_MBUF_F_PKT_TRACE; + if (rte_ring_full(traced_packets) == 1) { + rte_ring_dequeue(traced_packets, (void *)&t); + free_trace(t); + } + + t = STAILQ_FIRST(&gm->traces); + rte_ring_enqueue(traced_packets, t); +} + +int trace_print(char *buf, size_t len) { + struct gr_trace_item *t, *head; + struct tm tm; + size_t sz = 0; + int c; + + if (rte_ring_dequeue(traced_packets, (void *)&t) == 0) { + head = t; + + gmtime_r(&t->ts.tv_sec, &tm); + sz += strftime(&buf[sz], len - sz, "--------- %H:%M:%S.", &tm); + sz += snprintf(&buf[sz], len - sz, "%09luZ", t->ts.tv_nsec); + sz += snprintf(&buf[sz], len - sz, " cpu %d ---------\n", t->cpu_id); + + while (t) { + if ((c = snprintf( + &buf[sz], sz - len, "%s: ", rte_node_id_to_name(t->node_id) + )) + < 0) + break; + sz += c; + if (gr_get_node_ext_funcs(t->node_id)->format_trace) + c = gr_get_node_ext_funcs(t->node_id) + ->format_trace(t->data, &buf[sz], sz - len); + if (c < 0) + break; + sz += c; + if ((c = snprintf(&buf[sz], len - sz, "\n")) < 0) + break; + sz += c; + t = STAILQ_NEXT(t, next); + } + free_trace(head); + sz += snprintf(&buf[sz], len - sz, "\n"); + } + return sz; +} + +void trace_clear() { + struct gr_trace_item *t; + while (rte_ring_dequeue(traced_packets, (void *)&t) == 0) + free_trace(t); +} + +static void trace_init(struct event_base *) { + trace_pool = rte_mempool_create( + "trace", // name + rte_align32pow2(PACKET_COUNT_MAX * 128) - 1, + sizeof(struct gr_trace_item), + 0, // cache size + 0, // priv size + NULL, // mp_init + NULL, // mp_init_arg + NULL, // obj_init + NULL, // obj_init_arg + SOCKET_ID_ANY, + 0 // flags + ); + if (trace_pool == NULL) + ABORT("rte_mempool_create(trace_pool) failed"); + traced_packets = rte_ring_create( + "traced_packets", + PACKET_COUNT_MAX, + SOCKET_ID_ANY, + RING_F_SC_DEQ // flags + ); + + if (traced_packets == NULL) + ABORT("rte_stack_create(traced_packets) failed"); +} + +static void trace_fini(struct event_base *) { + trace_clear(); + rte_mempool_free(trace_pool); + rte_ring_free(traced_packets); +} + +static struct gr_module trace_module = { + .name = "trace", + .init = trace_init, + .fini = trace_fini, +}; + +RTE_INIT(trace_constructor) { + gr_register_module(&trace_module); +} diff --git a/modules/infra/datapath/tx.c b/modules/infra/datapath/tx.c index d914d308..a9ff39bc 100644 --- a/modules/infra/datapath/tx.c +++ b/modules/infra/datapath/tx.c @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -23,6 +24,17 @@ struct tx_ctx { uint16_t txq_ids[RTE_MAX_ETHPORTS]; }; +struct trace_tx_data { + uint16_t iface_id; + uint16_t port_id; + uint16_t queue_id; +}; + +static int format_tx_output(void *data, char *buf, size_t len) { + struct trace_tx_data *t = data; + return snprintf(buf, len, "p%dq%d", t->port_id, t->queue_id); +} + static inline void tx_burst( struct rte_graph *graph, struct rte_node *node, @@ -40,6 +52,16 @@ static inline void tx_burst( tx_ok = rte_eth_tx_burst(port_id, txq_id, mbufs, n); if (tx_ok < n) rte_node_enqueue(graph, node, TX_ERROR, (void *)&mbufs[tx_ok], n - tx_ok); + for (int i = 0; i < tx_ok; i++) { + if (unlikely(gr_mbuf_trace_is_set(mbufs[i]))) { + struct trace_tx_data *t = gr_trace_add(node, mbufs[i], sizeof(*t)); + if (t) { + t->queue_id = txq_id; + t->port_id = port_id; + } + gr_trace_aggregate(mbufs[i]); + } + } } } @@ -111,6 +133,7 @@ static struct rte_node_register node = { static struct gr_node_info info = { .node = &node, + .ext_funcs.format_trace = format_tx_output, }; GR_NODE_REGISTER(info); diff --git a/smoke/_init.sh b/smoke/_init.sh index 45626f70..a4febd13 100644 --- a/smoke/_init.sh +++ b/smoke/_init.sh @@ -41,6 +41,7 @@ grcli show ip nexthop grcli show ip route grcli show ip6 nexthop grcli show ip6 route +grcli show trace EOF set -x @@ -53,3 +54,5 @@ if [ "$run_grout" = true ]; then grout $grout_flags & fi socat FILE:/dev/null UNIX-CONNECT:$GROUT_SOCK_PATH,retry=10 + +grcli set trace all From 36088604b455b917014bf52545c7565cd566c343 Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 11 Oct 2024 20:42:53 +0000 Subject: [PATCH 02/10] infra: trace api for control_input Use trace api to enable/disable packet tracing for control_input node. Signed-off-by: Christophe Fontaine --- modules/infra/api/trace.c | 10 ++++++++-- modules/infra/datapath/control_input.c | 3 +++ modules/infra/datapath/gr_trace.h | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/modules/infra/api/trace.c b/modules/infra/api/trace.c index 795f5f33..c338da1f 100644 --- a/modules/infra/api/trace.c +++ b/modules/infra/api/trace.c @@ -8,9 +8,15 @@ #include #include +#include + #define TRACE_STR (6 * 1024) // 64 nodes, 80 cols per node: ~5120 bytes. -static bool trace_enabled = true; +static atomic_bool trace_enabled = false; + +bool gr_trace_enabled() { + return trace_enabled; +} static void iface_callback(iface_event_t event, struct iface *iface) { if (event == IFACE_EVENT_POST_ADD && trace_enabled) @@ -31,7 +37,7 @@ static struct api_out set_trace(const void *request, void **) { iface->flags &= ~GR_IFACE_F_PACKET_TRACE; } else { - trace_enabled = req->enabled; + atomic_store(&trace_enabled, req->enabled); while ((iface = iface_next(GR_IFACE_TYPE_UNDEF, iface)) != NULL) { if (req->enabled) iface->flags |= GR_IFACE_F_PACKET_TRACE; diff --git a/modules/infra/datapath/control_input.c b/modules/infra/datapath/control_input.c index c2944763..703c627f 100644 --- a/modules/infra/datapath/control_input.c +++ b/modules/infra/datapath/control_input.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -73,6 +74,8 @@ static uint16_t control_input_process( for (unsigned i = 0; i < n; i++) { mbuf = rte_pktmbuf_alloc(mp); if (mbuf) { + if (unlikely(gr_trace_enabled())) + gr_trace_begin(node, mbuf, 0); control_input_mbuf_data(mbuf)->data = msg[i].data; rte_node_enqueue_x1(graph, node, control_input_edges[msg[i].type], mbuf); } diff --git a/modules/infra/datapath/gr_trace.h b/modules/infra/datapath/gr_trace.h index 9c2357f0..bf9816ed 100644 --- a/modules/infra/datapath/gr_trace.h +++ b/modules/infra/datapath/gr_trace.h @@ -18,4 +18,6 @@ void gr_trace_aggregate(struct rte_mbuf *m); int trace_print(char *buf, size_t len); void trace_clear(void); + +bool gr_trace_enabled(void); #endif From ab91d94d181aca079c5132605bdf79c9e4f286a6 Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Thu, 17 Oct 2024 12:08:11 +0000 Subject: [PATCH 03/10] api: add ethertype and ip proto format functions Add ethertype and ip proto format functions Signed-off-by: Christophe Fontaine --- api/gr_net_types.h | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/api/gr_net_types.h b/api/gr_net_types.h index 98f84c56..e87c27ef 100644 --- a/api/gr_net_types.h +++ b/api/gr_net_types.h @@ -137,4 +137,52 @@ static inline int ip6_net_format(const struct ip6_net *net, char *buf, size_t le return snprintf(buf + n, len - n, "/%u", net->prefixlen); } +static inline int ethertype_format(const rte_be16_t ethertype, char *buf, size_t len) { + static const char *ethertypes[UINT16_MAX + 1] = { + [RTE_BE16(RTE_ETHER_TYPE_IPV4)] = "IP", + [RTE_BE16(RTE_ETHER_TYPE_IPV6)] = "IP6", + [RTE_BE16(RTE_ETHER_TYPE_ARP)] = "ARP", + [RTE_BE16(RTE_ETHER_TYPE_VLAN)] = "VLAN", + [RTE_BE16(RTE_ETHER_TYPE_QINQ)] = "QINQ", + [RTE_BE16(RTE_ETHER_TYPE_SLOW)] = "LACP", + [RTE_BE16(RTE_ETHER_TYPE_LLDP)] = "LLDP", + [RTE_BE16(RTE_ETHER_TYPE_MPLS)] = "MPLS", + [RTE_BE16(RTE_ETHER_TYPE_1588)] = "PTP", + }; + if (ethertypes[ethertype]) + return snprintf(buf, len, "%s", ethertypes[ethertype]); + else + return snprintf(buf, len, "ethertype %#04x", rte_be_to_cpu_16(ethertype)); +} + +static inline int nextproto_format(const uint8_t proto, char *buf, size_t len) { + static const char *protos[UINT8_MAX + 1] = { + [IPPROTO_HOPOPTS] = "IPv6 Hop-by-Hop", + [IPPROTO_ICMP] = "ICMP", + [IPPROTO_IGMP] = "IGMP", + [IPPROTO_IPIP] = "IP in IP", + [IPPROTO_TCP] = "TCP", + [IPPROTO_UDP] = "UDP", + [IPPROTO_IPV6] = "IPv6 Header", + [IPPROTO_ROUTING] = "IPv6 Routing Header", + [IPPROTO_FRAGMENT] = "IPv6 Fragment Header", + [IPPROTO_GRE] = "GRE", + [IPPROTO_ESP] = "ESP", + [IPPROTO_AH] = "Authentication Header", + [IPPROTO_MTP] = "Multicast Transport Protocol", + [IPPROTO_ICMPV6] = "IPv6 ICMP", + [IPPROTO_NONE] = "IPv6 No Next Header", + [IPPROTO_DSTOPTS] = "IPv6 Destination Options", + [IPPROTO_SCTP] = "SCTP", + [IPPROTO_MH] = "IPv6 Mobility Header", + [IPPROTO_UDPLITE] = "UDP Lite", + [IPPROTO_MPLS] = "MPLS In IP", + [IPPROTO_ETHERNET] = "Ethernet-within-IPv6 Encapsulation", + [IPPROTO_RAW] = "Raw IP Packets", + }; + if (protos[proto]) + return snprintf(buf, len, "%s", protos[proto]); + else + return snprintf(buf, len, "%d", proto); +} #endif From 35e10e56aa54e14486129e0c894a5c5b2a5f75fc Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 11 Oct 2024 09:49:12 +0000 Subject: [PATCH 04/10] eth: add tracing for ethernet in/out nodes Implement tracing functions for ethernet nodes. For vlan interfaces, enable tracing according to the user intent. Signed-off-by: Christophe Fontaine --- modules/infra/datapath/eth_input.c | 21 +++++++++++ modules/infra/datapath/eth_output.c | 46 +++++++++++++++++++++++++ modules/infra/datapath/eth_trace_priv.h | 19 ++++++++++ 3 files changed, 86 insertions(+) create mode 100644 modules/infra/datapath/eth_trace_priv.h diff --git a/modules/infra/datapath/eth_input.c b/modules/infra/datapath/eth_input.c index a690c887..09cc2f44 100644 --- a/modules/infra/datapath/eth_input.c +++ b/modules/infra/datapath/eth_input.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2024 Robin Jarry +#include "eth_trace_priv.h" #include "gr_eth_input.h" #include #include +#include #include #include @@ -96,6 +98,24 @@ eth_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u eth_in->eth_dst = ETH_DST_OTHER; } next: + if (unlikely(gr_mbuf_trace_is_set(m)) + || (vlan_iface && vlan_iface->flags & GR_IFACE_F_PACKET_TRACE)) { + struct trace_ether_data *t; + + if (gr_mbuf_trace_is_set(m)) + t = gr_trace_add(node, m, sizeof(*t)); + else + t = gr_trace_begin(node, m, sizeof(*t)); + + if (t) { + memcpy(&t->dst, ð->dst_addr, sizeof(t->dst)); + memcpy(&t->src, ð->src_addr, sizeof(t->dst)); + t->ether_type = eth_type; + t->vlan_id = vlan_id; + t->iface_id = eth_in->iface->id; + } + } + rte_node_enqueue_x1(graph, node, edge, m); } return nb_objs; @@ -115,6 +135,7 @@ static struct rte_node_register node = { static struct gr_node_info info = { .node = &node, + .ext_funcs.format_trace = format_eth, }; GR_NODE_REGISTER(info); diff --git a/modules/infra/datapath/eth_output.c b/modules/infra/datapath/eth_output.c index 399488c6..4bae7ef7 100644 --- a/modules/infra/datapath/eth_output.c +++ b/modules/infra/datapath/eth_output.c @@ -1,13 +1,16 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2024 Robin Jarry +#include "eth_trace_priv.h" #include "gr_datapath.h" #include "gr_eth_output.h" #include #include #include +#include #include +#include #include #include @@ -22,6 +25,35 @@ enum { NB_EDGES, }; +int format_eth(void *data, char *buf, size_t len) { + struct trace_ether_data *t = data; + const struct iface *iface = iface_from_id(t->iface_id); + const char *ifname = iface ? iface->name : "[deleted]"; + int c, s; + + if ((c = ethertype_format(t->ether_type, buf, len)) < 0) + return c; + + if ((s = snprintf( + buf + c, + len - c, + " " ETH_ADDR_FMT " -> " ETH_ADDR_FMT " iface %s", + ETH_ADDR_SPLIT(&t->src), + ETH_ADDR_SPLIT(&t->dst), + ifname + )) + < 0) + return s; + c += s; + + if (t->vlan_id != 0) { + if ((s = snprintf(buf + c, len - c, " vlan %d", t->vlan_id)) < 0) + return s; + c += s; + } + return c; +} + static uint16_t eth_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { const struct rte_ether_addr *src_mac; @@ -35,6 +67,7 @@ eth_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, for (uint16_t i = 0; i < nb_objs; i++) { mbuf = objs[i]; priv = eth_output_mbuf_data(mbuf); + sub = NULL; switch (priv->iface->type_id) { case GR_IFACE_TYPE_VLAN: @@ -71,6 +104,18 @@ eth_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, mbuf->port = port->port_id; if (unlikely(packet_trace_enabled)) trace_packet("tx", priv->iface->name, mbuf); + + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_ether_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + if (t) { + t->dst = eth->dst_addr; + t->src = eth->src_addr; + t->ether_type = eth->ether_type; + t->iface_id = priv->iface->id; + t->vlan_id = sub ? sub->vlan_id : 0; + } + } + rte_node_enqueue_x1(graph, node, TX, mbuf); } @@ -92,6 +137,7 @@ static struct rte_node_register node= { static struct gr_node_info info = { .node = &node, + .ext_funcs.format_trace = format_eth, }; GR_NODE_REGISTER(info); diff --git a/modules/infra/datapath/eth_trace_priv.h b/modules/infra/datapath/eth_trace_priv.h new file mode 100644 index 00000000..0c5a1692 --- /dev/null +++ b/modules/infra/datapath/eth_trace_priv.h @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024 Christophe Fontaine + +#include + +#ifndef _ETH_TRACE_PRIV_H +#define _ETH_TRACE_PRIV_H + +struct trace_ether_data { + struct rte_ether_addr dst; + struct rte_ether_addr src; + rte_be16_t ether_type; + uint16_t vlan_id; + uint16_t iface_id; +}; + +int format_eth(void *data, char *buf, size_t len); + +#endif From 0f6bd285c2907deee84e8ef46f24d8b179e1dd6f Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 11 Oct 2024 09:50:48 +0000 Subject: [PATCH 05/10] arp: add tracing for arp nodes Implement tracing function for arp input/output/output_request. Signed-off-by: Christophe Fontaine --- modules/ip/datapath/arp_input.c | 23 ++++++++++++++++ modules/ip/datapath/arp_output_reply.c | 35 ++++++++++++++++++++++++ modules/ip/datapath/arp_output_request.c | 6 ++++ 3 files changed, 64 insertions(+) diff --git a/modules/ip/datapath/arp_input.c b/modules/ip/datapath/arp_input.c index 56ecaa4d..210889ab 100644 --- a/modules/ip/datapath/arp_input.c +++ b/modules/ip/datapath/arp_input.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,18 @@ static inline void update_nexthop( rte_spinlock_unlock(&nh->lock); } +struct trace_arp_input_data { + uint16_t opcode; + ip4_addr_t sip; +}; + +static int format_arp_input(void *data, char *buf, size_t len) { + struct trace_arp_input_data *t = data; + return snprintf( + buf, len, "sip " IP4_ADDR_FMT " opcode %d", IP4_ADDR_SPLIT(&t->sip), t->opcode + ); +} + static uint16_t arp_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { struct nexthop *remote, *local; @@ -82,6 +95,7 @@ arp_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u for (uint16_t i = 0; i < nb_objs; i++) { mbuf = objs[i]; + sip = 0; // ARP protocol sanity checks. arp = rte_pktmbuf_mtod(mbuf, struct rte_arp_hdr *); @@ -133,6 +147,14 @@ arp_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u arp_data->local = local; arp_data->remote = remote; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_arp_input_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + if (t) { + t->opcode = rte_be_to_cpu_16(arp->arp_opcode); + t->sip = sip; + } + } + rte_node_enqueue_x1(graph, node, edge, mbuf); } @@ -163,6 +185,7 @@ static struct rte_node_register node = { static struct gr_node_info info = { .node = &node, .register_callback = arp_input_register, + .ext_funcs.format_trace = format_arp_input, }; GR_NODE_REGISTER(info); diff --git a/modules/ip/datapath/arp_output_reply.c b/modules/ip/datapath/arp_output_reply.c index 8951e681..6d245a8c 100644 --- a/modules/ip/datapath/arp_output_reply.c +++ b/modules/ip/datapath/arp_output_reply.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,24 @@ enum { EDGE_COUNT, }; +struct trace_arp_output_reply_data { + ip4_addr_t sip; + ip4_addr_t tip; + uint8_t opcode; +}; + +static int format_arp_output_reply(void *data, char *buf, size_t len) { + struct trace_arp_output_reply_data *t = data; + return snprintf( + buf, + len, + "opcode %d sip " IP4_ADDR_FMT " tip " IP4_ADDR_FMT, + t->opcode, + IP4_ADDR_SPLIT(&t->sip), + IP4_ADDR_SPLIT(&t->tip) + ); +} + static uint16_t arp_output_reply_process( struct rte_graph *graph, struct rte_node *node, @@ -39,6 +58,7 @@ static uint16_t arp_output_reply_process( for (uint16_t i = 0; i < nb_objs; i++) { mbuf = objs[i]; arp_data = arp_mbuf_data(mbuf); + if (arp_data->local == NULL || arp_data->remote == NULL) { // mbuf is not an ARP request edge = ERROR; @@ -71,6 +91,20 @@ static uint16_t arp_output_reply_process( edge = OUTPUT; num++; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_arp_output_reply_data *t; + t = gr_trace_add(node, mbuf, sizeof(*t)); + if (t) { + if (edge == OUTPUT) { + t->tip = arp->arp_data.arp_tip; + t->sip = arp->arp_data.arp_sip; + } else { + t->sip = 0; + t->tip = 0; + t->opcode = 0; + } + } + } rte_node_enqueue_x1(graph, node, edge, mbuf); } @@ -89,6 +123,7 @@ static struct rte_node_register node = { static struct gr_node_info info = { .node = &node, + .ext_funcs.format_trace = format_arp_output_reply, }; GR_NODE_REGISTER(info); diff --git a/modules/ip/datapath/arp_output_request.c b/modules/ip/datapath/arp_output_request.c index 2028698c..5c07f415 100644 --- a/modules/ip/datapath/arp_output_request.c +++ b/modules/ip/datapath/arp_output_request.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,11 @@ static uint16_t arp_output_request_process( mbuf = objs[i]; nh = (struct nexthop *)control_input_mbuf_data(mbuf)->data; local = ip4_addr_get_preferred(nh->iface_id, nh->ip); + + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + gr_trace_add(node, mbuf, 0); + } + if (local == NULL) { edge = ERROR; goto next; From a622b9de1352f70cbcb5d31c48a5217275bf009e Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 11 Oct 2024 09:51:36 +0000 Subject: [PATCH 06/10] icmp: add tracing for icmp_input node Implement tracing for icmp_node node Signed-off-by: Christophe Fontaine --- modules/ip/datapath/icmp_input.c | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/modules/ip/datapath/icmp_input.c b/modules/ip/datapath/icmp_input.c index 34354c72..b5a235c5 100644 --- a/modules/ip/datapath/icmp_input.c +++ b/modules/ip/datapath/icmp_input.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -26,6 +27,49 @@ enum { static control_output_cb_t icmp_cb[UINT8_MAX]; +struct trace_icmp_data { + uint16_t code; + uint16_t type; +}; + +static const char *icmp_to_str(uint8_t type, uint8_t code) { + const char *icmp_types[UINT8_MAX] = { + [RTE_ICMP_TYPE_ECHO_REPLY] = "Echo Reply", + [RTE_ICMP_TYPE_ECHO_REQUEST] = "Echo Request", + [RTE_ICMP_TYPE_REDIRECT] = "Redirect", + [RTE_ICMP_TYPE_DEST_UNREACHABLE] = "Destination Unreachable", + [RTE_ICMP_TYPE_TTL_EXCEEDED] = "Time to live Exceeded", + }; + + const char *ttl_exceeded[UINT8_MAX] = { + [RTE_ICMP_CODE_TTL_EXCEEDED] = "Time to Live exceeded in Transit", + [RTE_ICMP_CODE_TTL_FRAG] = "Fragment Reassembly Time Exceeded", + }; + + const char *dest_unreachable[UINT8_MAX] = { + [RTE_ICMP_CODE_UNREACH_NET] = "Network Unreachable", + [RTE_ICMP_CODE_UNREACH_HOST] = "Host Unreachable", + [RTE_ICMP_CODE_UNREACH_PROTO] = "Protocol Unreachable", + [RTE_ICMP_CODE_UNREACH_PORT] = "Port Unreachable", + [RTE_ICMP_CODE_UNREACH_FRAG] = "Fragmentation Needed and Don't Fragment was Set", + [RTE_ICMP_CODE_UNREACH_SRC] = "Source Route Failed", + }; + + switch (type) { + case RTE_ICMP_TYPE_DEST_UNREACHABLE: + return dest_unreachable[code]; + case RTE_ICMP_TYPE_TTL_EXCEEDED: + return ttl_exceeded[code]; + default: + return icmp_types[type]; + } +} + +static int format_icmp_input(void *data, char *buf, size_t len) { + struct trace_icmp_data *d = data; + return snprintf(buf, len, "%s", icmp_to_str(d->type, d->code)); +} + static uint16_t icmp_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { struct ip_local_mbuf_data *ip_data; @@ -44,6 +88,14 @@ icmp_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, goto next; } + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_icmp_data *d = gr_trace_add(node, mbuf, sizeof(*d)); + if (d) { + d->code = icmp->icmp_code; + d->type = icmp->icmp_type; + } + } + if (icmp->icmp_type == RTE_ICMP_TYPE_ECHO_REQUEST) { if (icmp->icmp_code != 0) { edge = INVALID; @@ -99,6 +151,7 @@ static struct rte_node_register icmp_input_node = { static struct gr_node_info icmp_input_info = { .node = &icmp_input_node, .register_callback = icmp_input_register, + .ext_funcs.format_trace = format_icmp_input, }; GR_NODE_REGISTER(icmp_input_info); From 0cb51486713188eca56ac34df62391cdab107793 Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 11 Oct 2024 09:53:29 +0000 Subject: [PATCH 07/10] ip: add tracing for ip nodes Implement tracing functions for ip nodes. Update tests to enable and show traces. Signed-off-by: Christophe Fontaine --- modules/ip/datapath/gr_ip4_datapath.h | 9 ++++++++ modules/ip/datapath/ip_error.c | 5 +++++ modules/ip/datapath/ip_forward.c | 12 +++++++++++ modules/ip/datapath/ip_input.c | 31 +++++++++++++++++++++++++++ modules/ip/datapath/ip_local.c | 5 +++++ modules/ip/datapath/ip_output.c | 11 +++++++++- 6 files changed, 72 insertions(+), 1 deletion(-) diff --git a/modules/ip/datapath/gr_ip4_datapath.h b/modules/ip/datapath/gr_ip4_datapath.h index 3e03d6bd..ad68a033 100644 --- a/modules/ip/datapath/gr_ip4_datapath.h +++ b/modules/ip/datapath/gr_ip4_datapath.h @@ -67,4 +67,13 @@ int icmp_local_send( void icmp_input_register_callback(uint8_t icmp_type, control_output_cb_t cb); +struct trace_ip_data { + ip4_addr_t src; + ip4_addr_t dst; + uint8_t proto; + uint8_t ttl; +}; + +int format_ip_data(void *data, char *buf, size_t); + #endif diff --git a/modules/ip/datapath/ip_error.c b/modules/ip/datapath/ip_error.c index 2f539332..68f67113 100644 --- a/modules/ip/datapath/ip_error.c +++ b/modules/ip/datapath/ip_error.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -39,6 +40,7 @@ ip_error_process(struct rte_graph *graph, struct rte_node *node, void **objs, ui ip = rte_pktmbuf_mtod(mbuf, struct rte_ipv4_hdr *); icmp = (struct rte_icmp_hdr *)rte_pktmbuf_prepend(mbuf, sizeof(*icmp)); + if (unlikely(icmp == NULL)) { edge = NO_HEADROOM; goto next; @@ -73,6 +75,9 @@ ip_error_process(struct rte_graph *graph, struct rte_node *node, void **objs, ui edge = ICMP_OUTPUT; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + gr_trace_add(node, mbuf, 0); + } rte_node_enqueue_x1(graph, node, edge, mbuf); } diff --git a/modules/ip/datapath/ip_forward.c b/modules/ip/datapath/ip_forward.c index 9df66fd7..e5efef90 100644 --- a/modules/ip/datapath/ip_forward.c +++ b/modules/ip/datapath/ip_forward.c @@ -2,6 +2,8 @@ // Copyright (c) 2024 Robin Jarry #include +#include +#include #include #include @@ -33,6 +35,15 @@ ip_forward_process(struct rte_graph *graph, struct rte_node *node, void **objs, csum = ip->hdr_checksum + RTE_BE16(0x0100); csum += csum >= 0xffff; ip->hdr_checksum = csum; + + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_ip_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + t->src = ip->src_addr; + t->dst = ip->dst_addr; + t->proto = ip->next_proto_id; + t->ttl = ip->time_to_live; + } + rte_node_enqueue_x1(graph, node, OUTPUT, mbuf); } @@ -53,6 +64,7 @@ static struct rte_node_register forward_node = { static struct gr_node_info info = { .node = &forward_node, + .ext_funcs.format_trace = format_ip_data, }; GR_NODE_REGISTER(info); diff --git a/modules/ip/datapath/ip_input.c b/modules/ip/datapath/ip_input.c index 58f89c6f..f1f5c46f 100644 --- a/modules/ip/datapath/ip_input.c +++ b/modules/ip/datapath/ip_input.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -26,6 +28,27 @@ enum edges { EDGE_COUNT, }; +int format_ip_data(void *data, char *buf, size_t len) { + struct trace_ip_data *t = data; + int c, s; + + if ((c = snprintf( + buf, + len, + IP4_ADDR_FMT " -> " IP4_ADDR_FMT " ttl %d nextproto: ", + IP4_ADDR_SPLIT(&t->src), + IP4_ADDR_SPLIT(&t->dst), + t->ttl + )) + < 0) + return c; + + if ((s = nextproto_format(t->proto, buf + c, len - c)) < 0) + return s; + + return c + s; +} + static uint16_t ip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { struct eth_input_mbuf_data *e; @@ -111,6 +134,13 @@ ip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, ui else edge = FORWARD; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_ip_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + t->src = ip->src_addr; + t->dst = ip->dst_addr; + t->proto = ip->next_proto_id; + t->ttl = ip->time_to_live; + } // Store the resolved next hop for ip_output to avoid a second route lookup. d->nh = nh; d->input_iface = iface; @@ -143,6 +173,7 @@ static struct rte_node_register input_node = { static struct gr_node_info info = { .node = &input_node, .register_callback = ip_input_register, + .ext_funcs.format_trace = format_ip_data, }; GR_NODE_REGISTER(info); diff --git a/modules/ip/datapath/ip_local.c b/modules/ip/datapath/ip_local.c index 912833ad..d8c9cb29 100644 --- a/modules/ip/datapath/ip_local.c +++ b/modules/ip/datapath/ip_local.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,10 @@ static uint16_t ip_input_local_process( for (i = 0; i < nb_objs; i++) { mbuf = objs[i]; ip = rte_pktmbuf_mtod(mbuf, struct rte_ipv4_hdr *); + + if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_add(node, mbuf, 0); + edge = edges[ip->next_proto_id]; if (edge != UNKNOWN_PROTO) { const struct iface *iface = ip_output_mbuf_data(mbuf)->input_iface; diff --git a/modules/ip/datapath/ip_output.c b/modules/ip/datapath/ip_output.c index d4d7e9e2..42ae4d95 100644 --- a/modules/ip/datapath/ip_output.c +++ b/modules/ip/datapath/ip_output.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -86,8 +87,8 @@ ip_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, u for (i = 0; i < nb_objs; i++) { mbuf = objs[i]; ip = rte_pktmbuf_mtod(mbuf, struct rte_ipv4_hdr *); - nh = ip_output_mbuf_data(mbuf)->nh; + if (nh == NULL) { edge = NO_ROUTE; goto next; @@ -145,6 +146,13 @@ ip_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, u eth_data->iface = iface; sent++; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_ip_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + t->src = ip->src_addr; + t->dst = ip->dst_addr; + t->proto = ip->next_proto_id; + t->ttl = ip->time_to_live; + } rte_node_enqueue_x1(graph, node, edge, mbuf); } @@ -165,6 +173,7 @@ static struct rte_node_register output_node = { static struct gr_node_info info = { .node = &output_node, + .ext_funcs.format_trace = format_ip_data, }; GR_NODE_REGISTER(info); From 906c4166e0a0ddb005bbd22cc0c853e22079c8be Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 11 Oct 2024 11:05:32 +0000 Subject: [PATCH 08/10] ipip: add tracing for ipip nodes Implement tracing for ipip nodes Signed-off-by: Christophe Fontaine --- modules/ipip/datapath_in.c | 8 ++++++++ modules/ipip/datapath_out.c | 4 ++++ 2 files changed, 12 insertions(+) diff --git a/modules/ipip/datapath_in.c b/modules/ipip/datapath_in.c index e5736ba9..34984b01 100644 --- a/modules/ipip/datapath_in.c +++ b/modules/ipip/datapath_in.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -61,7 +62,14 @@ ipip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, eth_data->iface = ipip; eth_data->eth_dst = ETH_DST_LOCAL; edge = IP_INPUT; + next: + // Even if ipip is not a source node, the user may want to trace + // packets from this tunnel interface + if (unlikely(ipip && ipip->flags & GR_IFACE_F_PACKET_TRACE)) + gr_trace_begin(node, mbuf, 0); + else if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_add(node, mbuf, 0); rte_node_enqueue_x1(graph, node, edge, mbuf); } diff --git a/modules/ipip/datapath_out.c b/modules/ipip/datapath_out.c index c4cec872..828c3aea 100644 --- a/modules/ipip/datapath_out.c +++ b/modules/ipip/datapath_out.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -68,7 +69,10 @@ ipip_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, // Resolve nexthop for the encapsulated packet. ip_data->nh = ip4_route_lookup(iface->vrf_id, ipip->remote); edge = IP_OUTPUT; + next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_add(node, mbuf, 0); rte_node_enqueue_x1(graph, node, edge, mbuf); } From bf4120e5c3f4dfc15ada8284632e918c83a8377c Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 11 Oct 2024 12:26:57 +0000 Subject: [PATCH 09/10] ip6: add tracing for ip6 nodes Implement tracing for ip6/icmp6/ndp nodes. Signed-off-by: Christophe Fontaine --- modules/ip6/datapath/gr_ip6_datapath.h | 9 ++++ modules/ip6/datapath/icmp6_input.c | 27 ++++++++++++ modules/ip6/datapath/icmp6_output.c | 4 ++ modules/ip6/datapath/ip6_error.c | 22 ++++++++++ modules/ip6/datapath/ip6_forward.c | 3 ++ modules/ip6/datapath/ip6_input.c | 58 ++++++++++++++++++++++++++ modules/ip6/datapath/ip6_local.c | 4 ++ modules/ip6/datapath/ip6_output.c | 9 ++++ modules/ip6/datapath/ndp_na_input.c | 6 +++ modules/ip6/datapath/ndp_ns_input.c | 3 ++ modules/ip6/datapath/ndp_ns_output.c | 3 ++ 11 files changed, 148 insertions(+) diff --git a/modules/ip6/datapath/gr_ip6_datapath.h b/modules/ip6/datapath/gr_ip6_datapath.h index 3514c8e5..38b8dadd 100644 --- a/modules/ip6/datapath/gr_ip6_datapath.h +++ b/modules/ip6/datapath/gr_ip6_datapath.h @@ -65,4 +65,13 @@ void ndp_update_nexthop( const struct rte_ether_addr *mac ); +struct trace_ip6_data { + struct rte_ipv6_addr src; + struct rte_ipv6_addr dst; + uint8_t hop_limits; + uint8_t proto; +}; + +int format_ip6_data(void *data, char *buf, size_t len); + #endif diff --git a/modules/ip6/datapath/icmp6_input.c b/modules/ip6/datapath/icmp6_input.c index e8ef977b..a0b6da0f 100644 --- a/modules/ip6/datapath/icmp6_input.c +++ b/modules/ip6/datapath/icmp6_input.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -24,6 +25,26 @@ enum { EDGE_COUNT, }; +struct trace_icmp6_data { + uint16_t type; +}; + +static int format_icmp6_data(void *data, char *buf, size_t len) { + struct trace_icmp6_data *t = data; + static const char *ICMP6_STR[UINT16_MAX] = { + [ICMP6_TYPE_ECHO_REQUEST] = "Echo Request", + [ICMP6_TYPE_ECHO_REPLY] = "Echo Reply", + [ICMP6_TYPE_NEIGH_SOLICIT] = "Neighbor Solicitation", + [ICMP6_TYPE_NEIGH_ADVERT] = "Neighbor Advertisement", + [ICMP6_TYPE_ROUTER_SOLICIT] = "Router Solicitation", + [ICMP6_TYPE_ROUTER_ADVERT] = "Router Advertisement", + }; + if (ICMP6_STR[t->type]) + return snprintf(buf, len, "%s", ICMP6_STR[t->type]); + else + return snprintf(buf, len, "type: %d", t->type); +} + static uint16_t icmp6_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { struct ip6_local_mbuf_data *d; @@ -37,6 +58,11 @@ icmp6_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, icmp6 = rte_pktmbuf_mtod(mbuf, struct icmp6 *); d = ip6_local_mbuf_data(mbuf); + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_icmp6_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + t->type = icmp6->type; + } + switch (icmp6->type) { case ICMP6_TYPE_ECHO_REQUEST: if (icmp6->code != 0) { @@ -91,6 +117,7 @@ static struct rte_node_register icmp6_input_node = { static struct gr_node_info icmp6_input_info = { .node = &icmp6_input_node, .register_callback = icmp6_input_register, + .ext_funcs.format_trace = format_icmp6_data, }; GR_NODE_REGISTER(icmp6_input_info); diff --git a/modules/ip6/datapath/icmp6_output.c b/modules/ip6/datapath/icmp6_output.c index 82f65f89..170f6195 100644 --- a/modules/ip6/datapath/icmp6_output.c +++ b/modules/ip6/datapath/icmp6_output.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -61,6 +62,9 @@ static uint16_t icmp6_output_process( o->input_iface = iface; edge = OUTPUT; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_add(node, mbuf, 0); + rte_node_enqueue_x1(graph, node, edge, mbuf); } diff --git a/modules/ip6/datapath/ip6_error.c b/modules/ip6/datapath/ip6_error.c index 085b595d..ebce0819 100644 --- a/modules/ip6/datapath/ip6_error.c +++ b/modules/ip6/datapath/ip6_error.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -20,6 +21,20 @@ enum edges { EDGE_COUNT, }; +struct trace_ip6_error_data { + icmp6_type_t icmp_type; +}; + +static int format_ip6_error_data(void *data, char *buf, size_t len) { + struct trace_ip6_error_data *d = data; + static const char *icmp_error[UINT16_MAX] = { + [ICMP6_ERR_DEST_UNREACH] = "Destination unreachable", + [ICMP6_ERR_TTL_EXCEEDED] = "TTL exceeded", + }; + + return snprintf(buf, len, "%s", icmp_error[d->icmp_type]); +} + static uint16_t ip6_error_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { struct icmp6_err_dest_unreach *du; @@ -71,6 +86,11 @@ ip6_error_process(struct rte_graph *graph, struct rte_node *node, void **objs, u break; } + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_ip6_error_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + t->icmp_type = icmp_type; + } + icmp6 = (struct icmp6 *)rte_pktmbuf_prepend(mbuf, sizeof(*icmp6)); if (unlikely(icmp6 == NULL || ip == NULL)) { edge = NO_HEADROOM; @@ -138,10 +158,12 @@ static struct rte_node_register ttl_exceeded_node = { static struct gr_node_info dest_unreach_info = { .node = &dest_unreach_node, + .ext_funcs.format_trace = format_ip6_error_data, }; static struct gr_node_info ttl_exceeded_info = { .node = &ttl_exceeded_node, + .ext_funcs.format_trace = format_ip6_error_data, }; GR_NODE_REGISTER(dest_unreach_info); diff --git a/modules/ip6/datapath/ip6_forward.c b/modules/ip6/datapath/ip6_forward.c index 0eafac3f..7d781535 100644 --- a/modules/ip6/datapath/ip6_forward.c +++ b/modules/ip6/datapath/ip6_forward.c @@ -2,6 +2,7 @@ // Copyright (c) 2024 Robin Jarry #include +#include #include #include @@ -23,6 +24,8 @@ ip6_forward_process(struct rte_graph *graph, struct rte_node *node, void **objs, for (i = 0; i < nb_objs; i++) { mbuf = objs[i]; ip = rte_pktmbuf_mtod(mbuf, struct rte_ipv6_hdr *); + if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_add(node, mbuf, 0); if (ip->hop_limits <= 1) { rte_node_enqueue_x1(graph, node, TTL_EXCEEDED, mbuf); diff --git a/modules/ip6/datapath/ip6_input.c b/modules/ip6/datapath/ip6_input.c index 05ec54c0..9c27fce2 100644 --- a/modules/ip6/datapath/ip6_input.c +++ b/modules/ip6/datapath/ip6_input.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -28,6 +29,55 @@ enum edges { EDGE_COUNT, }; +int format_ip6_data(void *data, char *buf, size_t len) { + struct trace_ip6_data *t = data; + char src[INET6_ADDRSTRLEN]; + char dst[INET6_ADDRSTRLEN]; + + static const char *protos[UINT8_MAX] = { + [0] = "IPv6 Hop-by-Hop", + [1] = "ICMP", + [2] = "IGMP", + [4] = "IP in IP", + [6] = "TCP", + [17] = "UDP", + [27] = "Reliable Data Protocol", + [41] = "IPv6 Encapsulation", + [43] = "IPv6 Routing Header", + [44] = "IPv6 Fragment Header", + [47] = "GRE", + [50] = "ESP", + [51] = "Authentication Header", + [58] = "IPv6 ICMP", + [59] = "IPv6 No Next Header", + [60] = "IPv6 Destination Options", + [89] = "OSPF", + [112] = "VRRP", + [132] = "SCTP", + [136] = "UDP Lite", + [137] = "MPLS In IP", + [145] = "NSH", + }; + + inet_ntop(AF_INET6, &t->src, src, sizeof(src)); + inet_ntop(AF_INET6, &t->dst, dst, sizeof(dst)); + + if (protos[t->proto]) + return snprintf( + buf, + len, + "%s -> %s next proto %s ttl %d", + src, + dst, + protos[t->proto], + t->hop_limits + ); + else + return snprintf( + buf, len, "%s -> %s next proto %d ttl %d", src, dst, t->proto, t->hop_limits + ); +} + static uint16_t ip6_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, uint16_t nb_objs) { struct ip6_output_mbuf_data *d; @@ -110,6 +160,13 @@ ip6_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, u edge = FORWARD; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_ip6_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + t->src = ip->src_addr; + t->dst = ip->dst_addr; + t->proto = ip->proto; + t->hop_limits = ip->hop_limits; + } // Store the resolved next hop for ip6_output to avoid a second route lookup. d->nh = nh; rte_node_enqueue_x1(graph, node, edge, mbuf); @@ -143,6 +200,7 @@ static struct rte_node_register input_node = { static struct gr_node_info info = { .node = &input_node, .register_callback = ip6_input_register, + .ext_funcs.format_trace = format_ip6_data, }; GR_NODE_REGISTER(info); diff --git a/modules/ip6/datapath/ip6_local.c b/modules/ip6/datapath/ip6_local.c index 7bef3863..0b881a58 100644 --- a/modules/ip6/datapath/ip6_local.c +++ b/modules/ip6/datapath/ip6_local.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,9 @@ static uint16_t ip6_input_local_process( break; } next: + if (unlikely(gr_mbuf_trace_is_set(m))) + gr_trace_add(node, m, 0); + rte_node_enqueue_x1(graph, node, edge, m); } diff --git a/modules/ip6/datapath/ip6_output.c b/modules/ip6/datapath/ip6_output.c index 6f727d75..dfb3ff31 100644 --- a/modules/ip6/datapath/ip6_output.c +++ b/modules/ip6/datapath/ip6_output.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -150,6 +151,13 @@ ip6_output_process(struct rte_graph *graph, struct rte_node *node, void **objs, eth_data->iface = iface; sent++; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) { + struct trace_ip6_data *t = gr_trace_add(node, mbuf, sizeof(*t)); + t->src = ip->src_addr; + t->dst = ip->dst_addr; + t->proto = ip->proto; + t->hop_limits = ip->hop_limits; + } rte_node_enqueue_x1(graph, node, edge, mbuf); } @@ -170,6 +178,7 @@ static struct rte_node_register output_node = { static struct gr_node_info info = { .node = &output_node, + .ext_funcs.format_trace = format_ip6_data, }; GR_NODE_REGISTER(info); diff --git a/modules/ip6/datapath/ndp_na_input.c b/modules/ip6/datapath/ndp_na_input.c index b4baea71..c69ab381 100644 --- a/modules/ip6/datapath/ndp_na_input.c +++ b/modules/ip6/datapath/ndp_na_input.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -135,9 +136,14 @@ static uint16_t ndp_na_input_process( ASSERT_NDP(lladdr_found); ndp_update_nexthop(graph, node, remote, iface, &lladdr); + + if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_aggregate(mbuf); rte_pktmbuf_free(mbuf); continue; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_add(node, mbuf, 0); rte_node_enqueue_x1(graph, node, next, mbuf); } diff --git a/modules/ip6/datapath/ndp_ns_input.c b/modules/ip6/datapath/ndp_ns_input.c index 314990c4..86eb2478 100644 --- a/modules/ip6/datapath/ndp_ns_input.c +++ b/modules/ip6/datapath/ndp_ns_input.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -160,6 +161,8 @@ static uint16_t ndp_ns_input_process( next = IP_OUTPUT; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_add(node, mbuf, 0); rte_node_enqueue_x1(graph, node, next, mbuf); } diff --git a/modules/ip6/datapath/ndp_ns_output.c b/modules/ip6/datapath/ndp_ns_output.c index 1726fd37..e41c5ef1 100644 --- a/modules/ip6/datapath/ndp_ns_output.c +++ b/modules/ip6/datapath/ndp_ns_output.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -98,6 +99,8 @@ static uint16_t ndp_ns_output_process( ip6_output_mbuf_data(mbuf)->nh = nh; next = OUTPUT; next: + if (unlikely(gr_mbuf_trace_is_set(mbuf))) + gr_trace_add(node, mbuf, 0); rte_node_enqueue_x1(graph, node, next, mbuf); } From e90543d4446cfb108f2906364c58a256ef3e5594 Mon Sep 17 00:00:00 2001 From: Christophe Fontaine Date: Fri, 18 Oct 2024 07:33:19 +0000 Subject: [PATCH 10/10] infra: add tracing for control_output node Implement tracing and trace aggregate for control output node. Signed-off-by: Christophe Fontaine --- modules/infra/datapath/control_output.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/infra/datapath/control_output.c b/modules/infra/datapath/control_output.c index 53435876..4fc6291d 100644 --- a/modules/infra/datapath/control_output.c +++ b/modules/infra/datapath/control_output.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -24,8 +25,13 @@ static uint16_t control_output_process( for (unsigned i = 0; i < n_objs; i++) { if (control_output_enqueue(objs[i]) < 0) rte_node_enqueue_x1(graph, node, ERROR, objs[i]); - else + else { sent++; + if (unlikely(gr_trace_enabled())) { + gr_trace_add(node, objs[i], 0); + gr_trace_aggregate(objs[i]); + } + } } if (sent > 0) control_output_done();