72 SCLogError(
"Error creating thread %s: you do not have support for Napatech adapter "
73 "enabled please recompile with --enable-napatech",
94 #ifdef NAPATECH_ENABLE_BYPASS
95 static int NapatechBypassCallback(
Packet *p);
132 static TmEcode NapatechStreamInit(
void)
143 FatalError(
"Failed to allocate memory for numa detection array: %s", strerror(errno));
146 for (i = 0; i <= numa_max_node(); ++i) {
162 static TmEcode NapatechStreamDeInit(
void)
203 #ifdef NAPATECH_ENABLE_BYPASS
210 uint8_t type_of_service;
211 uint16_t total_length;
213 uint16_t fragment_offset;
214 uint8_t time_to_live;
215 uint8_t next_proto_id;
216 uint16_t hdr_checksum;
230 uint8_t src_addr[16];
231 uint8_t dst_addr[16];
242 uint16_t dgram_cksum;
267 #define RTE_PTYPE_L2_ETHER 0x10000000
268 #define RTE_PTYPE_L3_IPV4 0x01000000
269 #define RTE_PTYPE_L3_IPV6 0x04000000
270 #define RTE_PTYPE_L4_TCP 0x00100000
271 #define RTE_PTYPE_L4_UDP 0x00200000
276 #define RTE_PTYPE_L3_MASK 0x0f000000
277 #define RTE_PTYPE_L4_MASK 0x00f00000
279 #define COLOR_IS_SPAN 0x00001000
281 static int is_inline = 0;
282 static int inline_port_map[
MAX_PORTS] = { -1 };
296 if ((inline_port_map[port] == -1) && (inline_port_map[peer] == -1)) {
297 inline_port_map[port] = peer;
298 inline_port_map[peer] = port;
300 SCLogError(
"Port pairing is already configured.");
317 static int port_adapter_map[
MAX_PORTS] = { -1 };
320 NtInfoStream_t h_info_stream;
322 if (
unlikely(port_adapter_map[port] == -1)) {
323 if ((status = NT_InfoOpen(&h_info_stream,
"ExampleInfo")) != NT_SUCCESS) {
328 h_info.cmd = NT_INFO_CMD_READ_PORT_V9;
329 h_info.u.port_v9.portNo = (uint8_t) port;
330 if ((status = NT_InfoRead(h_info_stream, &h_info)) != NT_SUCCESS) {
333 NT_InfoClose(h_info_stream);
336 port_adapter_map[port] = h_info.u.port_v9.data.adapterNo;
338 return port_adapter_map[port];
374 static int CompareIPv6Addr(uint8_t addr_a[16], uint8_t addr_b[16]) {
376 for (pos = 0; pos < 16; ++pos) {
377 if (addr_a[pos] < addr_b[pos]) {
379 }
else if (addr_a[pos] > addr_b[pos]) {
397 static NtFlowStream_t InitFlowStream(
int adapter,
int stream_id)
400 NtFlowStream_t hFlowStream;
405 NT_FlowOpenAttrInit(&attr);
406 NT_FlowOpenAttrSetAdapterNo(&attr, adapter);
408 snprintf(flow_name,
sizeof(flow_name),
"Flow_stream_%d", stream_id );
409 SCLogDebug(
"Opening flow programming stream: %s", flow_name);
410 if ((status = NT_FlowOpen_Attr(&hFlowStream, flow_name, &attr)) != NT_SUCCESS) {
411 SCLogWarning(
"Napatech bypass functionality not supported by the FPGA version on adapter "
412 "%d - disabling support.",
431 static int ProgramFlow(
Packet *p,
int inline_mode)
434 memset(&flow_match, 0,
sizeof(flow_match));
444 uint32_t packet_type = ((ntpv->dyn3->color_hi << 14) & 0xFFFFC000) | ntpv->dyn3->color_lo;
445 uint8_t *packet = (uint8_t *) ntpv->dyn3 + ntpv->dyn3->descrLength;
447 uint32_t layer3 = packet_type & RTE_PTYPE_L3_MASK;
448 uint32_t layer4 = packet_type & RTE_PTYPE_L4_MASK;
449 uint32_t is_span = packet_type & COLOR_IS_SPAN;
460 uint32_t do_swap = 0;
473 struct IPv4Tuple4 v4Tuple;
474 struct IPv6Tuple4 v6Tuple;
475 struct ipv4_hdr *pIPv4_hdr = NULL;
476 struct ipv6_hdr *pIPv6_hdr = NULL;
479 case RTE_PTYPE_L3_IPV4:
481 pIPv4_hdr = (
struct ipv4_hdr *) (packet + ntpv->dyn3->offset0);
483 v4Tuple.sa = pIPv4_hdr->src_addr;
484 v4Tuple.da = pIPv4_hdr->dst_addr;
486 do_swap = (htonl(pIPv4_hdr->src_addr) > htonl(pIPv4_hdr->dst_addr));
489 v4Tuple.sa = pIPv4_hdr->src_addr;
490 v4Tuple.da = pIPv4_hdr->dst_addr;
492 v4Tuple.sa = pIPv4_hdr->dst_addr;
493 v4Tuple.da = pIPv4_hdr->src_addr;
498 case RTE_PTYPE_L3_IPV6:
500 pIPv6_hdr = (
struct ipv6_hdr *) (packet + ntpv->dyn3->offset0);
501 do_swap = (CompareIPv6Addr(pIPv6_hdr->src_addr, pIPv6_hdr->dst_addr) > 0);
504 memcpy(&(v6Tuple.sa), pIPv6_hdr->src_addr, 16);
505 memcpy(&(v6Tuple.da), pIPv6_hdr->dst_addr, 16);
510 memcpy(&(v6Tuple.sa), pIPv6_hdr->src_addr, 16);
511 memcpy(&(v6Tuple.da), pIPv6_hdr->dst_addr, 16);
513 memcpy(&(v6Tuple.sa), pIPv6_hdr->dst_addr, 16);
514 memcpy(&(v6Tuple.da), pIPv6_hdr->src_addr, 16);
526 case RTE_PTYPE_L4_TCP:
528 struct tcp_hdr *tcp_hdr = (
struct tcp_hdr *) (packet + ntpv->dyn3->offset1);
529 if (layer3 == RTE_PTYPE_L3_IPV4) {
531 v4Tuple.dp = tcp_hdr->dst_port;
532 v4Tuple.sp = tcp_hdr->src_port;
533 flow_match.keyId = NAPATECH_KEYTYPE_IPV4;
536 v4Tuple.sp = tcp_hdr->src_port;
537 v4Tuple.dp = tcp_hdr->dst_port;
539 v4Tuple.sp = tcp_hdr->dst_port;
540 v4Tuple.dp = tcp_hdr->src_port;
542 flow_match.keyId = NAPATECH_KEYTYPE_IPV4_SPAN;
544 memcpy(&(flow_match.keyData), &v4Tuple,
sizeof(v4Tuple));
547 v6Tuple.dp = tcp_hdr->dst_port;
548 v6Tuple.sp = tcp_hdr->src_port;
549 flow_match.keyId = NAPATECH_KEYTYPE_IPV6;
552 v6Tuple.sp = tcp_hdr->src_port;
553 v6Tuple.dp = tcp_hdr->dst_port;
555 v6Tuple.dp = tcp_hdr->src_port;
556 v6Tuple.sp = tcp_hdr->dst_port;
558 flow_match.keyId = NAPATECH_KEYTYPE_IPV6_SPAN;
560 memcpy(&(flow_match.keyData), &v6Tuple,
sizeof(v6Tuple));
562 flow_match.ipProtocolField = 6;
565 case RTE_PTYPE_L4_UDP:
567 struct udp_hdr *udp_hdr = (
struct udp_hdr *) (packet + ntpv->dyn3->offset1);
568 if (layer3 == RTE_PTYPE_L3_IPV4) {
570 v4Tuple.dp = udp_hdr->dst_port;
571 v4Tuple.sp = udp_hdr->src_port;
572 flow_match.keyId = NAPATECH_KEYTYPE_IPV4;
575 v4Tuple.sp = udp_hdr->src_port;
576 v4Tuple.dp = udp_hdr->dst_port;
578 v4Tuple.dp = udp_hdr->src_port;
579 v4Tuple.sp = udp_hdr->dst_port;
581 flow_match.keyId = NAPATECH_KEYTYPE_IPV4_SPAN;
583 memcpy(&(flow_match.keyData), &v4Tuple,
sizeof(v4Tuple));
586 v6Tuple.dp = udp_hdr->dst_port;
587 v6Tuple.sp = udp_hdr->src_port;
588 flow_match.keyId = NAPATECH_KEYTYPE_IPV6;
591 v6Tuple.sp = udp_hdr->src_port;
592 v6Tuple.dp = udp_hdr->dst_port;
594 v6Tuple.dp = udp_hdr->src_port;
595 v6Tuple.sp = udp_hdr->dst_port;
597 flow_match.keyId = NAPATECH_KEYTYPE_IPV6_SPAN;
599 memcpy(&(flow_match.keyData), &v6Tuple,
sizeof(v6Tuple));
601 flow_match.ipProtocolField = 17;
615 flow_match.keySetId = NAPATECH_FLOWTYPE_DROP;
618 flow_match.keySetId = NAPATECH_FLOWTYPE_PASS;
620 flow_match.keySetId = NAPATECH_FLOWTYPE_DROP;
624 if (NT_FlowWrite(ntpv->
flow_stream, &flow_match, -1) != NT_SUCCESS) {
639 static int NapatechBypassCallback(
Packet *p)
681 FatalError(
"Failed to allocate memory for NAPATECH thread vars.");
692 *data = (
void *) ntv;
707 static void NapatechReleasePacket(
struct Packet_ *p)
713 #ifdef NAPATECH_ENABLE_BYPASS
715 p->
ntpv.dyn3->wireLength = 0;
723 if (p->
ntpv.bypass == 1) {
724 ProgramFlow(p, is_inline);
738 static int GetNumaNode(
void)
743 #if defined(__linux__)
744 cpu = sched_getcpu();
745 node = numa_node_of_cpu(cpu);
747 SCLogWarning(
"Auto configuration of NUMA node is not supported on this OS.");
759 static void RecommendNUMAConfig(
void)
762 int set_cpu_affinity = 0;
764 p = buffer =
SCCalloc(
sizeof(
char), (32 * (numa_max_node() + 1) + 1));
765 if (buffer == NULL) {
766 FatalError(
"Failed to allocate memory for temporary buffer: %s", strerror(errno));
769 if (
ConfGetBool(
"threading.set-cpu-affinity", &set_cpu_affinity) != 1) {
770 set_cpu_affinity = 0;
773 if (set_cpu_affinity) {
774 SCLogPerf(
"Minimum host buffers that should be defined in ntservice.ini:");
775 for (
int i = 0; i <= numa_max_node(); ++i) {
777 p += snprintf(p, 32,
"%s[%d, 16, %d]", (i == 0 ?
"" :
","),
780 SCLogPerf(
"E.g.: HostBuffersRx=%s", buffer);
797 char error_buffer[100];
799 NtNetBuf_t packet_buffer;
802 int set_cpu_affinity = 0;
804 int is_autoconfig = 0;
809 #ifdef NAPATECH_ENABLE_BYPASS
816 for (adapter = 0; adapter < NapatechGetNumAdapters(); ++adapter) {
817 flow_stream[adapter] = InitFlowStream(adapter, ntv->
stream_id);
822 if (
ConfGetBool(
"napatech.auto-config", &is_autoconfig) == 0) {
827 numa_node = GetNumaNode();
829 if (numa_node <= numa_max_node()) {
833 if (
ConfGetBool(
"threading.set-cpu-affinity", &set_cpu_affinity) != 1) {
834 set_cpu_affinity = 0;
837 if (set_cpu_affinity) {
845 RecommendNUMAConfig();
847 #ifdef NAPATECH_ENABLE_BYPASS
848 if (
ConfGetBool(
"napatech.inline", &is_inline) == 0) {
854 inline_port_map[i] = -1;
863 if (status == 0x20002061) {
864 FatalError(
"Check host buffer configuration in ntservice.ini"
865 " or try running /opt/napatech3/bin/ntpl -e "
866 "\"delete=all\" to clean-up stream NUMA config.");
867 }
else if (status == 0x20000008) {
868 FatalError(
"Check napatech.ports in the suricata config file.");
870 SCLogNotice(
"Napatech packet input engine started.");
875 "Napatech Packet Loop Started - cpu: %3d, cpu_numa: %3d stream: %3u ",
876 sched_getcpu(), numa_node, ntv->
stream_id);
880 if ((status = NT_NetRxOpen(&(ntv->
rx_stream),
"SuricataStream", NT_NET_INTERFACE_PACKET,
900 status = NT_NetRxGet(ntv->
rx_stream, &packet_buffer, 1000);
902 status == NT_STATUS_TIMEOUT || status == NT_STATUS_TRYAGAIN)) {
903 if (status == NT_STATUS_TIMEOUT) {
904 TmThreadsCaptureHandleTimeout(
tv, NULL);
907 }
else if (
unlikely(status != NT_SUCCESS)) {
909 SCLogInfo(
"Failed to read from Napatech Stream %d: %s",
917 NT_NetRxRelease(ntv->
rx_stream, packet_buffer);
921 #ifdef NAPATECH_ENABLE_BYPASS
926 pkt_ts = NT_NET_GET_PKT_TIMESTAMP(packet_buffer);
933 switch (NT_NET_GET_PKT_TIMESTAMP_TYPE(packet_buffer)) {
934 case NT_TIMESTAMP_TYPE_NATIVE_UNIX:
936 ((pkt_ts % 100000000) / 100) + ((pkt_ts % 100) > 50 ? 1 : 0));
938 case NT_TIMESTAMP_TYPE_PCAP:
941 case NT_TIMESTAMP_TYPE_PCAP_NANOTIME:
943 ((pkt_ts & 0xFFFFFFFF) / 1000) + ((pkt_ts % 1000) > 500 ? 1 : 0));
945 case NT_TIMESTAMP_TYPE_NATIVE_NDIS:
948 ((pkt_ts % 100000000) / 100) + ((pkt_ts % 100) > 50 ? 1 : 0));
951 SCLogError(
"Packet from Napatech Stream: %u does not have a supported timestamp "
954 NT_NetRxRelease(ntv->
rx_stream, packet_buffer);
958 #ifdef NAPATECH_ENABLE_BYPASS
959 p->
ntpv.dyn3 = _NT_NET_GET_PKT_DESCR_PTR_DYN3(packet_buffer);
960 p->
BypassPacketsFlow = (NapatechIsBypassSupported() ? NapatechBypassCallback : NULL);
961 NT_NET_SET_PKT_TXPORT(packet_buffer, inline_port_map[p->
ntpv.dyn3->rxPort]);
971 if (
unlikely(
PacketSetData(p, (uint8_t *)NT_NET_GET_PKT_L2_PTR(packet_buffer), NT_NET_GET_PKT_WIRE_LENGTH(packet_buffer)))) {
1011 SCLogInfo(
"nt%lu - pkts: %lu; drop: %lu (%5.2f%%); bytes: %lu",
1025 SCLogInfo(
"--- Total Packets: %ld Total Dropped: %ld (%5.2f%%)",
1028 #ifdef NAPATECH_ENABLE_BYPASS
1029 SCLogInfo(
"--- BypassCB - Total: %ld, UDP: %ld, TCP: %ld, Unhandled: %ld",
1080 SCLogError(
"Datalink type %" PRId32
" not yet supported in module NapatechDecode",
1106 *data = (
void *)
dtv;