From: Mohsin Kazmi Date: Tue, 30 Sep 2025 12:15:35 +0000 (+0000) Subject: snort: add support for daq-vpp msg dump X-Git-Url: https://gerrit.fd.io/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F61%2F43761%2F2;p=vpp.git snort: add support for daq-vpp msg dump Type: feature To enable msg debugging: --daq-var debug-msg Signed-off-by: Mohsin Kazmi Change-Id: Ie2acd4aa763837c46d1908915ccf941743bf5b38 --- diff --git a/src/plugins/snort/CMakeLists.txt b/src/plugins/snort/CMakeLists.txt index 8a5b0003323..534baa72595 100644 --- a/src/plugins/snort/CMakeLists.txt +++ b/src/plugins/snort/CMakeLists.txt @@ -53,7 +53,7 @@ add_vpp_plugin(snort vpp-plugin-snort ) -add_library(daq_vpp SHARED daq/main.c daq/config.c daq/socket.c) +add_library(daq_vpp SHARED daq/main.c daq/config.c daq/socket.c daq/dump.c) set_target_properties(daq_vpp PROPERTIES SOVERSION ${VPP_LIB_VERSION}) target_compile_options (daq_vpp PRIVATE "-fvisibility=hidden") target_compile_options (daq_vpp PRIVATE "-DHAVE_VISIBILITY") diff --git a/src/plugins/snort/daq/config.c b/src/plugins/snort/daq/config.c index a615bc89286..2acccf43d09 100644 --- a/src/plugins/snort/daq/config.c +++ b/src/plugins/snort/daq/config.c @@ -56,6 +56,8 @@ daq_vpp_parse_config (daq_vpp_ctx_t *ctx, DAQ_ModuleConfig_h modcfg) { if (!strcmp (varKey, "debug")) vdm->debug = true; + else if (!strcmp (varKey, "debug-msg")) + vdm->debug_msg = vdm->debug = true; else if (!strcmp (varKey, "socket")) { vdm->socket_name = varValue; diff --git a/src/plugins/snort/daq/daq_vpp.h b/src/plugins/snort/daq/daq_vpp.h index dbe8a6f8d81..a4692d95730 100644 --- a/src/plugins/snort/daq/daq_vpp.h +++ b/src/plugins/snort/daq/daq_vpp.h @@ -39,6 +39,58 @@ if (daq_vpp_main.debug) \ printf ("%s: %s: " fmt "\n", "daq_vpp", __func__, ##__VA_ARGS__); +/* dump.c */ +char *daq_vpp_dump_pkt_hdr (const DAQ_PktHdr_t *hdr); +void daq_vpp_dump_msg_type (DAQ_MsgType type); +void daq_vpp_dump_msg (DAQ_Msg_h msg); +char *daq_vpp_dump_packet_data (const uint8_t *data, uint32_t len); + +#define DEBUG2(fmt, ...) \ + if (daq_vpp_main.debug_msg) \ + printf ("%s: %s: " fmt "\n", "daq_vpp", __func__, ##__VA_ARGS__); + +#define DEBUG_DUMP_MSG(msg) \ + if (daq_vpp_main.debug_msg) \ + { \ + printf ("%s: %s: MSG DUMP START \n", "daq_vpp", __func__); \ + if (msg) \ + daq_vpp_dump_msg (msg); \ + printf ("%s: %s: MSG DUMP END \n", "daq_vpp", __func__); \ + } + +#define DEBUG_DUMP_DATA_HEX(data, len) \ + if (daq_vpp_main.debug_msg) \ + { \ + printf ("%s: %s: MSG DUMP START \n", "daq_vpp", __func__); \ + char *data_buf = daq_vpp_dump_packet_data (data, len); \ + if (data_buf) \ + { \ + printf ("%s", data_buf); \ + free (data_buf); \ + } \ + printf ("%s: %s: MSG DUMP END \n", "daq_vpp", __func__); \ + } + +#define DEBUG_DUMP_MSG2(hdr, type, data, len) \ + if (daq_vpp_main.debug_msg) \ + { \ + printf ("%s: %s: MSG DUMP START \n", "daq_vpp", __func__); \ + char *pkt_hdr_buf = daq_vpp_dump_pkt_hdr (hdr); \ + char *data_buf = daq_vpp_dump_packet_data (data, len); \ + if (pkt_hdr_buf) \ + { \ + printf ("%s", pkt_hdr_buf); \ + free (pkt_hdr_buf); \ + } \ + daq_vpp_dump_msg_type (type); \ + if (data_buf) \ + { \ + printf ("%s", data_buf); \ + free (data_buf); \ + } \ + printf ("%s: %s: MSG DUMP END \n", "daq_vpp", __func__); \ + } + #define SET_ERROR(modinst, ...) \ daq_vpp_main.daq_base_api.set_errbuf (modinst, __VA_ARGS__) @@ -117,6 +169,7 @@ typedef struct _vpp_context typedef struct { uint32_t debug : 1; + uint32_t debug_msg : 1; uint32_t config_parsed : 1; uint32_t connected : 1; uint32_t buffer_pools_initialized : 1; diff --git a/src/plugins/snort/daq/dump.c b/src/plugins/snort/daq/dump.c new file mode 100644 index 00000000000..73d25a61205 --- /dev/null +++ b/src/plugins/snort/daq/dump.c @@ -0,0 +1,466 @@ +/* +** Copyright (C) 2025 Cisco and/or its affiliates. All rights reserved. +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License Version 2 as +** published by the Free Software Foundation. You may not use, modify or +** distribute this program under any other version of the GNU General +** Public License. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software Foundation, Inc. +** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#include +#include +#include +#include +#include + +#include "daq_vpp.h" + +static inline char * +daq_vpp_dump_napt_info (const DAQ_NAPTInfo_t *info) +{ + char *buf = 0; + size_t buf_size = 1024; + int n = 0; + char src_addr_str[INET6_ADDRSTRLEN]; + char dst_addr_str[INET6_ADDRSTRLEN]; + + buf = malloc (buf_size); + if (!buf) + return NULL; + + memset (buf, 0, buf_size); + + n += snprintf (buf + n, buf_size - n, "--- DAQ NAPT Info ---\n"); + if (info == NULL) + { + n += snprintf (buf + n, buf_size - n, + "No Network Address and Port Translation\n"); + } + else + { + inet_ntop (daq_napt_info_src_addr_family (info), &info->src_addr, + src_addr_str, sizeof (src_addr_str)); + inet_ntop (daq_napt_info_dst_addr_family (info), &info->dst_addr, + dst_addr_str, sizeof (dst_addr_str)); + + n += snprintf (buf + n, buf_size - n, " Source: [%s]:%u\n", + src_addr_str, ntohs (info->src_port)); + n += snprintf (buf + n, buf_size - n, " Destination: [%s]:%u\n", + dst_addr_str, ntohs (info->dst_port)); + n += snprintf (buf + n, buf_size - n, " Flags: %#04x\n", + info->flags); + + n += snprintf (buf + n, buf_size - n, " \tSource IP:"); + if ((info->flags & DAQ_NAPT_INFO_FLAG_SIP_V6) == + DAQ_NAPT_INFO_FLAG_SIP_V6) + n += snprintf (buf + n, buf_size - n, " IPv6\n"); + else + n += snprintf (buf + n, buf_size - n, " IPv4\n"); + n += snprintf (buf + n, buf_size - n, " \tDestination IP:"); + if ((info->flags & DAQ_NAPT_INFO_FLAG_DIP_V6) == + DAQ_NAPT_INFO_FLAG_DIP_V6) + n += snprintf (buf + n, buf_size - n, " IPv6\n"); + else + n += snprintf (buf + n, buf_size - n, " IPv4\n"); + + n += snprintf (buf + n, buf_size - n, " IP Layer: %u ", + info->ip_layer); + switch (info->ip_layer) + { + case IPPROTO_TCP: + n += snprintf (buf + n, buf_size - n, "(TCP)\n"); + break; + case IPPROTO_UDP: + n += snprintf (buf + n, buf_size - n, "(UDP)\n"); + break; + case IPPROTO_ICMPV6: + n += snprintf (buf + n, buf_size - n, "(ICMPv6)\n"); + break; + default: + n += snprintf (buf + n, buf_size - n, "(Other)\n"); + break; + } + } + n += snprintf (buf + n, buf_size - n, "----------------------------\n"); + return buf; +} + +static inline char * +daq_vpp_dump_packet_decode_flags (DAQ_PktDecodeFlags_t flags) +{ + char *buf = 0; + size_t buf_size = 1024; + int n = 0; + + buf = malloc (buf_size); + if (!buf) + return NULL; + + memset (buf, 0, buf_size); + n += snprintf (buf + n, buf_size - n, " Flags (0x%08x):\n", flags.all); + + // General parsing status + if (flags.bits.l2) + n += snprintf (buf + n, buf_size - n, " - L2 Parsed\n"); + if (flags.bits.l3) + n += snprintf (buf + n, buf_size - n, " - L3 Parsed\n"); + if (flags.bits.l4) + n += snprintf (buf + n, buf_size - n, " - L4 Parsed\n"); + + // Checksum status + if (flags.bits.l2_checksum) + n += snprintf (buf + n, buf_size - n, " - L2 Checksum OK\n"); + if (flags.bits.l3_checksum) + n += snprintf (buf + n, buf_size - n, " - L3 Checksum OK\n"); + if (flags.bits.l4_checksum) + n += snprintf (buf + n, buf_size - n, " - L4 Checksum OK\n"); + if (flags.bits.checksum_error) + n += snprintf (buf + n, buf_size - n, " - Checksum Error Detected\n"); + + // L2 details + if (flags.bits.vlan) + n += snprintf (buf + n, buf_size - n, " - VLAN Tag Found\n"); + if (flags.bits.vlan_qinq) + n += snprintf (buf + n, buf_size - n, " - QinQ VLAN Tags Found\n"); + if (flags.bits.ethernet) + n += snprintf (buf + n, buf_size - n, " - Protocol: Ethernet\n"); + + // L3 protocols + if (flags.bits.ipv4) + n += snprintf (buf + n, buf_size - n, " - Protocol: IPv4\n"); + if (flags.bits.ipv6) + n += snprintf (buf + n, buf_size - n, " - Protocol: IPv6\n"); + + // L4 protocols + if (flags.bits.tcp) + n += snprintf (buf + n, buf_size - n, " - Protocol: TCP\n"); + if (flags.bits.udp) + n += snprintf (buf + n, buf_size - n, " - Protocol: UDP\n"); + if (flags.bits.icmp) + n += snprintf (buf + n, buf_size - n, " - Protocol: ICMP\n"); + + // TCP options + if (flags.bits.tcp_opt_mss) + n += snprintf (buf + n, buf_size - n, " - TCP Opt: MSS\n"); + if (flags.bits.tcp_opt_ws) + n += snprintf (buf + n, buf_size - n, " - TCP Opt: Window Scale\n"); + if (flags.bits.tcp_opt_ts) + n += snprintf (buf + n, buf_size - n, " - TCP Opt: Timestamp\n"); + + return buf; +} + +static inline char * +daq_vpp_dump_packet_decode_data (const DAQ_PktDecodeData_t *data) +{ + char *buf = 0; + char *flags_buf = 0; + size_t buf_size = 1024; + int n = 0; + + buf = malloc (buf_size); + if (!buf) + return NULL; + + memset (buf, 0, buf_size); + n += snprintf (buf + n, buf_size - n, "--- DAQ Packet Decode Data ---\n"); + + if (data == NULL) + { + n += snprintf (buf + n, buf_size - n, "No Packet Decode Data\n"); + } + else + { + + // Call the helper to print the detailed flags + flags_buf = daq_vpp_dump_packet_decode_flags (data->flags); + if (flags_buf) + { + n += snprintf (buf + n, buf_size - n, "%s", flags_buf); + free (flags_buf); + } + + // Print the offsets, checking for the invalid sentinel value + n += snprintf (buf + n, buf_size - n, " Offsets:\n"); + n += snprintf (buf + n, buf_size - n, " %-18s: ", "L2 Offset"); + if (data->l2_offset == DAQ_PKT_DECODE_OFFSET_INVALID) + n += snprintf (buf + n, buf_size - n, "Invalid\n"); + else + n += snprintf (buf + n, buf_size - n, "%u\n", data->l2_offset); + + n += snprintf (buf + n, buf_size - n, " %-18s: ", "L3 Offset"); + if (data->l3_offset == DAQ_PKT_DECODE_OFFSET_INVALID) + n += snprintf (buf + n, buf_size - n, "Invalid\n"); + else + n += snprintf (buf + n, buf_size - n, "%u\n", data->l3_offset); + + n += snprintf (buf + n, buf_size - n, " %-18s: ", "L4 Offset"); + if (data->l4_offset == DAQ_PKT_DECODE_OFFSET_INVALID) + n += snprintf (buf + n, buf_size - n, "Invalid\n"); + else + n += snprintf (buf + n, buf_size - n, "%u\n", data->l4_offset); + + n += snprintf (buf + n, buf_size - n, " %-18s: ", "Payload Offset"); + if (data->payload_offset == DAQ_PKT_DECODE_OFFSET_INVALID) + n += snprintf (buf + n, buf_size - n, "Invalid\n"); + else + n += snprintf (buf + n, buf_size - n, "%u\n", data->payload_offset); + + n += snprintf (buf + n, buf_size - n, " %-18s: ", "Checksum Offset"); + if (data->checksum_offset == DAQ_PKT_DECODE_OFFSET_INVALID) + n += snprintf (buf + n, buf_size - n, "Invalid\n"); + else + n += snprintf (buf + n, buf_size - n, "%u\n", data->checksum_offset); + } + n += snprintf (buf + n, buf_size - n, "-------------------------------\n"); + return buf; +} + +static inline char * +daq_vpp_dump_packet_tcp_ack_data (const DAQ_PktTcpAckData_t *data) +{ + char *buf = 0; + size_t buf_size = 512; + int n = 0; + + buf = malloc (buf_size); + if (!buf) + return NULL; + + memset (buf, 0, buf_size); + + n += snprintf (buf + n, buf_size - n, "--- DAQ Packet TCP ACK Data ---\n"); + + if (data == NULL) + { + n += snprintf (buf + n, buf_size - n, "No Packet Tcp Ack Data\n"); + } + else + { + n += + snprintf (buf + n, buf_size - n, "--- DAQ TCP Elided ACK Data ---\n"); + + // Use ntohl() ("network to host long") for the 32-bit sequence number. + // The '%u' format specifier is for unsigned integers. + n += snprintf (buf + n, buf_size - n, " TCP Ack Number: %u\n", + ntohl (data->tcp_ack_seq_num)); + + // Use ntohs() ("network to host short") for the 16-bit window size. + n += snprintf (buf + n, buf_size - n, " TCP Window Size: %u\n", + ntohs (data->tcp_window_size)); + } + + n += snprintf (buf + n, buf_size - n, "---------------------------------\n"); + return buf; +} + +char * +daq_vpp_dump_packet_data (const uint8_t *data, uint32_t len) +{ + char *buf = 0; + size_t buf_size; + int n = 0; + + // Each byte as two hex chars + space + 128bytes extra for formatting + buf_size = len * 3 + 512; + + buf = malloc (buf_size); + if (!buf) + return NULL; + + memset (buf, 0, buf_size); + n += snprintf (buf + n, buf_size - n, + "--- DAQ Packet (%u bytes) Hex Dump ---\n", len); + + if (data == NULL || len == 0) + { + n += snprintf (buf + n, buf_size - n, "No data to dump.\n"); + } + else + { + + for (uint32_t i = 0; i < len; i++) + { + if (i % 16 == 0 && i > 0) + n += snprintf (buf + n, buf_size - n, "\n"); + n += snprintf (buf + n, buf_size - n, "%02x ", data[i]); + } + } + n += snprintf (buf + n, buf_size - n, + "\n-----------------------------------\n"); + return buf; +} + +char * +daq_vpp_dump_pkt_hdr (const DAQ_PktHdr_t *hdr) +{ + char *buf = 0; + size_t buf_size = 1024; + int n = 0; + + buf = malloc (buf_size); + if (!buf) + return NULL; + + memset (buf, 0, buf_size); + + n += snprintf (buf + n, buf_size - n, "--- DAQ Packet Header ---\n"); + + if (hdr == NULL) + { + n += snprintf (buf + n, buf_size - n, "No DAQ Packet Header\n"); + } + else + { + // The %06ld for tv_usec ensures leading zeros are printed for + // microseconds. + n += snprintf (buf + n, buf_size - n, + " Timestamp (ts) : %ld.%06ld seconds\n", + hdr->ts.tv_sec, hdr->ts.tv_usec); + n += snprintf (buf + n, buf_size - n, + " Packet Length (pktlen): %u bytes\n", hdr->pktlen); + n += snprintf (buf + n, buf_size - n, " Ingress Index : %d\n", + hdr->ingress_index); + n += snprintf (buf + n, buf_size - n, " Egress Index : %d\n", + hdr->egress_index); + n += snprintf (buf + n, buf_size - n, " Ingress Group : %d\n", + hdr->ingress_group); + n += snprintf (buf + n, buf_size - n, " Egress Group : %d\n", + hdr->egress_group); + // Printing opaque/ID values in both decimal and hex is often useful for + // debugging. + n += snprintf (buf + n, buf_size - n, + " Opaque Value : %u (0x%08x)\n", hdr->opaque, + hdr->opaque); + n += snprintf (buf + n, buf_size - n, + " Flow ID : %u (0x%08x)\n", hdr->flow_id, + hdr->flow_id); + // Flags are best viewed in hex to analyze the bitmask. + n += snprintf (buf + n, buf_size - n, + " Flags : 0x%08x\n", hdr->flags); + n += snprintf (buf + n, buf_size - n, " Address Space ID : %u\n", + hdr->address_space_id); + n += snprintf (buf + n, buf_size - n, " Tenant ID : %u\n", + hdr->tenant_id); + } + n += snprintf (buf + n, buf_size - n, "-------------------------\n"); + return buf; +} + +static inline const char * +daq_vpp_msg_type_to_str (DAQ_MsgType type) +{ + switch (type) + { + case DAQ_MSG_TYPE_PACKET: + return "DAQ_MSG_TYPE_PACKET"; + case DAQ_MSG_TYPE_PAYLOAD: + return "DAQ_MSG_TYPE_PAYLOAD"; + case DAQ_MSG_TYPE_SOF: + return "DAQ_MSG_TYPE_SOF"; + case DAQ_MSG_TYPE_EOF: + return "DAQ_MSG_TYPE_EOF"; + case DAQ_MSG_TYPE_HA_STATE: + return "DAQ_MSG_TYPE_HA_STATE"; + default: + return "UNKNOWN_DAQ_MSG_TYPE"; + } +} + +void +daq_vpp_dump_msg_type (DAQ_MsgType type) +{ + printf ("--- DAQ Message Type ---\n"); + printf (" Type : %s (%d)\n", daq_vpp_msg_type_to_str (type), + type); + printf ("------------------------\n"); +} + +static inline void +daq_vpp_dump_priv_data (const void *priv) +{ + printf ("--- DAQ Message Private Data ---\n"); + if (priv == NULL) + { + printf (" No Private Data\n"); + } + else + { + daq_vpp_msg_pool_entry_t *entry = (daq_vpp_msg_pool_entry_t *) priv; + printf (" desc index: %u\n", entry->index); + } + printf ("-------------------------------\n"); +} + +void +daq_vpp_dump_msg (DAQ_Msg_h msg) +{ + DAQ_PktHdr_t *pkthdr = (DAQ_PktHdr_t *) daq_msg_get_hdr (msg); + DAQ_MsgType type = daq_msg_get_type (msg); + const uint8_t *data = daq_msg_get_data (msg); + uint32_t data_len = daq_msg_get_data_len (msg); + const void *priv = daq_msg_get_priv_data (msg); + + char *napt_buf = NULL; + char *decode_buf = NULL; + char *tcp_ack_buf = NULL; + char *pkt_hdr_buf = NULL; + char *hex_dump_buf = NULL; + + // Print the Private Data + daq_vpp_dump_priv_data (priv); + + // Print the Pkt Header + pkt_hdr_buf = daq_vpp_dump_pkt_hdr (pkthdr); + if (pkt_hdr_buf) + { + printf ("%s", pkt_hdr_buf); + free (pkt_hdr_buf); + } + + // Print the message type + daq_vpp_dump_msg_type (type); + + // Print NAPT Info if present + napt_buf = + daq_vpp_dump_napt_info (daq_msg_get_meta (msg, DAQ_PKT_META_NAPT_INFO)); + if (napt_buf) + { + printf ("%s", napt_buf); + free (napt_buf); + } + // Print Packet Decode Data if present + decode_buf = daq_vpp_dump_packet_decode_data ( + daq_msg_get_meta (msg, DAQ_PKT_META_DECODE_DATA)); + if (decode_buf) + { + printf ("%s", decode_buf); + free (decode_buf); + } + // Print TCP ACK Data if present + tcp_ack_buf = daq_vpp_dump_packet_tcp_ack_data ( + daq_msg_get_meta (msg, DAQ_PKT_META_TCP_ACK_DATA)); + if (tcp_ack_buf) + { + printf ("%s", tcp_ack_buf); + free (tcp_ack_buf); + } + + // Print Hex Dump of Packet Data if present + hex_dump_buf = daq_vpp_dump_packet_data (data, data_len); + if (hex_dump_buf) + { + printf ("%s", hex_dump_buf); + free (hex_dump_buf); + } +} diff --git a/src/plugins/snort/daq/main.c b/src/plugins/snort/daq/main.c index 448ad83b376..ff38ce702c2 100644 --- a/src/plugins/snort/daq/main.c +++ b/src/plugins/snort/daq/main.c @@ -32,6 +32,7 @@ #include #include +#include #include "daq_vpp.h" @@ -54,6 +55,7 @@ daq_vpp_err (daq_vpp_ctx_t *ctx, char *fmt, ...) daq_vpp_main.daq_base_api.set_errbuf (ctx->modinst, "%s", buffer); return DAQ_ERROR; } + static inline __attribute__ ((always_inline)) void daq_vpp_prefetch_read (void *p) { @@ -457,6 +459,7 @@ daq_vpp_fill_msg (daq_vpp_ctx_t *ctx, daq_vpp_qpair_t *qp, uint32_t desc_index, pe->msg.data = data; pe->msg.data_len = d->length; + DEBUG_DUMP_MSG (&pe->msg); return &pe->msg; } @@ -654,6 +657,8 @@ daq_vpp_msg_finalize (void *handle, const DAQ_Msg_t *msg, DAQ_Verdict verdict) daq_vpp_qpair_header_t *h = qp->hdr; daq_vpp_desc_t *d; + DEBUG_DUMP_MSG (msg); + if (verdict >= MAX_DAQ_VERDICT) verdict = DAQ_VERDICT_PASS; ctx->stats.verdicts[verdict]++; @@ -798,8 +803,8 @@ daq_vpp_ioctl (void *handle, DAQ_IoctlCmd cmd, void *arg, size_t arglen) else gpl->priv_data_len = 0; - DEBUG ("ioctl cmd %s %u", daq_vpp_ioctl_cmd_to_str (cmd), - gpl->priv_data_len); + DEBUG2 ("ioctl cmd %s %u", daq_vpp_ioctl_cmd_to_str (cmd), + gpl->priv_data_len); return DAQ_SUCCESS; }