70 SCLogError(
"Error creating thread %s: you do not have support for Napatech adapter "
71 "enabled please recompile with --enable-napatech",
93 #ifdef NAPATECH_ENABLE_BYPASS
94 static int NapatechBypassCallback(
Packet *p);
173 #ifdef NAPATECH_ENABLE_BYPASS
180 uint8_t type_of_service;
181 uint16_t total_length;
183 uint16_t fragment_offset;
184 uint8_t time_to_live;
185 uint8_t next_proto_id;
186 uint16_t hdr_checksum;
200 uint8_t src_addr[16];
201 uint8_t dst_addr[16];
212 uint16_t dgram_cksum;
237 #define RTE_PTYPE_L2_ETHER 0x10000000
238 #define RTE_PTYPE_L3_IPV4 0x01000000
239 #define RTE_PTYPE_L3_IPV6 0x04000000
240 #define RTE_PTYPE_L4_TCP 0x00100000
241 #define RTE_PTYPE_L4_UDP 0x00200000
246 #define RTE_PTYPE_L3_MASK 0x0f000000
247 #define RTE_PTYPE_L4_MASK 0x00f00000
249 #define COLOR_IS_SPAN 0x00001000
251 static int is_inline = 0;
252 static int inline_port_map[
MAX_PORTS] = { -1 };
266 if ((inline_port_map[port] == -1) && (inline_port_map[peer] == -1)) {
267 inline_port_map[port] = peer;
268 inline_port_map[peer] = port;
270 SCLogError(
"Port pairing is already configured.");
287 static int port_adapter_map[
MAX_PORTS] = { -1 };
290 NtInfoStream_t h_info_stream;
292 if (
unlikely(port_adapter_map[port] == -1)) {
293 if ((status = NT_InfoOpen(&h_info_stream,
"ExampleInfo")) != NT_SUCCESS) {
298 h_info.cmd = NT_INFO_CMD_READ_PORT_V9;
299 h_info.u.port_v9.portNo = (uint8_t) port;
300 if ((status = NT_InfoRead(h_info_stream, &h_info)) != NT_SUCCESS) {
303 NT_InfoClose(h_info_stream);
306 port_adapter_map[port] = h_info.u.port_v9.data.adapterNo;
308 return port_adapter_map[port];
345 static int CompareIPv6Addr(uint8_t addr_a[16], uint8_t addr_b[16]) {
347 for (pos = 0; pos < 16; ++pos) {
348 if (addr_a[pos] < addr_b[pos]) {
350 }
else if (addr_a[pos] > addr_b[pos]) {
368 static NtFlowStream_t InitFlowStream(
int adapter,
int stream_id)
371 NtFlowStream_t hFlowStream;
376 NT_FlowOpenAttrInit(&attr);
377 NT_FlowOpenAttrSetAdapterNo(&attr, adapter);
379 snprintf(flow_name,
sizeof(flow_name),
"Flow_stream_%d", stream_id );
380 SCLogDebug(
"Opening flow programming stream: %s", flow_name);
381 if ((status = NT_FlowOpen_Attr(&hFlowStream, flow_name, &attr)) != NT_SUCCESS) {
382 SCLogWarning(
"Napatech bypass functionality not supported by the FPGA version on adapter "
383 "%d - disabling support.",
402 static int ProgramFlow(
Packet *p,
int is_inline)
405 memset(&flow_match, 0,
sizeof(flow_match));
415 uint32_t packet_type = ((ntpv->dyn3->color_hi << 14) & 0xFFFFC000) | ntpv->dyn3->color_lo;
416 uint8_t *packet = (uint8_t *) ntpv->dyn3 + ntpv->dyn3->descrLength;
418 uint32_t layer3 = packet_type & RTE_PTYPE_L3_MASK;
419 uint32_t layer4 = packet_type & RTE_PTYPE_L4_MASK;
420 uint32_t is_span = packet_type & COLOR_IS_SPAN;
431 uint32_t do_swap = 0;
444 struct IPv4Tuple4 v4Tuple;
445 struct IPv6Tuple4 v6Tuple;
446 struct ipv4_hdr *pIPv4_hdr = NULL;
447 struct ipv6_hdr *pIPv6_hdr = NULL;
450 case RTE_PTYPE_L3_IPV4:
452 pIPv4_hdr = (
struct ipv4_hdr *) (packet + ntpv->dyn3->offset0);
454 v4Tuple.sa = pIPv4_hdr->src_addr;
455 v4Tuple.da = pIPv4_hdr->dst_addr;
457 do_swap = (htonl(pIPv4_hdr->src_addr) > htonl(pIPv4_hdr->dst_addr));
460 v4Tuple.sa = pIPv4_hdr->src_addr;
461 v4Tuple.da = pIPv4_hdr->dst_addr;
463 v4Tuple.sa = pIPv4_hdr->dst_addr;
464 v4Tuple.da = pIPv4_hdr->src_addr;
469 case RTE_PTYPE_L3_IPV6:
471 pIPv6_hdr = (
struct ipv6_hdr *) (packet + ntpv->dyn3->offset0);
472 do_swap = (CompareIPv6Addr(pIPv6_hdr->src_addr, pIPv6_hdr->dst_addr) > 0);
475 memcpy(&(v6Tuple.sa), pIPv6_hdr->src_addr, 16);
476 memcpy(&(v6Tuple.da), pIPv6_hdr->dst_addr, 16);
481 memcpy(&(v6Tuple.sa), pIPv6_hdr->src_addr, 16);
482 memcpy(&(v6Tuple.da), pIPv6_hdr->dst_addr, 16);
484 memcpy(&(v6Tuple.sa), pIPv6_hdr->dst_addr, 16);
485 memcpy(&(v6Tuple.da), pIPv6_hdr->src_addr, 16);
497 case RTE_PTYPE_L4_TCP:
499 struct tcp_hdr *tcp_hdr = (
struct tcp_hdr *) (packet + ntpv->dyn3->offset1);
500 if (layer3 == RTE_PTYPE_L3_IPV4) {
502 v4Tuple.dp = tcp_hdr->dst_port;
503 v4Tuple.sp = tcp_hdr->src_port;
504 flow_match.keyId = NAPATECH_KEYTYPE_IPV4;
507 v4Tuple.sp = tcp_hdr->src_port;
508 v4Tuple.dp = tcp_hdr->dst_port;
510 v4Tuple.sp = tcp_hdr->dst_port;
511 v4Tuple.dp = tcp_hdr->src_port;
513 flow_match.keyId = NAPATECH_KEYTYPE_IPV4_SPAN;
515 memcpy(&(flow_match.keyData), &v4Tuple,
sizeof(v4Tuple));
518 v6Tuple.dp = tcp_hdr->dst_port;
519 v6Tuple.sp = tcp_hdr->src_port;
520 flow_match.keyId = NAPATECH_KEYTYPE_IPV6;
523 v6Tuple.sp = tcp_hdr->src_port;
524 v6Tuple.dp = tcp_hdr->dst_port;
526 v6Tuple.dp = tcp_hdr->src_port;
527 v6Tuple.sp = tcp_hdr->dst_port;
529 flow_match.keyId = NAPATECH_KEYTYPE_IPV6_SPAN;
531 memcpy(&(flow_match.keyData), &v6Tuple,
sizeof(v6Tuple));
533 flow_match.ipProtocolField = 6;
536 case RTE_PTYPE_L4_UDP:
538 struct udp_hdr *udp_hdr = (
struct udp_hdr *) (packet + ntpv->dyn3->offset1);
539 if (layer3 == RTE_PTYPE_L3_IPV4) {
541 v4Tuple.dp = udp_hdr->dst_port;
542 v4Tuple.sp = udp_hdr->src_port;
543 flow_match.keyId = NAPATECH_KEYTYPE_IPV4;
546 v4Tuple.sp = udp_hdr->src_port;
547 v4Tuple.dp = udp_hdr->dst_port;
549 v4Tuple.dp = udp_hdr->src_port;
550 v4Tuple.sp = udp_hdr->dst_port;
552 flow_match.keyId = NAPATECH_KEYTYPE_IPV4_SPAN;
554 memcpy(&(flow_match.keyData), &v4Tuple,
sizeof(v4Tuple));
557 v6Tuple.dp = udp_hdr->dst_port;
558 v6Tuple.sp = udp_hdr->src_port;
559 flow_match.keyId = NAPATECH_KEYTYPE_IPV6;
562 v6Tuple.sp = udp_hdr->src_port;
563 v6Tuple.dp = udp_hdr->dst_port;
565 v6Tuple.dp = udp_hdr->src_port;
566 v6Tuple.sp = udp_hdr->dst_port;
568 flow_match.keyId = NAPATECH_KEYTYPE_IPV6_SPAN;
570 memcpy(&(flow_match.keyData), &v6Tuple,
sizeof(v6Tuple));
572 flow_match.ipProtocolField = 17;
586 flow_match.keySetId = NAPATECH_FLOWTYPE_DROP;
589 flow_match.keySetId = NAPATECH_FLOWTYPE_PASS;
591 flow_match.keySetId = NAPATECH_FLOWTYPE_DROP;
595 if (NT_FlowWrite(ntpv->
flow_stream, &flow_match, -1) != NT_SUCCESS) {
610 static int NapatechBypassCallback(
Packet *p)
652 FatalError(
"Failed to allocate memory for NAPATECH thread vars.");
664 *data = (
void *) ntv;
679 static void NapatechReleasePacket(
struct Packet_ *p)
685 #ifdef NAPATECH_ENABLE_BYPASS
687 p->
ntpv.dyn3->wireLength = 0;
695 if (p->
ntpv.bypass == 1) {
696 ProgramFlow(p, is_inline);
710 static int GetNumaNode(
void)
715 #if defined(__linux__)
716 cpu = sched_getcpu();
717 node = numa_node_of_cpu(cpu);
719 SCLogWarning(
"Auto configuration of NUMA node is not supported on this OS.");
731 static void RecommendNUMAConfig(
SCLogLevel log_level)
737 int set_cpu_affinity = 0;
739 if (
ConfGetBool(
"threading.set-cpu-affinity", &set_cpu_affinity) != 1) {
740 set_cpu_affinity = 0;
743 if (set_cpu_affinity) {
744 SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
745 "Minimum host buffers that should be defined in ntservice.ini:");
747 SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
" NUMA Node 0: %d",
750 if (numa_max_node() >= 1)
751 SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
754 if (numa_max_node() >= 2)
755 SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
758 if (numa_max_node() >= 3)
759 SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
762 snprintf(string0, 16,
"[%d, 16, 0]",
SC_ATOMIC_GET(numa0_count));
763 snprintf(string1, 16, (numa_max_node() >= 1 ?
",[%d, 16, 1]" :
""),
765 snprintf(string2, 16, (numa_max_node() >= 2 ?
",[%d, 16, 2]" :
""),
767 snprintf(string3, 16, (numa_max_node() >= 3 ?
",[%d, 16, 3]" :
""),
770 SCLog(log_level, __FILE__, __FUNCTION__, __LINE__,
771 "E.g.: HostBuffersRx=%s%s%s%s", string0, string1, string2,
774 SCLogError(
"Or, try running /opt/napatech3/bin/ntpl -e \"delete=all\" to clean-up stream "
790 char error_buffer[100];
792 NtNetBuf_t packet_buffer;
794 uint64_t hba_pkt_drops = 0;
795 uint64_t hba_byte_drops = 0;
796 uint16_t hba_pkt = 0;
798 int set_cpu_affinity = 0;
800 int is_autoconfig = 0;
805 #ifdef NAPATECH_ENABLE_BYPASS
812 for (adapter = 0; adapter < NapatechGetNumAdapters(); ++adapter) {
813 flow_stream[adapter] = InitFlowStream(adapter, ntv->
stream_id);
817 if (
ConfGetBool(
"napatech.auto-config", &is_autoconfig) == 0) {
822 numa_node = GetNumaNode();
840 if (
ConfGetBool(
"threading.set-cpu-affinity", &set_cpu_affinity) != 1) {
841 set_cpu_affinity = 0;
844 if (set_cpu_affinity) {
848 numa_node = GetNumaNode();
852 #ifdef NAPATECH_ENABLE_BYPASS
853 if (
ConfGetBool(
"napatech.inline", &is_inline) == 0) {
859 inline_port_map[i] = -1;
868 if (status == 0x20002061) {
869 SCLogError(
"Check host buffer configuration in ntservice.ini.");
873 }
else if (status == 0x20000008) {
874 FatalError(
"Check napatech.ports in the suricata config file.");
877 SCLogNotice(
"Napatech packet input engine started.");
882 "Napatech Packet Loop Started - cpu: %3d, cpu_numa: %3d stream: %3u ",
883 sched_getcpu(), numa_node, ntv->
stream_id);
888 FatalError(
"Failed to allocate memory for NAPATECH stream counter.");
890 snprintf(s_hbad_pkt, 32,
"nt%d.hba_drop", ntv->
stream_id);
897 if ((status = NT_NetRxOpen(&(ntv->
rx_stream),
"SuricataStream",
898 NT_NET_INTERFACE_PACKET, ntv->
stream_id, ntv->
hba)) != NT_SUCCESS) {
917 status = NT_NetRxGet(ntv->
rx_stream, &packet_buffer, 1000);
919 status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) {
920 if (status == NT_STATUS_TIMEOUT) {
921 TmThreadsCaptureHandleTimeout(
tv, NULL);
924 }
else if (
unlikely(status != NT_SUCCESS)) {
926 SCLogInfo(
"Failed to read from Napatech Stream %d: %s",
932 #ifdef NAPATECH_ENABLE_BYPASS
939 NT_NetRxRelease(ntv->
rx_stream, packet_buffer);
943 pkt_ts = NT_NET_GET_PKT_TIMESTAMP(packet_buffer);
950 switch (NT_NET_GET_PKT_TIMESTAMP_TYPE(packet_buffer)) {
951 case NT_TIMESTAMP_TYPE_NATIVE_UNIX:
954 ((pkt_ts % 100000000) / 100) + ((pkt_ts % 100) > 50 ? 1 : 0));
956 case NT_TIMESTAMP_TYPE_PCAP:
960 case NT_TIMESTAMP_TYPE_PCAP_NANOTIME:
963 ((pkt_ts & 0xFFFFFFFF) / 1000) + ((pkt_ts % 1000) > 500 ? 1 : 0));
965 case NT_TIMESTAMP_TYPE_NATIVE_NDIS:
969 ((pkt_ts % 100000000) / 100) + ((pkt_ts % 100) > 50 ? 1 : 0));
972 SCLogError(
"Packet from Napatech Stream: %u does not have a supported timestamp "
975 NT_NetRxRelease(ntv->
rx_stream, packet_buffer);
981 stat_cmd.cmd = NT_NETRX_READ_CMD_STREAM_DROP;
983 if (
unlikely((status = NT_NetRxRead(ntv->
rx_stream, &stat_cmd)) != NT_SUCCESS)) {
985 SCLogInfo(
"Couldn't retrieve drop statistics from the RX stream: %u",
988 hba_pkt_drops = stat_cmd.u.streamDrop.pktsDropped;
995 #ifdef NAPATECH_ENABLE_BYPASS
996 p->
ntpv.dyn3 = _NT_NET_GET_PKT_DESCR_PTR_DYN3(packet_buffer);
997 p->
BypassPacketsFlow = (NapatechIsBypassSupported() ? NapatechBypassCallback : NULL);
998 NT_NET_SET_PKT_TXPORT(packet_buffer, inline_port_map[p->
ntpv.dyn3->rxPort]);
1008 if (
unlikely(
PacketSetData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) {
1030 SCLogInfo(
"Host Buffer Allowance Drops - pkts: %ld, bytes: %ld", hba_pkt_drops, hba_byte_drops);
1052 SCLogInfo(
"nt%lu - pkts: %lu; drop: %lu (%5.2f%%); bytes: %lu",
1066 SCLogInfo(
"--- Total Packets: %ld Total Dropped: %ld (%5.2f%%)",
1069 #ifdef NAPATECH_ENABLE_BYPASS
1070 SCLogInfo(
"--- BypassCB - Total: %ld, UDP: %ld, TCP: %ld, Unhandled: %ld",
1121 SCLogError(
"Datalink type %" PRId32
" not yet supported in module NapatechDecode",
1147 *data = (
void *)
dtv;