diff --git a/configure.ac b/configure.ac index 4d66c55d0a96..77a90b88dcd1 100644 --- a/configure.ac +++ b/configure.ac @@ -1384,6 +1384,7 @@ ]) # DPDK support + enable_dpdk_bond_pmd="no" AC_ARG_ENABLE(dpdk, AS_HELP_STRING([--enable-dpdk], [Enable DPDK support [default=no]]), [enable_dpdk=$enableval],[enable_dpdk=no]) @@ -1415,6 +1416,23 @@ fi CFLAGS="${CFLAGS} `pkg-config --cflags libdpdk`" LIBS="${LIBS} -Wl,-R,`pkg-config --libs-only-L libdpdk | cut -c 3-` -lnuma `pkg-config --libs libdpdk`" + + if test ! -z "$(ldconfig -p | grep librte_net_bond)"; then + AC_DEFINE([HAVE_DPDK_BOND],[1],(DPDK Bond PMD support enabled)) + enable_dpdk_bond_pmd="yes" + LIBS="${LIBS} -lrte_net_bond" # 20.11+ + elif test ! -z "$(ldconfig -p | grep librte_pmd_bond)"; then + AC_DEFINE([HAVE_DPDK_BOND],[1],(DPDK Bond PMD support enabled)) + enable_dpdk_bond_pmd="yes" + LIBS="${LIBS} -lrte_pmd_bond" + else + echo + echo " WARNING: DPDK Bond PMD was not found on your system, " + echo " you will be unable to use DPDK Bond PMD." + echo " You can try to \"sudo ldconfig\" and reconfigure again" + echo " or compile and install DPDK with Bond support enabled." + echo + fi ]) # Netmap support @@ -2629,6 +2647,7 @@ SURICATA_BUILD_CONF="Suricata Configuration: Profiling rules enabled: ${enable_profiling_rules} Plugin support (experimental): ${plugin_support} + DPDK Bond PMD: ${enable_dpdk_bond_pmd} Development settings: Coccinelle / spatch: ${enable_coccinelle} diff --git a/doc/userguide/capture-hardware/dpdk.rst b/doc/userguide/capture-hardware/dpdk.rst new file mode 100644 index 000000000000..91ae1c876ca9 --- /dev/null +++ b/doc/userguide/capture-hardware/dpdk.rst @@ -0,0 +1,97 @@ +.. _dpdk: + +DPDK +==== + +Introduction +------------- + +The Data Plane Development Kit (DPDK) is a set of libraries and drivers that +enhance and speed up packet processing in the data plane. Its primary use is to +provide faster packet processing by bypassing the kernel network stack, which +can provide significant performance improvements. For detailed instructions on +how to setup DPDK, please refer to :doc:`../configuration/suricata-yaml` to +learn more about the basic setup for DPDK. +The following sections contain examples of how to set up DPDK and Suricata for +more obscure use-cases. + +Bond interface +-------------- + +Link Bonding Poll Mode Driver (Bond PMD), is a software +mechanism provided by the Data Plane Development Kit (DPDK) for aggregating +multiple physical network interfaces into a single logical interface. +Bonding can be e.g. used to: + +* deliver bidirectional flows of tapped interfaces to the same worker, +* establish redundancy by monitoring multiple links, +* improve network performance by load-balancing traffic across multiple links. + +Bond PMD is essentially a virtual driver that manipulates with multiple +physical network interfaces. It can operate in multiple modes as described +in the `DPDK docs +`_ +The individual bonding modes can accustom user needs. +DPDK Bond PMD has a requirement that the aggregated interfaces must be +the same device types - e.g. both physical ports run on mlx5 PMD. +Bond PMD supports multiple queues and therefore can work in workers runmode. +It should have no effect on traffic distribution of the individual ports and +flows should be distributed by physical ports according to the RSS +configuration the same way as if they would be configured independently. + +As an example of Bond PMD, we can setup Suricata to monitor 2 interfaces +that receive TAP traffic from optical interfaces. This means that Suricata +receive one direction of the communication on one interface and the other +direction is received on the other interface. + +:: + + ... + dpdk: + eal-params: + proc-type: primary + vdev: 'net_bonding0,mode=0,slave=0000:04:00.0,slave=0000:04:00.1' + + # DPDK capture support + # RX queues (and TX queues in IPS mode) are assigned to cores in 1:1 ratio + interfaces: + - interface: net_bonding0 # PCIe address of the NIC port + # Threading: possible values are either "auto" or number of threads + # - auto takes all cores + # in IPS mode it is required to specify the number of cores and the + # numbers on both interfaces must match + threads: 4 + ... + +In the DPDK part of suricata.yaml we have added a new parameter to the +eal-params section for virtual devices - `vdev`. +DPDK Environment Abstraction Layer (EAL) can initialize some virtual devices +during the initialization of EAL. +In this case, EAL creates a new device of type `net_bonding`. Suffix of +`net_bonding` signifies the name of the interface (in this case the zero). +Extra arguments are passed after the device name, such as the bonding mode +(`mode=0`). This is the round-robin mode as is described in the DPDK +documentation of Bond PMD. +Members (slaves) of the `net_bonding0` interface are appended after +the bonding mode parameter. + +When the device is specified within EAL parameters, it can be used within +Suricata `interfaces` list. Note that the list doesn't contain PCIe addresses +of the physical ports but instead the `net_bonding0` interface. +Threading section is also adjusted according to the items in the interfaces +list by enablign set-cpu-affinity and listing CPUs that should be used in +management and worker CPU set. + +:: + + ... + threading: + set-cpu-affinity: yes + cpu-affinity: + - management-cpu-set: + cpu: [ 0 ] # include only these CPUs in affinity settings + - receive-cpu-set: + cpu: [ 0 ] # include only these CPUs in affinity settings + - worker-cpu-set: + cpu: [ 2,4,6,8 ] + ... diff --git a/doc/userguide/capture-hardware/index.rst b/doc/userguide/capture-hardware/index.rst index f121508cb49d..992bd07f614b 100644 --- a/doc/userguide/capture-hardware/index.rst +++ b/doc/userguide/capture-hardware/index.rst @@ -9,3 +9,4 @@ Using Capture Hardware ebpf-xdp netmap af-xdp + dpdk diff --git a/etc/schema.json b/etc/schema.json index 7223e0d75541..81024cf6b49b 100644 --- a/etc/schema.json +++ b/etc/schema.json @@ -4204,6 +4204,9 @@ "vlan_qinq": { "type": "integer" }, + "vlan_qinqinq": { + "type": "integer" + }, "vntag": { "type": "integer" }, diff --git a/rust/src/http2/parser.rs b/rust/src/http2/parser.rs index 88486f03b039..adabeb28c6e4 100644 --- a/rust/src/http2/parser.rs +++ b/rust/src/http2/parser.rs @@ -456,13 +456,15 @@ fn http2_parse_headers_block_literal_incindex<'a>( } else { dyn_headers.table.push(headcopy); } + let mut toremove = 0; while dyn_headers.current_size > dyn_headers.max_size - && !dyn_headers.table.is_empty() + && toremove < dyn_headers.table.len() { dyn_headers.current_size -= - 32 + dyn_headers.table[0].name.len() + dyn_headers.table[0].value.len(); - dyn_headers.table.remove(0); + 32 + dyn_headers.table[toremove].name.len() + dyn_headers.table[toremove].value.len(); + toremove += 1; } + dyn_headers.table.drain(0..toremove); } return Ok((r, head)); } diff --git a/rust/src/krb/log.rs b/rust/src/krb/log.rs index 427876ad7e3c..7cb952581bc7 100644 --- a/rust/src/krb/log.rs +++ b/rust/src/krb/log.rs @@ -18,7 +18,7 @@ // written by Pierre Chifflier use crate::jsonbuilder::{JsonBuilder, JsonError}; -use crate::krb::krb5::{KRB5State,KRB5Transaction,test_weak_encryption}; +use crate::krb::krb5::{KRB5Transaction,test_weak_encryption}; fn krb5_log_response(jsb: &mut JsonBuilder, tx: &mut KRB5Transaction) -> Result<(), JsonError> { @@ -68,7 +68,7 @@ fn krb5_log_response(jsb: &mut JsonBuilder, tx: &mut KRB5Transaction) -> Result< } #[no_mangle] -pub extern "C" fn rs_krb5_log_json_response(jsb: &mut JsonBuilder, _state: &mut KRB5State, tx: &mut KRB5Transaction) -> bool +pub extern "C" fn rs_krb5_log_json_response(jsb: &mut JsonBuilder, tx: &mut KRB5Transaction) -> bool { krb5_log_response(jsb, tx).is_ok() } diff --git a/rust/src/mqtt/logger.rs b/rust/src/mqtt/logger.rs index 09b14fe25d6f..af0db17bc2b8 100644 --- a/rust/src/mqtt/logger.rs +++ b/rust/src/mqtt/logger.rs @@ -17,7 +17,7 @@ // written by Sascha Steinbiss -use super::mqtt::{MQTTState, MQTTTransaction}; +use super::mqtt::MQTTTransaction; use crate::jsonbuilder::{JsonBuilder, JsonError}; use crate::mqtt::mqtt_message::{MQTTOperation, MQTTSubscribeTopicData}; use crate::mqtt::parser::FixedHeader; @@ -298,7 +298,7 @@ fn log_mqtt(tx: &MQTTTransaction, flags: u32, js: &mut JsonBuilder) -> Result<() #[no_mangle] pub unsafe extern "C" fn rs_mqtt_logger_log( - _state: &mut MQTTState, tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder, + tx: *mut std::os::raw::c_void, flags: u32, js: &mut JsonBuilder, ) -> bool { let tx = cast_pointer!(tx, MQTTTransaction); log_mqtt(tx, flags, js).is_ok() diff --git a/rust/src/rfb/logger.rs b/rust/src/rfb/logger.rs index e670e869cec3..392b825b19d3 100644 --- a/rust/src/rfb/logger.rs +++ b/rust/src/rfb/logger.rs @@ -19,7 +19,7 @@ use std; use std::fmt::Write; -use super::rfb::{RFBState, RFBTransaction}; +use super::rfb::RFBTransaction; use crate::jsonbuilder::{JsonBuilder, JsonError}; fn log_rfb(tx: &RFBTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { @@ -113,8 +113,7 @@ fn log_rfb(tx: &RFBTransaction, js: &mut JsonBuilder) -> Result<(), JsonError> { } #[no_mangle] -pub unsafe extern "C" fn rs_rfb_logger_log(_state: &mut RFBState, - tx: *mut std::os::raw::c_void, +pub unsafe extern "C" fn rs_rfb_logger_log(tx: *mut std::os::raw::c_void, js: &mut JsonBuilder) -> bool { let tx = cast_pointer!(tx, RFBTransaction); log_rfb(tx, js).is_ok() diff --git a/rust/src/smb/smb1_records.rs b/rust/src/smb/smb1_records.rs index ce3f9194ec60..0d412da3d6b5 100644 --- a/rust/src/smb/smb1_records.rs +++ b/rust/src/smb/smb1_records.rs @@ -21,6 +21,8 @@ use crate::smb::smb::*; use crate::smb::smb_records::*; use nom7::bytes::streaming::{tag, take}; use nom7::combinator::{complete, cond, peek, rest, verify}; +use nom7::error::{make_error, ErrorKind}; +use nom7::Err; use nom7::multi::many1; use nom7::number::streaming::{le_u8, le_u16, le_u32, le_u64}; use nom7::IResult; @@ -94,6 +96,7 @@ pub fn parse_smb1_write_request_record(i: &[u8]) -> IResult<&[u8], Smb1WriteRequ } pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IResult<&[u8], Smb1WriteRequestRecord> { + let origin_i = i; let ax = andx_offset as u16; let (i, wct) = le_u8(i)?; let (i, _andx_command) = le_u8(i)?; @@ -106,16 +109,19 @@ pub fn parse_smb1_write_andx_request_record(i : &[u8], andx_offset: usize) -> IR let (i, _remaining) = le_u16(i)?; let (i, data_len_high) = le_u16(i)?; let (i, data_len_low) = le_u16(i)?; + let data_len = ((data_len_high as u32) << 16)|(data_len_low as u32); let (i, data_offset) = le_u16(i)?; + if data_offset < 0x3c || data_offset < ax{ + return Err(Err::Error(make_error(i, ErrorKind::LengthValue))); + } let (i, high_offset) = cond(wct == 14, le_u32)(i)?; - let (i, bcc) = le_u16(i)?; - //spec [MS-CIFS].pdf says always take one byte padding - let (i, _padding) = cond(bcc > data_len_low, |b| take(bcc - data_len_low)(b))(i)?; // TODO figure out how this works with data_len_high - let (i, _padding_evasion) = cond(data_offset > ax+4+2*(wct as u16), |b| take(data_offset - (ax+4+2*(wct as u16)))(b))(i)?; - let (i, file_data) = rest(i)?; + let (_i, _bcc) = le_u16(i)?; + let (i, _padding_data) = take(data_offset-ax)(origin_i)?; + let (i, file_data) = take(std::cmp::min(data_len, i.len() as u32))(i)?; + let record = Smb1WriteRequestRecord { - offset: high_offset.map(|ho| (ho as u64) << 32 | offset as u64).unwrap_or(0), - len: ((data_len_high as u32) << 16)|(data_len_low as u32), + offset: ((high_offset.unwrap_or(0) as u64) << 32) | offset as u64, + len: data_len, fid, data: file_data, }; @@ -862,3 +868,16 @@ pub fn parse_smb_record(i: &[u8]) -> IResult<&[u8], SmbRecord> { }; Ok((i, record)) } + +#[test] +fn test_parse_smb1_write_andx_request_record_origin() { + let data = hex::decode("0eff000000014000000000ff00000008001400000014003f000000000014004142434445464748494a4b4c4d4e4f5051520a0a").unwrap(); + let result = parse_smb1_write_andx_request_record(&data, SMB1_HEADER_SIZE); + assert!(result.is_ok()); + let record = result.unwrap().1; + assert_eq!(record.offset, 0); + assert_eq!(record.len, 20); + assert_eq!(record.fid, &[0x01, 0x40]); + assert_eq!(record.data.len(), 20); + assert_eq!(record.data, b"ABCDEFGHIJKLMNOPQR\n\n"); +} diff --git a/src/Makefile.am b/src/Makefile.am index 737b6a6a71fa..4ca8dc7bdbc3 100755 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -532,6 +532,7 @@ noinst_HEADERS = \ util-dpdk-i40e.h \ util-dpdk-ice.h \ util-dpdk-ixgbe.h \ + util-dpdk-bonding.h \ util-ebpf.h \ util-enum.h \ util-error.h \ @@ -1127,6 +1128,7 @@ libsuricata_c_a_SOURCES = \ util-dpdk-i40e.c \ util-dpdk-ice.c \ util-dpdk-ixgbe.c \ + util-dpdk-bonding.c \ util-ebpf.c \ util-enum.c \ util-error.c \ diff --git a/src/app-layer-htp.c b/src/app-layer-htp.c index 3b8baae4b65a..b2c915d9342d 100644 --- a/src/app-layer-htp.c +++ b/src/app-layer-htp.c @@ -1604,6 +1604,16 @@ static int HtpRequestBodyHandleMultipart(HtpState *hstate, HtpTxUserData *htud, if (filedata_len >= (uint32_t)(expected_boundary_len + 2)) { filedata_len -= (expected_boundary_len + 2 - 1); + // take as much as we can until start of boundary + for (size_t nb = 0; nb < (size_t)expected_boundary_len + 1; nb++) { + if (filedata[filedata_len] == '\r') { + if (nb == expected_boundary_len || + filedata[filedata_len + 1] == '\n') { + break; + } + } + filedata_len++; + } SCLogDebug("opening file with partial data"); } else { filedata = NULL; diff --git a/src/decode-erspan.c b/src/decode-erspan.c index e9ffac180d7d..ccdf64aeaef9 100644 --- a/src/decode-erspan.c +++ b/src/decode-erspan.c @@ -99,7 +99,7 @@ int DecodeERSPAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, const uint8_t } if (vlan_id > 0) { - if (p->vlan_idx >= 2) { + if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { ENGINE_SET_EVENT(p,ERSPAN_TOO_MANY_VLAN_LAYERS); return TM_ECODE_FAILED; } diff --git a/src/decode-vlan.c b/src/decode-vlan.c index 61059201eb85..2ec8e2ad9706 100644 --- a/src/decode-vlan.c +++ b/src/decode-vlan.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2021 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -62,6 +62,8 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, StatsIncr(tv, dtv->counter_vlan); else if (p->vlan_idx == 1) StatsIncr(tv, dtv->counter_vlan_qinq); + else if (p->vlan_idx == 2) + StatsIncr(tv, dtv->counter_vlan_qinqinq); if(len < VLAN_HEADER_LEN) { ENGINE_SET_INVALID_EVENT(p, VLAN_HEADER_TOO_SMALL); @@ -70,7 +72,7 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, if (!PacketIncreaseCheckLayers(p)) { return TM_ECODE_FAILED; } - if (p->vlan_idx >= 2) { + if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); return TM_ECODE_FAILED; } @@ -93,16 +95,6 @@ int DecodeVLAN(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, return TM_ECODE_OK; } -uint16_t DecodeVLANGetId(const Packet *p, uint8_t layer) -{ - if (unlikely(layer > 1)) - return 0; - if (p->vlan_idx > layer) { - return p->vlan_id[layer]; - } - return 0; -} - typedef struct IEEE8021ahHdr_ { uint32_t flags; uint8_t c_destination[6]; diff --git a/src/decode-vlan.h b/src/decode-vlan.h index bdc0c0cc1c6a..809038dbe6fc 100644 --- a/src/decode-vlan.h +++ b/src/decode-vlan.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2010 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -36,10 +36,6 @@ uint16_t DecodeVLANGetId(const struct Packet_ *, uint8_t layer); #define GET_VLAN_ID(vlanh) ((uint16_t)(SCNtohs((vlanh)->vlan_cfi) & 0x0FFF)) #define GET_VLAN_PROTO(vlanh) ((SCNtohs((vlanh)->protocol))) -/* return vlan id in host byte order */ -#define VLAN_GET_ID1(p) DecodeVLANGetId((p), 0) -#define VLAN_GET_ID2(p) DecodeVLANGetId((p), 1) - /** Vlan header struct */ typedef struct VLANHdr_ { uint16_t vlan_cfi; @@ -51,5 +47,9 @@ typedef struct VLANHdr_ { void DecodeVLANRegisterTests(void); +/** VLAN max encapsulation layer count/index */ +#define VLAN_MAX_LAYERS 3 +#define VLAN_MAX_LAYER_IDX (VLAN_MAX_LAYERS - 1) + #endif /* __DECODE_VLAN_H__ */ diff --git a/src/decode.c b/src/decode.c index 6a064cfd4199..303459e086bc 100644 --- a/src/decode.c +++ b/src/decode.c @@ -412,8 +412,7 @@ Packet *PacketDefragPktSetup(Packet *parent, const uint8_t *pkt, uint32_t len, u p->tenant_id = parent->tenant_id; /* tell new packet it's part of a tunnel */ SET_TUNNEL_PKT(p); - p->vlan_id[0] = parent->vlan_id[0]; - p->vlan_id[1] = parent->vlan_id[1]; + memcpy(&p->vlan_id[0], &parent->vlan_id[0], sizeof(p->vlan_id)); p->vlan_idx = parent->vlan_idx; p->livedev = parent->livedev; @@ -555,6 +554,7 @@ void DecodeRegisterPerfCounters(DecodeThreadVars *dtv, ThreadVars *tv) dtv->counter_gre = StatsRegisterCounter("decoder.gre", tv); dtv->counter_vlan = StatsRegisterCounter("decoder.vlan", tv); dtv->counter_vlan_qinq = StatsRegisterCounter("decoder.vlan_qinq", tv); + dtv->counter_vlan_qinqinq = StatsRegisterCounter("decoder.vlan_qinqinq", tv); dtv->counter_vxlan = StatsRegisterCounter("decoder.vxlan", tv); dtv->counter_vntag = StatsRegisterCounter("decoder.vntag", tv); dtv->counter_ieee8021ah = StatsRegisterCounter("decoder.ieee8021ah", tv); diff --git a/src/decode.h b/src/decode.h index 2646e0824194..b39502f54523 100644 --- a/src/decode.h +++ b/src/decode.h @@ -225,7 +225,6 @@ typedef struct Address_ { (p)->pktlen = (len); \ } while (0) - /* Port is just a uint16_t */ typedef uint16_t Port; #define SET_PORT(v, p) ((p) = (v)) @@ -453,7 +452,7 @@ typedef struct Packet_ * has the exact same tuple as the lower levels */ uint8_t recursion_level; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; uint8_t vlan_idx; /* flow */ @@ -700,6 +699,7 @@ typedef struct DecodeThreadVars_ uint16_t counter_gre; uint16_t counter_vlan; uint16_t counter_vlan_qinq; + uint16_t counter_vlan_qinqinq; uint16_t counter_vxlan; uint16_t counter_vntag; uint16_t counter_ieee8021ah; @@ -1185,7 +1185,7 @@ static inline bool DecodeNetworkLayer(ThreadVars *tv, DecodeThreadVars *dtv, case ETHERNET_TYPE_VLAN: case ETHERNET_TYPE_8021AD: case ETHERNET_TYPE_8021QINQ: - if (p->vlan_idx >= 2) { + if (p->vlan_idx > VLAN_MAX_LAYER_IDX) { ENGINE_SET_EVENT(p,VLAN_HEADER_TOO_MANY_LAYERS); } else { DecodeVLAN(tv, dtv, p, data, len); diff --git a/src/defrag-hash.c b/src/defrag-hash.c index dda23016429b..2f19ce28ee13 100644 --- a/src/defrag-hash.c +++ b/src/defrag-hash.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -137,8 +137,7 @@ static void DefragTrackerInit(DefragTracker *dt, Packet *p) dt->af = AF_INET6; } dt->proto = IP_GET_IPPROTO(p); - dt->vlan_id[0] = p->vlan_id[0]; - dt->vlan_id[1] = p->vlan_id[1]; + memcpy(&dt->vlan_id[0], &p->vlan_id[0], sizeof(dt->vlan_id)); dt->policy = DefragGetOsPolicy(p); dt->host_timeout = DefragPolicyGetHostTimeout(p); dt->remove = 0; @@ -361,9 +360,10 @@ typedef struct DefragHashKey4_ { struct { uint32_t src, dst; uint32_t id; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; + uint16_t pad[1]; }; - uint32_t u32[4]; + uint32_t u32[5]; }; } DefragHashKey4; @@ -372,9 +372,10 @@ typedef struct DefragHashKey6_ { struct { uint32_t src[4], dst[4]; uint32_t id; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; + uint16_t pad[1]; }; - uint32_t u32[10]; + uint32_t u32[11]; }; } DefragHashKey6; @@ -392,7 +393,7 @@ static inline uint32_t DefragHashGetKey(Packet *p) uint32_t key; if (p->ip4h != NULL) { - DefragHashKey4 dhk; + DefragHashKey4 dhk = { .pad[0] = 0 }; if (p->src.addr_data32[0] > p->dst.addr_data32[0]) { dhk.src = p->src.addr_data32[0]; dhk.dst = p->dst.addr_data32[0]; @@ -401,13 +402,13 @@ static inline uint32_t DefragHashGetKey(Packet *p) dhk.dst = p->src.addr_data32[0]; } dhk.id = (uint32_t)IPV4_GET_IPID(p); - dhk.vlan_id[0] = p->vlan_id[0]; - dhk.vlan_id[1] = p->vlan_id[1]; + memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id)); - uint32_t hash = hashword(dhk.u32, 4, defrag_config.hash_rand); + uint32_t hash = + hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand); key = hash % defrag_config.hash_size; } else if (p->ip6h != NULL) { - DefragHashKey6 dhk; + DefragHashKey6 dhk = { .pad[0] = 0 }; if (DefragHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { dhk.src[0] = p->src.addr_data32[0]; dhk.src[1] = p->src.addr_data32[1]; @@ -428,10 +429,10 @@ static inline uint32_t DefragHashGetKey(Packet *p) dhk.dst[3] = p->src.addr_data32[3]; } dhk.id = IPV6_EXTHDR_GET_FH_ID(p); - dhk.vlan_id[0] = p->vlan_id[0]; - dhk.vlan_id[1] = p->vlan_id[1]; + memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id)); - uint32_t hash = hashword(dhk.u32, 10, defrag_config.hash_rand); + uint32_t hash = + hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand); key = hash % defrag_config.hash_size; } else key = 0; @@ -441,15 +442,12 @@ static inline uint32_t DefragHashGetKey(Packet *p) /* Since two or more trackers can have the same hash key, we need to compare * the tracker with the current tracker key. */ -#define CMP_DEFRAGTRACKER(d1,d2,id) \ - (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && \ - CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \ - (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && \ - CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \ - (d1)->proto == IP_GET_IPPROTO(d2) && \ - (d1)->id == (id) && \ - (d1)->vlan_id[0] == (d2)->vlan_id[0] && \ - (d1)->vlan_id[1] == (d2)->vlan_id[1]) +#define CMP_DEFRAGTRACKER(d1, d2, id) \ + (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \ + (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \ + (d1)->proto == IP_GET_IPPROTO(d2) && (d1)->id == (id) && \ + (d1)->vlan_id[0] == (d2)->vlan_id[0] && (d1)->vlan_id[1] == (d2)->vlan_id[1] && \ + (d1)->vlan_id[2] == (d2)->vlan_id[2]) static inline int DefragTrackerCompare(DefragTracker *t, Packet *p) { @@ -469,7 +467,7 @@ static inline int DefragTrackerCompare(DefragTracker *t, Packet *p) * Get a new defrag tracker. We're checking memcap first and will try to make room * if the memcap is reached. * - * \retval dt *LOCKED* tracker on succes, NULL on error. + * \retval dt *LOCKED* tracker on success, NULL on error. */ static DefragTracker *DefragTrackerGetNew(Packet *p) { diff --git a/src/defrag.c b/src/defrag.c index 989b39cb3389..a4c307834f08 100644 --- a/src/defrag.c +++ b/src/defrag.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2007-2012 Open Information Security Foundation +/* Copyright (C) 2007-2022 Open Information Security Foundation * * You can copy, redistribute or modify this Program under the terms of * the GNU General Public License version 2 as published by the Free @@ -2259,6 +2259,41 @@ static int DefragVlanQinQTest(void) PASS; } +/** + * Like DefragVlanTest, but for QinQinQ, testing the third level VLAN ID. + */ +static int DefragVlanQinQinQTest(void) +{ + Packet *r = NULL; + + DefragInit(); + + Packet *p1 = BuildTestPacket(IPPROTO_ICMP, 1, 0, 1, 'A', 8); + FAIL_IF_NULL(p1); + Packet *p2 = BuildTestPacket(IPPROTO_ICMP, 1, 1, 0, 'B', 8); + FAIL_IF_NULL(p2); + + /* With no VLAN IDs set, packets should re-assemble. */ + FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2)) == NULL); + SCFree(r); + + /* With mismatched VLANs, packets should not re-assemble. */ + p1->vlan_id[0] = 1; + p2->vlan_id[0] = 1; + p1->vlan_id[1] = 2; + p2->vlan_id[1] = 2; + p1->vlan_id[2] = 3; + p2->vlan_id[2] = 4; + FAIL_IF((r = Defrag(NULL, NULL, p1)) != NULL); + FAIL_IF((r = Defrag(NULL, NULL, p2)) != NULL); + + PacketFree(p1); + PacketFree(p2); + DefragDestroy(); + + PASS; +} static int DefragTrackerReuseTest(void) { int id = 1; @@ -2508,6 +2543,7 @@ void DefragRegisterTests(void) UtRegisterTest("DefragVlanTest", DefragVlanTest); UtRegisterTest("DefragVlanQinQTest", DefragVlanQinQTest); + UtRegisterTest("DefragVlanQinQinQTest", DefragVlanQinQinQTest); UtRegisterTest("DefragTrackerReuseTest", DefragTrackerReuseTest); UtRegisterTest("DefragTimeoutTest", DefragTimeoutTest); UtRegisterTest("DefragMfIpv4Test", DefragMfIpv4Test); diff --git a/src/defrag.h b/src/defrag.h index 016aa3ea5cd5..11e6a619b2f1 100644 --- a/src/defrag.h +++ b/src/defrag.h @@ -87,7 +87,7 @@ typedef struct DefragTracker_ { SCMutex lock; /**< Mutex for locking list operations on * this tracker. */ - uint16_t vlan_id[2]; /**< VLAN ID tracker applies to. */ + uint16_t vlan_id[VLAN_MAX_LAYERS]; /**< VLAN ID tracker applies to. */ uint32_t id; /**< IP ID for this tracker. 32 bits for IPv6, 16 * for IPv4. */ diff --git a/src/flow-hash.c b/src/flow-hash.c index 387adf0d6c23..9edd6d1daed5 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -42,6 +42,7 @@ #include "util-time.h" #include "util-debug.h" +#include "util-device.h" #include "util-hash-lookup3.h" @@ -87,11 +88,13 @@ typedef struct FlowHashKey4_ { struct { uint32_t addrs[2]; uint16_t ports[2]; - uint16_t proto; /**< u16 so proto and recur add up to u32 */ - uint16_t recur; /**< u16 so proto and recur add up to u32 */ - uint16_t vlan_id[2]; + uint8_t proto; /**< u8 so proto and recur and livedev add up to u32 */ + uint8_t recur; + uint16_t livedev; + uint16_t vlan_id[VLAN_MAX_LAYERS]; + uint16_t pad[1]; }; - const uint32_t u32[5]; + const uint32_t u32[6]; }; } FlowHashKey4; @@ -100,11 +103,13 @@ typedef struct FlowHashKey6_ { struct { uint32_t src[4], dst[4]; uint16_t ports[2]; - uint16_t proto; /**< u16 so proto and recur add up to u32 */ - uint16_t recur; /**< u16 so proto and recur add up to u32 */ - uint16_t vlan_id[2]; + uint8_t proto; /**< u8 so proto and recur and livedev add up to u32 */ + uint8_t recur; + uint16_t livedev; + uint16_t vlan_id[VLAN_MAX_LAYERS]; + uint16_t pad[1]; }; - const uint32_t u32[11]; + const uint32_t u32[12]; }; } FlowHashKey6; @@ -112,7 +117,9 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p) { uint32_t hash = 0; if (p->ip4h != NULL) { - FlowHashKey4 fhk; + FlowHashKey4 fhk = { + .pad[0] = 0, + }; int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]); fhk.addrs[1 - ai] = p->src.addr_data32[0]; @@ -121,16 +128,19 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p) fhk.ports[0] = 0xfedc; fhk.ports[1] = 0xba98; - fhk.proto = (uint16_t)p->proto; - fhk.recur = (uint16_t)p->recursion_level; + fhk.proto = (uint8_t)p->proto; + fhk.recur = (uint8_t)p->recursion_level; /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking * is disabled. */ fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask; fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } else if (p->ip6h != NULL) { - FlowHashKey6 fhk; + FlowHashKey6 fhk = { + .pad[0] = 0, + }; if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { fhk.src[0] = p->src.addr_data32[0]; fhk.src[1] = p->src.addr_data32[1]; @@ -153,12 +163,13 @@ uint32_t FlowGetIpPairProtoHash(const Packet *p) fhk.ports[0] = 0xfedc; fhk.ports[1] = 0xba98; - fhk.proto = (uint16_t)p->proto; - fhk.recur = (uint16_t)p->recursion_level; + fhk.proto = (uint8_t)p->proto; + fhk.recur = (uint8_t)p->recursion_level; fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask; fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 11, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } return hash; } @@ -182,7 +193,7 @@ static inline uint32_t FlowGetHash(const Packet *p) if (p->ip4h != NULL) { if (p->tcph != NULL || p->udph != NULL) { - FlowHashKey4 fhk; + FlowHashKey4 fhk = { .pad[0] = 0 }; int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]); fhk.addrs[1-ai] = p->src.addr_data32[0]; @@ -192,19 +203,24 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.ports[1-pi] = p->sp; fhk.ports[pi] = p->dp; - fhk.proto = (uint16_t)p->proto; - fhk.recur = (uint16_t)p->recursion_level; + fhk.proto = p->proto; + fhk.recur = p->recursion_level; + /* g_livedev_mask sets the livedev ids to 0 if livedev.use-for-tracking + * is disabled. */ + uint16_t devid = p->livedev ? p->livedev->id : 0; + fhk.livedev = devid & g_livedev_mask; /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking * is disabled. */ fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask; fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) { uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p)); uint32_t pdst = IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p)); - FlowHashKey4 fhk; + FlowHashKey4 fhk = { .pad[0] = 0 }; const int ai = (psrc > pdst); fhk.addrs[1-ai] = psrc; @@ -214,29 +230,35 @@ static inline uint32_t FlowGetHash(const Packet *p) fhk.ports[1-pi] = p->icmpv4vars.emb_sport; fhk.ports[pi] = p->icmpv4vars.emb_dport; - fhk.proto = (uint16_t)ICMPV4_GET_EMB_PROTO(p); - fhk.recur = (uint16_t)p->recursion_level; + fhk.proto = ICMPV4_GET_EMB_PROTO(p); + fhk.recur = p->recursion_level; + uint16_t devid = p->livedev ? p->livedev->id : 0; + fhk.livedev = devid & g_livedev_mask; fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask; fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } else { - FlowHashKey4 fhk; + FlowHashKey4 fhk = { .pad[0] = 0 }; const int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]); fhk.addrs[1-ai] = p->src.addr_data32[0]; fhk.addrs[ai] = p->dst.addr_data32[0]; fhk.ports[0] = 0xfeed; fhk.ports[1] = 0xbeef; - fhk.proto = (uint16_t)p->proto; - fhk.recur = (uint16_t)p->recursion_level; + fhk.proto = p->proto; + fhk.recur = p->recursion_level; + uint16_t devid = p->livedev ? p->livedev->id : 0; + fhk.livedev = devid & g_livedev_mask; fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask; fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } } else if (p->ip6h != NULL) { - FlowHashKey6 fhk; + FlowHashKey6 fhk = { .pad[0] = 0 }; if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) { fhk.src[0] = p->src.addr_data32[0]; fhk.src[1] = p->src.addr_data32[1]; @@ -260,12 +282,15 @@ static inline uint32_t FlowGetHash(const Packet *p) const int pi = (p->sp > p->dp); fhk.ports[1-pi] = p->sp; fhk.ports[pi] = p->dp; - fhk.proto = (uint16_t)p->proto; - fhk.recur = (uint16_t)p->recursion_level; + fhk.proto = p->proto; + fhk.recur = p->recursion_level; + uint16_t devid = p->livedev ? p->livedev->id : 0; + fhk.livedev = devid & g_livedev_mask; fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask; fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = p->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 11, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } return hash; @@ -284,7 +309,9 @@ uint32_t FlowKeyGetHash(FlowKey *fk) uint32_t hash = 0; if (fk->src.family == AF_INET) { - FlowHashKey4 fhk; + FlowHashKey4 fhk = { + .pad[0] = 0, + }; int ai = (fk->src.address.address_un_data32[0] > fk->dst.address.address_un_data32[0]); fhk.addrs[1-ai] = fk->src.address.address_un_data32[0]; fhk.addrs[ai] = fk->dst.address.address_un_data32[0]; @@ -293,14 +320,18 @@ uint32_t FlowKeyGetHash(FlowKey *fk) fhk.ports[1-pi] = fk->sp; fhk.ports[pi] = fk->dp; - fhk.proto = (uint16_t)fk->proto; - fhk.recur = (uint16_t)fk->recursion_level; + fhk.proto = fk->proto; + fhk.recur = fk->recursion_level; + fhk.livedev = fk->livedev_id & g_livedev_mask; fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask; fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = fk->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 5, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } else { - FlowHashKey6 fhk; + FlowHashKey6 fhk = { + .pad[0] = 0, + }; if (FlowHashRawAddressIPv6GtU32(fk->src.address.address_un_data32, fk->dst.address.address_un_data32)) { fhk.src[0] = fk->src.address.address_un_data32[0]; @@ -325,12 +356,14 @@ uint32_t FlowKeyGetHash(FlowKey *fk) const int pi = (fk->sp > fk->dp); fhk.ports[1-pi] = fk->sp; fhk.ports[pi] = fk->dp; - fhk.proto = (uint16_t)fk->proto; - fhk.recur = (uint16_t)fk->recursion_level; + fhk.proto = fk->proto; + fhk.recur = fk->recursion_level; + fhk.livedev = fk->livedev_id & g_livedev_mask; fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask; fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask; + fhk.vlan_id[2] = fk->vlan_id[2] & g_vlan_mask; - hash = hashword(fhk.u32, 11, flow_config.hash_rand); + hash = hashword(fhk.u32, ARRAY_SIZE(fhk.u32), flow_config.hash_rand); } return hash; } @@ -355,10 +388,18 @@ static inline bool CmpAddrsAndPorts(const uint32_t src1[4], src_port1 == dst_port2 && dst_port1 == src_port2); } -static inline bool CmpVlanIds(const uint16_t vlan_id1[2], const uint16_t vlan_id2[2]) +static inline bool CmpVlanIds( + const uint16_t vlan_id1[VLAN_MAX_LAYERS], const uint16_t vlan_id2[VLAN_MAX_LAYERS]) { return ((vlan_id1[0] ^ vlan_id2[0]) & g_vlan_mask) == 0 && - ((vlan_id1[1] ^ vlan_id2[1]) & g_vlan_mask) == 0; + ((vlan_id1[1] ^ vlan_id2[1]) & g_vlan_mask) == 0 && + ((vlan_id1[2] ^ vlan_id2[2]) & g_vlan_mask) == 0; +} + +static inline bool CmpLiveDevIds(const LiveDevice *livedev, const uint16_t id) +{ + uint16_t devid = livedev ? livedev->id : 0; + return (((devid ^ id) & g_livedev_mask) == 0); } /* Since two or more flows can have the same hash key, we need to compare @@ -369,10 +410,9 @@ static inline bool CmpFlowPacket(const Flow *f, const Packet *p) const uint32_t *f_dst = f->dst.address.address_un_data32; const uint32_t *p_src = p->src.address.address_un_data32; const uint32_t *p_dst = p->dst.address.address_un_data32; - return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, p_src, p_dst, p->sp, - p->dp) && f->proto == p->proto && - f->recursion_level == p->recursion_level && - CmpVlanIds(f->vlan_id, p->vlan_id); + return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, p_src, p_dst, p->sp, p->dp) && + f->proto == p->proto && f->recursion_level == p->recursion_level && + CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0); } static inline bool CmpFlowKey(const Flow *f, const FlowKey *k) @@ -381,10 +421,9 @@ static inline bool CmpFlowKey(const Flow *f, const FlowKey *k) const uint32_t *f_dst = f->dst.address.address_un_data32; const uint32_t *k_src = k->src.address.address_un_data32; const uint32_t *k_dst = k->dst.address.address_un_data32; - return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, k_src, k_dst, k->sp, - k->dp) && f->proto == k->proto && - f->recursion_level == k->recursion_level && - CmpVlanIds(f->vlan_id, k->vlan_id); + return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, k_src, k_dst, k->sp, k->dp) && + f->proto == k->proto && f->recursion_level == k->recursion_level && + CmpVlanIds(f->vlan_id, k->vlan_id) && CmpLiveDevIds(f->livedev, k->livedev_id); } static inline bool CmpAddrsAndICMPTypes(const uint32_t src1[4], @@ -407,10 +446,10 @@ static inline bool CmpFlowICMPPacket(const Flow *f, const Packet *p) const uint32_t *f_dst = f->dst.address.address_un_data32; const uint32_t *p_src = p->src.address.address_un_data32; const uint32_t *p_dst = p->dst.address.address_un_data32; - return CmpAddrsAndICMPTypes(f_src, f_dst, f->icmp_s.type, - f->icmp_d.type, p_src, p_dst, p->icmp_s.type, p->icmp_d.type) && - f->proto == p->proto && f->recursion_level == p->recursion_level && - CmpVlanIds(f->vlan_id, p->vlan_id); + return CmpAddrsAndICMPTypes(f_src, f_dst, f->icmp_s.type, f->icmp_d.type, p_src, p_dst, + p->icmp_s.type, p->icmp_d.type) && + f->proto == p->proto && f->recursion_level == p->recursion_level && + CmpVlanIds(f->vlan_id, p->vlan_id) && (f->livedev == p->livedev || g_livedev_mask == 0); } /** @@ -433,7 +472,8 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p))) && f->sp == p->icmpv4vars.emb_sport && f->dp == p->icmpv4vars.emb_dport && f->proto == ICMPV4_GET_EMB_PROTO(p) && f->recursion_level == p->recursion_level && - CmpVlanIds(f->vlan_id, p->vlan_id)) { + CmpVlanIds(f->vlan_id, p->vlan_id) && + (f->livedev == p->livedev || g_livedev_mask == 0)) { return 1; /* check the less likely case where the ICMP error was a response to @@ -442,7 +482,8 @@ static inline int FlowCompareICMPv4(Flow *f, const Packet *p) (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p))) && f->dp == p->icmpv4vars.emb_sport && f->sp == p->icmpv4vars.emb_dport && f->proto == ICMPV4_GET_EMB_PROTO(p) && - f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id)) { + f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id) && + (f->livedev == p->livedev || g_livedev_mask == 0)) { return 1; } @@ -473,7 +514,7 @@ static inline int FlowCompareESP(Flow *f, const Packet *p) return CmpAddrs(f_src, p_src) && CmpAddrs(f_dst, p_dst) && f->proto == p->proto && f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id) && - f->esp.spi == ESP_GET_SPI(p); + f->esp.spi == ESP_GET_SPI(p) && (f->livedev == p->livedev || g_livedev_mask == 0); } void FlowSetupPacket(Packet *p) @@ -614,7 +655,7 @@ static inline void NoFlowHandleIPS(Packet *p) * \param tv thread vars * \param fls lookup support vars * - * \retval f *LOCKED* flow on succes, NULL on error. + * \retval f *LOCKED* flow on success, NULL on error. */ static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, Packet *p) { @@ -964,6 +1005,61 @@ Flow *FlowGetExistingFlowFromFlowId(int64_t flow_id) return f; } +/** \brief Look for existing Flow using a FlowKey + * + * Hash retrieval function for flows. Looks up the hash bucket containing the + * flow pointer. Then compares the packet with the found flow to see if it is + * the flow we need. If it isn't, walk the list until the right flow is found. + * + * + * \param key Pointer to FlowKey build using flow to look for + * \param hash Value of the flow hash + * \retval f *LOCKED* flow or NULL + */ +static Flow *FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash) +{ + /* get our hash bucket and lock it */ + FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; + FBLOCK_LOCK(fb); + + SCLogDebug("fb %p fb->head %p", fb, fb->head); + + /* return if the bucket don't have a flow */ + if (fb->head == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + + /* ok, we have a flow in the bucket. Let's find out if it is our flow */ + Flow *f = fb->head; + + /* see if this is the flow we are looking for */ + if (FlowCompareKey(f, key) == 0) { + while (f) { + f = f->next; + + if (f == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + + if (FlowCompareKey(f, key) != 0) { + /* found our flow, lock & return */ + FLOWLOCK_WRLOCK(f); + + FBLOCK_UNLOCK(fb); + return f; + } + } + } + + /* lock & return */ + FLOWLOCK_WRLOCK(f); + + FBLOCK_UNLOCK(fb); + return f; +} + /** \brief Get or create a Flow using a FlowKey * * Hash retrieval function for flows. Looks up the hash bucket containing the @@ -993,8 +1089,8 @@ Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t ha return NULL; } f->proto = key->proto; - f->vlan_id[0] = key->vlan_id[0]; - f->vlan_id[1] = key->vlan_id[1]; + memcpy(&f->vlan_id[0], &key->vlan_id[0], sizeof(f->vlan_id)); + ; f->src.addr_data32[0] = key->src.addr_data32[0]; f->src.addr_data32[1] = key->src.addr_data32[1]; f->src.addr_data32[2] = key->src.addr_data32[2]; @@ -1006,6 +1102,7 @@ Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t ha f->sp = key->sp; f->dp = key->dp; f->recursion_level = 0; + // f->livedev is set by caller EBPFCreateFlowForKey f->flow_hash = hash; if (key->src.family == AF_INET) { f->flags |= FLOW_IPV4; @@ -1028,61 +1125,6 @@ Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t ha return f; } -/** \brief Look for existing Flow using a FlowKey - * - * Hash retrieval function for flows. Looks up the hash bucket containing the - * flow pointer. Then compares the packet with the found flow to see if it is - * the flow we need. If it isn't, walk the list until the right flow is found. - * - * - * \param key Pointer to FlowKey build using flow to look for - * \param hash Value of the flow hash - * \retval f *LOCKED* flow or NULL - */ -Flow *FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash) -{ - /* get our hash bucket and lock it */ - FlowBucket *fb = &flow_hash[hash % flow_config.hash_size]; - FBLOCK_LOCK(fb); - - SCLogDebug("fb %p fb->head %p", fb, fb->head); - - /* return if the bucket don't have a flow */ - if (fb->head == NULL) { - FBLOCK_UNLOCK(fb); - return NULL; - } - - /* ok, we have a flow in the bucket. Let's find out if it is our flow */ - Flow *f = fb->head; - - /* see if this is the flow we are looking for */ - if (FlowCompareKey(f, key) == 0) { - while (f) { - f = f->next; - - if (f == NULL) { - FBLOCK_UNLOCK(fb); - return NULL; - } - - if (FlowCompareKey(f, key) != 0) { - /* found our flow, lock & return */ - FLOWLOCK_WRLOCK(f); - - FBLOCK_UNLOCK(fb); - return f; - } - } - } - - /* lock & return */ - FLOWLOCK_WRLOCK(f); - - FBLOCK_UNLOCK(fb); - return f; -} - #define FLOW_GET_NEW_TRIES 5 /* inline locking wrappers to make profiling easier */ diff --git a/src/flow-hash.h b/src/flow-hash.h index a8c27f2ea4dd..201eb6414543 100644 --- a/src/flow-hash.h +++ b/src/flow-hash.h @@ -82,7 +82,6 @@ typedef struct FlowBucket_ { Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *tctx, Packet *, Flow **); Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash); -Flow *FlowGetExistingFlowFromHash(FlowKey * key, uint32_t hash); Flow *FlowGetExistingFlowFromFlowId(int64_t flow_id); uint32_t FlowKeyGetHash(FlowKey *flow_key); uint32_t FlowGetIpPairProtoHash(const Packet *p); diff --git a/src/flow-timeout.c b/src/flow-timeout.c index 9196c22dbef0..91dd872375e4 100644 --- a/src/flow-timeout.c +++ b/src/flow-timeout.c @@ -90,8 +90,7 @@ static inline Packet *FlowForceReassemblyPseudoPacketSetup(Packet *p, p->flags |= PKT_STREAM_EOF; p->flags |= PKT_HAS_FLOW; p->flags |= PKT_PSEUDO_STREAM_END; - p->vlan_id[0] = f->vlan_id[0]; - p->vlan_id[1] = f->vlan_id[1]; + memcpy(&p->vlan_id[0], &f->vlan_id[0], sizeof(p->vlan_id)); p->vlan_idx = f->vlan_idx; p->livedev = (struct LiveDevice_ *)f->livedev; diff --git a/src/flow-util.c b/src/flow-util.c index 324f9be87840..3572c0823f4e 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -150,8 +150,7 @@ void FlowInit(Flow *f, const Packet *p) f->proto = p->proto; f->recursion_level = p->recursion_level; - f->vlan_id[0] = p->vlan_id[0]; - f->vlan_id[1] = p->vlan_id[1]; + memcpy(&f->vlan_id[0], &p->vlan_id[0], sizeof(f->vlan_id)); f->vlan_idx = p->vlan_idx; f->livedev = p->livedev; diff --git a/src/flow.h b/src/flow.h index 6ec901c00972..f6c2eb47fda9 100644 --- a/src/flow.h +++ b/src/flow.h @@ -301,7 +301,8 @@ typedef struct FlowKey_ Port sp, dp; uint8_t proto; uint8_t recursion_level; - uint16_t vlan_id[2]; + uint16_t livedev_id; + uint16_t vlan_id[VLAN_MAX_LAYERS]; } FlowKey; typedef struct FlowAddress_ { @@ -364,7 +365,7 @@ typedef struct Flow_ }; uint8_t proto; uint8_t recursion_level; - uint16_t vlan_id[2]; + uint16_t vlan_id[VLAN_MAX_LAYERS]; uint8_t vlan_idx; diff --git a/src/output-json-alert.c b/src/output-json-alert.c index f7b67fa0c082..d7918e81ffaa 100644 --- a/src/output-json-alert.c +++ b/src/output-json-alert.c @@ -229,12 +229,12 @@ static void AlertJsonDns(const Flow *f, const uint64_t tx_id, JsonBuilder *js) dns_state, tx_id); if (txptr) { jb_open_object(js, "dns"); - JsonBuilder *qjs = JsonDNSLogQuery(txptr, tx_id); + JsonBuilder *qjs = JsonDNSLogQuery(txptr); if (qjs != NULL) { jb_set_object(js, "query", qjs); jb_free(qjs); } - JsonBuilder *ajs = JsonDNSLogAnswer(txptr, tx_id); + JsonBuilder *ajs = JsonDNSLogAnswer(txptr); if (ajs != NULL) { jb_set_object(js, "answer", ajs); jb_free(ajs); diff --git a/src/output-json-dns.c b/src/output-json-dns.c index d5729c85961c..0b6589d5c1bf 100644 --- a/src/output-json-dns.c +++ b/src/output-json-dns.c @@ -263,7 +263,7 @@ typedef struct LogDnsLogThread_ { OutputJsonThreadCtx *ctx; } LogDnsLogThread; -JsonBuilder *JsonDNSLogQuery(void *txptr, uint64_t tx_id) +JsonBuilder *JsonDNSLogQuery(void *txptr) { JsonBuilder *queryjb = jb_new_array(); if (queryjb == NULL) { @@ -292,7 +292,7 @@ JsonBuilder *JsonDNSLogQuery(void *txptr, uint64_t tx_id) return queryjb; } -JsonBuilder *JsonDNSLogAnswer(void *txptr, uint64_t tx_id) +JsonBuilder *JsonDNSLogAnswer(void *txptr) { if (!rs_dns_do_log_answer(txptr, LOG_ALL_RRTYPES)) { return NULL; diff --git a/src/output-json-dns.h b/src/output-json-dns.h index 9d0e451328e3..1e19427361b8 100644 --- a/src/output-json-dns.h +++ b/src/output-json-dns.h @@ -26,7 +26,7 @@ void JsonDnsLogRegister(void); -JsonBuilder *JsonDNSLogQuery(void *txptr, uint64_t tx_id) __attribute__((nonnull)); -JsonBuilder *JsonDNSLogAnswer(void *txptr, uint64_t tx_id) __attribute__((nonnull)); +JsonBuilder *JsonDNSLogQuery(void *txptr) __attribute__((nonnull)); +JsonBuilder *JsonDNSLogAnswer(void *txptr) __attribute__((nonnull)); #endif /* __OUTPUT_JSON_DNS_H__ */ diff --git a/src/output-json-flow.c b/src/output-json-flow.c index a52e20eb28b3..07bcd954f2f5 100644 --- a/src/output-json-flow.c +++ b/src/output-json-flow.c @@ -113,6 +113,9 @@ static JsonBuilder *CreateEveHeaderFromFlow(const Flow *f) if (f->vlan_idx > 1) { jb_append_uint(jb, f->vlan_id[1]); } + if (f->vlan_idx > 2) { + jb_append_uint(jb, f->vlan_id[2]); + } jb_close(jb); } diff --git a/src/output-json-ftp.c b/src/output-json-ftp.c index 7177fb6a9dbc..ece9344bf409 100644 --- a/src/output-json-ftp.c +++ b/src/output-json-ftp.c @@ -46,7 +46,7 @@ #include "app-layer-ftp.h" #include "output-json-ftp.h" -static void EveFTPLogCommand(Flow *f, FTPTransaction *tx, JsonBuilder *jb) +static void EveFTPLogCommand(FTPTransaction *tx, JsonBuilder *jb) { /* Preallocate array objects to simplify failure case */ JsonBuilder *js_resplist = NULL; @@ -173,7 +173,7 @@ static int JsonFTPLogger(ThreadVars *tv, void *thread_data, if (f->alproto == ALPROTO_FTPDATA) { EveFTPDataAddMetadata(f, jb); } else { - EveFTPLogCommand(f, tx, jb); + EveFTPLogCommand(tx, jb); } if (!jb_close(jb)) { diff --git a/src/output-json-krb5.c b/src/output-json-krb5.c index 8381cfd6132f..5e6fbad5ecd1 100644 --- a/src/output-json-krb5.c +++ b/src/output-json-krb5.c @@ -60,7 +60,7 @@ static int JsonKRB5Logger(ThreadVars *tv, void *thread_data, } jb_open_object(jb, "krb5"); - if (!rs_krb5_log_json_response(jb, state, krb5tx)) { + if (!rs_krb5_log_json_response(jb, krb5tx)) { goto error; } jb_close(jb); diff --git a/src/output-json-mqtt.c b/src/output-json-mqtt.c index 7b3ca62131ac..9ea890508070 100644 --- a/src/output-json-mqtt.c +++ b/src/output-json-mqtt.c @@ -65,7 +65,7 @@ bool JsonMQTTAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) if (state) { MQTTTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_MQTT, state, tx_id); if (tx) { - return rs_mqtt_logger_log(state, tx, MQTT_DEFAULTS, js); + return rs_mqtt_logger_log(tx, MQTT_DEFAULTS, js); } } @@ -89,7 +89,7 @@ static int JsonMQTTLogger(ThreadVars *tv, void *thread_data, return TM_ECODE_FAILED; } - if (!rs_mqtt_logger_log(state, tx, thread->mqttlog_ctx->flags, js)) + if (!rs_mqtt_logger_log(tx, thread->mqttlog_ctx->flags, js)) goto error; OutputJsonBuilderBuffer(js, thread->ctx); diff --git a/src/output-json-netflow.c b/src/output-json-netflow.c index de9dbdb4ec84..2ac6995cfad6 100644 --- a/src/output-json-netflow.c +++ b/src/output-json-netflow.c @@ -117,6 +117,9 @@ static JsonBuilder *CreateEveHeaderFromNetFlow(const Flow *f, int dir) if (f->vlan_idx > 1) { jb_append_uint(js, f->vlan_id[1]); } + if (f->vlan_idx > 2) { + jb_append_uint(js, f->vlan_id[2]); + } jb_close(js); } diff --git a/src/output-json-rfb.c b/src/output-json-rfb.c index 285c22ab4482..cc12d2f1bbdc 100644 --- a/src/output-json-rfb.c +++ b/src/output-json-rfb.c @@ -48,11 +48,11 @@ bool JsonRFBAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) { - RFBState *state = FlowGetAppState(f); + void *state = FlowGetAppState(f); if (state) { RFBTransaction *tx = AppLayerParserGetTx(f->proto, ALPROTO_RFB, state, tx_id); if (tx) { - return rs_rfb_logger_log(state, tx, js); + return rs_rfb_logger_log(tx, js); } } @@ -69,7 +69,7 @@ static int JsonRFBLogger(ThreadVars *tv, void *thread_data, return TM_ECODE_FAILED; } - if (!rs_rfb_logger_log(NULL, tx, js)) { + if (!rs_rfb_logger_log(tx, js)) { goto error; } diff --git a/src/output-json-smtp.c b/src/output-json-smtp.c index 99771ec68fb4..cc3003907585 100644 --- a/src/output-json-smtp.c +++ b/src/output-json-smtp.c @@ -51,7 +51,7 @@ #include "output-json-smtp.h" #include "output-json-email-common.h" -static void EveSmtpDataLogger(const Flow *f, void *state, void *vtx, uint64_t tx_id, JsonBuilder *js) +static void EveSmtpDataLogger(void *state, void *vtx, JsonBuilder *js) { SMTPTransaction *tx = vtx; SMTPString *rcptto_str; @@ -81,7 +81,7 @@ static int JsonSmtpLogger(ThreadVars *tv, void *thread_data, const Packet *p, Fl return TM_ECODE_OK; jb_open_object(jb, "smtp"); - EveSmtpDataLogger(f, state, tx, tx_id, jb); + EveSmtpDataLogger(state, tx, jb); jb_close(jb); EveEmailLogJson(jhl, jb, p, f, state, tx, tx_id); @@ -99,7 +99,7 @@ bool EveSMTPAddMetadata(const Flow *f, uint64_t tx_id, JsonBuilder *js) if (smtp_state) { SMTPTransaction *tx = AppLayerParserGetTx(IPPROTO_TCP, ALPROTO_SMTP, smtp_state, tx_id); if (tx) { - EveSmtpDataLogger(f, smtp_state, tx, tx_id, js); + EveSmtpDataLogger(smtp_state, tx, js); return true; } } diff --git a/src/output-json.c b/src/output-json.c index 09128403a9dc..95a6e5ef4c25 100644 --- a/src/output-json.c +++ b/src/output-json.c @@ -836,6 +836,9 @@ JsonBuilder *CreateEveHeader(const Packet *p, enum OutputJsonLogDirection dir, if (p->vlan_idx > 1) { jb_append_uint(js, p->vlan_id[1]); } + if (p->vlan_idx > 2) { + jb_append_uint(js, p->vlan_id[2]); + } jb_close(js); } diff --git a/src/runmode-dpdk.c b/src/runmode-dpdk.c index 72e3ed2a51e8..82e6aee57f27 100644 --- a/src/runmode-dpdk.c +++ b/src/runmode-dpdk.c @@ -44,6 +44,7 @@ #include "util-dpdk-i40e.h" #include "util-dpdk-ice.h" #include "util-dpdk-ixgbe.h" +#include "util-dpdk-bonding.h" #include "util-time.h" #include "util-conf.h" #include "suricata.h" @@ -765,7 +766,7 @@ static void DeviceSetPMDSpecificRSS(struct rte_eth_rss_conf *rss_conf, const cha { // RSS is configured in a specific way for a driver i40e and DPDK version <= 19.xx if (strcmp(driver_name, "net_i40e") == 0) - i40eDeviceSetRSSHashFunction(&rss_conf->rss_hf); + i40eDeviceSetRSSConf(rss_conf); if (strcmp(driver_name, "net_ice") == 0) iceDeviceSetRSSHashFunction(&rss_conf->rss_hf); if (strcmp(driver_name, "net_ixgbe") == 0) @@ -921,6 +922,52 @@ static void DumpRSSFlags(const uint64_t requested, const uint64_t actual) SCLogConfig("RTE_ETH_RSS_L4_DST_ONLY %sset", (actual & RTE_ETH_RSS_L4_DST_ONLY) ? "" : "NOT "); } +static void DumpRXOffloadCapabilities(const uint64_t rx_offld_capa) +{ + SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_STRIP - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_STRIP ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_IPV4_CKSUM - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_IPV4_CKSUM ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_UDP_CKSUM - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_UDP_CKSUM ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_TCP_CKSUM - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_TCP_CKSUM ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_TCP_LRO - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_TCP_LRO ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_QINQ_STRIP - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_QINQ_STRIP ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_MACSEC_STRIP - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_MACSEC_STRIP ? "" : "NOT "); +#if RTE_VERSION < RTE_VERSION_NUM(22, 11, 0, 0) + SCLogConfig("RTE_ETH_RX_OFFLOAD_HEADER_SPLIT - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_HEADER_SPLIT ? "" : "NOT "); +#endif + SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_FILTER - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_FILTER ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_VLAN_EXTEND - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_VLAN_EXTEND ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_SCATTER - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_SCATTER ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_TIMESTAMP - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_TIMESTAMP ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_SECURITY - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_SECURITY ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_KEEP_CRC - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_KEEP_CRC ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_SCTP_CKSUM - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_SCTP_CKSUM ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM ? "" : "NOT "); + SCLogConfig("RTE_ETH_RX_OFFLOAD_RSS_HASH - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_RSS_HASH ? "" : "NOT "); +#if RTE_VERSION >= RTE_VERSION_NUM(20, 11, 0, 0) + SCLogConfig("RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT - %savailable", + rx_offld_capa & RTE_ETH_RX_OFFLOAD_BUFFER_SPLIT ? "" : "NOT "); +#endif +} + static int DeviceValidateMTU(const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info) { if (iconf->mtu > dev_info->max_mtu || iconf->mtu < dev_info->min_mtu) { @@ -975,6 +1022,7 @@ static int32_t DeviceSetSocketID(uint16_t port_id, int32_t *socket_id) static void DeviceInitPortConf(const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info, struct rte_eth_conf *port_conf) { + DumpRXOffloadCapabilities(dev_info->rx_offload_capa); *port_conf = (struct rte_eth_conf){ .rxmode = { .mq_mode = RTE_ETH_MQ_RX_NONE, @@ -996,7 +1044,12 @@ static void DeviceInitPortConf(const DPDKIfaceConfig *iconf, .rss_hf = iconf->rss_hf, }; - DeviceSetPMDSpecificRSS(&port_conf->rx_adv_conf.rss_conf, dev_info->driver_name); + const char *dev_driver = dev_info->driver_name; + if (strcmp(dev_info->driver_name, "net_bonding") == 0) { + dev_driver = BondingDeviceDriverGet(iconf->port_id); + } + + DeviceSetPMDSpecificRSS(&port_conf->rx_adv_conf.rss_conf, dev_driver); uint64_t rss_hf_tmp = port_conf->rx_adv_conf.rss_conf.rss_hf & dev_info->flow_type_rss_offloads; @@ -1197,17 +1250,51 @@ static int DeviceConfigureIPS(DPDKIfaceConfig *iconf) SCReturnInt(0); } +/** + * Function verifies changes in e.g. device info after configuration has + * happened. Sometimes (e.g. DPDK Bond PMD with Intel NICs i40e/ixgbe) change + * device info only after the device configuration. + * @param iconf + * @param dev_info + * @return 0 on success, -EAGAIN when reconfiguration is needed, <0 on failure + */ +static int32_t DeviceVerifyPostConfigure( + const DPDKIfaceConfig *iconf, const struct rte_eth_dev_info *dev_info) +{ + struct rte_eth_dev_info post_conf_dev_info = { 0 }; + int32_t ret = rte_eth_dev_info_get(iconf->port_id, &post_conf_dev_info); + if (ret < 0) { + SCLogError("%s: getting device info failed (err: %s)", iconf->iface, rte_strerror(-ret)); + SCReturnInt(ret); + } + + if (dev_info->flow_type_rss_offloads != post_conf_dev_info.flow_type_rss_offloads || + dev_info->rx_offload_capa != post_conf_dev_info.rx_offload_capa || + dev_info->tx_offload_capa != post_conf_dev_info.tx_offload_capa || + dev_info->max_rx_queues != post_conf_dev_info.max_rx_queues || + dev_info->max_tx_queues != post_conf_dev_info.max_tx_queues || + dev_info->max_mtu != post_conf_dev_info.max_mtu) { + SCLogWarning("Device information severely changed after configuration, reconfiguring"); + return -EAGAIN; + } + + if (strcmp(dev_info->driver_name, "net_bonding") == 0) { + ret = BondingAllDevicesSameDriver(iconf->port_id); + if (ret < 0) { + SCLogError("%s: bond port uses port with different DPDK drivers", iconf->iface); + SCReturnInt(ret); + } + } + + return 0; +} + static int DeviceConfigure(DPDKIfaceConfig *iconf) { SCEnter(); - // configure device - int retval; - struct rte_eth_dev_info dev_info; - struct rte_eth_conf port_conf; - - retval = rte_eth_dev_get_port_by_name(iconf->iface, &(iconf->port_id)); + int32_t retval = rte_eth_dev_get_port_by_name(iconf->iface, &(iconf->port_id)); if (retval < 0) { - SCLogError("%s: getting port id failed (err=%d). Is device enabled?", iconf->iface, retval); + SCLogError("%s: getting port id failed (err: %s)", iconf->iface, rte_strerror(-retval)); SCReturnInt(retval); } @@ -1218,13 +1305,14 @@ static int DeviceConfigure(DPDKIfaceConfig *iconf) retval = DeviceSetSocketID(iconf->port_id, &iconf->socket_id); if (retval < 0) { - SCLogError("%s: invalid socket id (err=%d)", iconf->iface, retval); + SCLogError("%s: invalid socket id (err: %s)", iconf->iface, rte_strerror(-retval)); SCReturnInt(retval); } + struct rte_eth_dev_info dev_info = { 0 }; retval = rte_eth_dev_info_get(iconf->port_id, &dev_info); - if (retval != 0) { - SCLogError("%s: getting device info failed (err=%d)", iconf->iface, retval); + if (retval < 0) { + SCLogError("%s: getting device info failed (err: %s)", iconf->iface, rte_strerror(-retval)); SCReturnInt(retval); } @@ -1241,9 +1329,10 @@ static int DeviceConfigure(DPDKIfaceConfig *iconf) } retval = DeviceValidateMTU(iconf, &dev_info); - if (retval != 0) + if (retval < 0) return retval; + struct rte_eth_conf port_conf = { 0 }; DeviceInitPortConf(iconf, &dev_info, &port_conf); if (port_conf.rxmode.offloads & RTE_ETH_RX_OFFLOAD_CHECKSUM) { // Suricata does not need recalc checksums now @@ -1252,12 +1341,16 @@ static int DeviceConfigure(DPDKIfaceConfig *iconf) retval = rte_eth_dev_configure( iconf->port_id, iconf->nb_rx_queues, iconf->nb_tx_queues, &port_conf); - if (retval != 0) { - SCLogError("%s: failed to configure the device (port %u, err %d)", iconf->iface, - iconf->port_id, retval); + if (retval < 0) { + SCLogError("%s: failed to configure the device (port %u, err %s)", iconf->iface, + iconf->port_id, rte_strerror(-retval)); SCReturnInt(retval); } + retval = DeviceVerifyPostConfigure(iconf, &dev_info); + if (retval < 0) + return retval; + retval = rte_eth_dev_adjust_nb_rx_tx_desc( iconf->port_id, &iconf->nb_rx_desc, &iconf->nb_tx_desc); if (retval != 0) { @@ -1348,7 +1441,13 @@ static void *ParseDpdkConfigAndConfigureDevice(const char *iface) FatalError("DPDK configuration could not be parsed"); } - if (DeviceConfigure(iconf) != 0) { + retval = DeviceConfigure(iconf); + if (retval == -EAGAIN) { + // for e.g. bonding PMD it needs to be reconfigured + retval = DeviceConfigure(iconf); + } + + if (retval < 0) { // handles both configure attempts iconf->DerefFunc(iconf); retval = rte_eal_cleanup(); if (retval != 0) diff --git a/src/source-af-packet.c b/src/source-af-packet.c index 89f8c2e80319..0c50ed219aa6 100644 --- a/src/source-af-packet.c +++ b/src/source-af-packet.c @@ -2209,6 +2209,7 @@ static int AFPBypassCallback(Packet *p) keys[0]->port16[1] = GET_TCP_DST_PORT(p); keys[0]->vlan0 = p->vlan_id[0]; keys[0]->vlan1 = p->vlan_id[1]; + keys[0]->vlan2 = p->vlan_id[2]; if (IPV4_GET_IPPROTO(p) == IPPROTO_TCP) { keys[0]->ip_proto = 1; @@ -2234,6 +2235,7 @@ static int AFPBypassCallback(Packet *p) keys[1]->port16[1] = GET_TCP_SRC_PORT(p); keys[1]->vlan0 = p->vlan_id[0]; keys[1]->vlan1 = p->vlan_id[1]; + keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], @@ -2269,6 +2271,7 @@ static int AFPBypassCallback(Packet *p) keys[0]->port16[1] = GET_TCP_DST_PORT(p); keys[0]->vlan0 = p->vlan_id[0]; keys[0]->vlan1 = p->vlan_id[1]; + keys[0]->vlan2 = p->vlan_id[2]; if (IPV6_GET_NH(p) == IPPROTO_TCP) { keys[0]->ip_proto = 1; @@ -2296,6 +2299,7 @@ static int AFPBypassCallback(Packet *p) keys[1]->port16[1] = GET_TCP_SRC_PORT(p); keys[1]->vlan0 = p->vlan_id[0]; keys[1]->vlan1 = p->vlan_id[1]; + keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], @@ -2363,6 +2367,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[0]->port16[1] = htons(p->dp); keys[0]->vlan0 = p->vlan_id[0]; keys[0]->vlan1 = p->vlan_id[1]; + keys[0]->vlan2 = p->vlan_id[2]; if (IPV4_GET_IPPROTO(p) == IPPROTO_TCP) { keys[0]->ip_proto = 1; } else { @@ -2387,6 +2392,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->port16[1] = htons(p->sp); keys[1]->vlan0 = p->vlan_id[0]; keys[1]->vlan1 = p->vlan_id[1]; + keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v4_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { @@ -2420,6 +2426,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[0]->port16[1] = htons(GET_TCP_DST_PORT(p)); keys[0]->vlan0 = p->vlan_id[0]; keys[0]->vlan1 = p->vlan_id[1]; + keys[0]->vlan2 = p->vlan_id[2]; if (IPV6_GET_NH(p) == IPPROTO_TCP) { keys[0]->ip_proto = 1; } else { @@ -2446,6 +2453,7 @@ static int AFPXDPBypassCallback(Packet *p) keys[1]->port16[1] = htons(GET_TCP_SRC_PORT(p)); keys[1]->vlan0 = p->vlan_id[0]; keys[1]->vlan1 = p->vlan_id[1]; + keys[1]->vlan2 = p->vlan_id[2]; keys[1]->ip_proto = keys[0]->ip_proto; if (AFPInsertHalfFlow(p->afp_v.v6_map_fd, keys[1], p->afp_v.nr_cpus) == 0) { diff --git a/src/source-dpdk.c b/src/source-dpdk.c index 14dd9f807125..cc9dcd6f6e62 100644 --- a/src/source-dpdk.c +++ b/src/source-dpdk.c @@ -87,6 +87,7 @@ TmEcode NoDPDKSupportExit(ThreadVars *tv, const void *initdata, void **data) #include "util-dpdk.h" #include "util-dpdk-i40e.h" +#include "util-dpdk-bonding.h" #include #define BURST_SIZE 32 @@ -194,6 +195,10 @@ static uint64_t DPDKGetSeconds(void) static void DevicePostStartPMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name) { + if (strcmp(driver_name, "net_bonding") == 0) { + driver_name = BondingDeviceDriverGet(ptv->port_id); + } + // The PMD Driver i40e has a special way to set the RSS, it can be set via rte_flow rules // and only after the start of the port if (strcmp(driver_name, "net_i40e") == 0) @@ -202,16 +207,20 @@ static void DevicePostStartPMDSpecificActions(DPDKThreadVars *ptv, const char *d static void DevicePreStopPMDSpecificActions(DPDKThreadVars *ptv, const char *driver_name) { - int retval; + if (strcmp(driver_name, "net_bonding") == 0) { + driver_name = BondingDeviceDriverGet(ptv->port_id); + } if (strcmp(driver_name, "net_i40e") == 0) { +#if RTE_VERSION > RTE_VERSION_NUM(20, 0, 0, 0) // Flush the RSS rules that have been inserted in the post start section struct rte_flow_error flush_error = { 0 }; - retval = rte_flow_flush(ptv->port_id, &flush_error); + int32_t retval = rte_flow_flush(ptv->port_id, &flush_error); if (retval != 0) { SCLogError("Unable to flush rte_flow rules: %s Flush error msg: %s", rte_strerror(-retval), flush_error.message); } +#endif /* RTE_VERSION > RTE_VERSION_NUM(20, 0, 0, 0) */ } } diff --git a/src/stream-tcp.c b/src/stream-tcp.c index ec87745c3b1b..d30bb39a48b7 100644 --- a/src/stream-tcp.c +++ b/src/stream-tcp.c @@ -6504,8 +6504,7 @@ static void StreamTcpPseudoPacketCreateDetectLogFlush(ThreadVars *tv, np->flags |= PKT_HAS_FLOW; np->flags |= PKT_IGNORE_CHECKSUM; np->flags |= PKT_PSEUDO_DETECTLOG_FLUSH; - np->vlan_id[0] = f->vlan_id[0]; - np->vlan_id[1] = f->vlan_id[1]; + memcpy(&np->vlan_id[0], &f->vlan_id[0], sizeof(np->vlan_id)); np->vlan_idx = f->vlan_idx; np->livedev = (struct LiveDevice_ *)f->livedev; diff --git a/src/suricata.c b/src/suricata.c index 007ca7b329e0..7172a49dba40 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -202,6 +202,10 @@ int g_disable_randomness = 1; * comparing flows */ uint16_t g_vlan_mask = 0xffff; +/** determine (without branching) if we include the livedev ids when hashing or + * comparing flows */ +uint16_t g_livedev_mask = 0xffff; + /* flag to disable hashing almost globally, to be similar to disabling nss * support */ bool g_disable_hashing = false; @@ -2933,13 +2937,16 @@ int SuricataMain(int argc, char **argv) exit(EXIT_SUCCESS); } - int vlan_tracking = 1; - if (ConfGetBool("vlan.use-for-tracking", &vlan_tracking) == 1 && !vlan_tracking) { + int tracking = 1; + if (ConfGetBool("vlan.use-for-tracking", &tracking) == 1 && !tracking) { /* Ignore vlan_ids when comparing flows. */ g_vlan_mask = 0x0000; } - SCLogDebug("vlan tracking is %s", vlan_tracking == 1 ? "enabled" : "disabled"); - + SCLogDebug("vlan tracking is %s", tracking == 1 ? "enabled" : "disabled"); + if (ConfGetBool("livedev.use-for-tracking", &tracking) == 1 && !tracking) { + /* Ignore livedev id when comparing flows. */ + g_livedev_mask = 0x0000; + } SetupUserMode(&suricata); InitRunAs(&suricata); diff --git a/src/suricata.h b/src/suricata.h index 82b049f583e2..957134b92c06 100644 --- a/src/suricata.h +++ b/src/suricata.h @@ -172,6 +172,7 @@ void GlobalsInitPreConfig(void); extern volatile uint8_t suricata_ctl_flags; extern int g_disable_randomness; extern uint16_t g_vlan_mask; +extern uint16_t g_livedev_mask; /* Flag to disable hashing (almost) globally. */ extern bool g_disable_hashing; diff --git a/src/util-device.c b/src/util-device.c index 5eed6abdb5da..74a51c9f1069 100644 --- a/src/util-device.c +++ b/src/util-device.c @@ -132,6 +132,12 @@ int LiveRegisterDevice(const char *dev) return -1; } + int id = LiveGetDeviceCount(); + if (id > UINT16_MAX) { + SCFree(pd); + return -1; + } + pd->dev = SCStrdup(dev); if (unlikely(pd->dev == NULL)) { SCFree(pd); @@ -143,7 +149,7 @@ int LiveRegisterDevice(const char *dev) SC_ATOMIC_INIT(pd->pkts); SC_ATOMIC_INIT(pd->drop); SC_ATOMIC_INIT(pd->invalid_checksums); - pd->id = LiveGetDeviceCount(); + pd->id = (uint16_t)id; TAILQ_INSERT_TAIL(&live_devices, pd, next); SCLogDebug("Device \"%s\" registered and created.", dev); diff --git a/src/util-device.h b/src/util-device.h index ae9ec97c08b5..51ddf7d5257a 100644 --- a/src/util-device.h +++ b/src/util-device.h @@ -51,7 +51,7 @@ typedef struct LiveDevice_ { char dev_short[MAX_DEVNAME + 1]; bool tenant_id_set; - int id; + uint16_t id; SC_ATOMIC_DECLARE(uint64_t, pkts); SC_ATOMIC_DECLARE(uint64_t, drop); diff --git a/src/util-dpdk-bonding.c b/src/util-dpdk-bonding.c new file mode 100644 index 000000000000..2dda0927a735 --- /dev/null +++ b/src/util-dpdk-bonding.c @@ -0,0 +1,120 @@ +/* Copyright (C) 2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Lukas Sismis + */ + +#ifndef UTIL_DPDK_BONDING_C +#define UTIL_DPDK_BONDING_C + +#include "suricata-common.h" +#include "util-dpdk-bonding.h" + +#ifdef HAVE_DPDK + +#include "util-dpdk.h" +#include "util-debug.h" + +/** + * Determines if the port is Bond or not by evaluating device driver name + * @param pid port ID + * @return 0 - the device si Bond PMD, 1 - regular device, <0 error + */ +int32_t BondingIsBond(uint16_t pid) +{ + struct rte_eth_dev_info di; + int32_t ret = rte_eth_dev_info_get(pid, &di); + if (ret < 0) { + SCLogError("%s: unable to get device info (err: %s)", DPDKGetPortNameByPortID(pid), + rte_strerror(-ret)); + return ret; + } + + return strcmp(di.driver_name, "net_bonding") == 0 ? 0 : 1; +} + +uint16_t BondingMemberDevicesGet( + uint16_t bond_pid, uint16_t bonded_devs[], uint16_t bonded_devs_length) +{ +#ifdef HAVE_DPDK_BOND + int32_t len = rte_eth_bond_slaves_get(bond_pid, bonded_devs, bonded_devs_length); + if (len == 0) + FatalError("%s: no bonded devices found", DPDKGetPortNameByPortID(bond_pid)); + else if (len < 0) + FatalError("%s: unable to get bonded devices (err: %s)", DPDKGetPortNameByPortID(bond_pid), + rte_strerror(-len)); + + return len; +#else + FatalError( + "%s: bond port not supported in DPDK installation", DPDKGetPortNameByPortID(bond_pid)); +#endif +} + +int32_t BondingAllDevicesSameDriver(uint16_t bond_pid) +{ + uint16_t bonded_devs[RTE_MAX_ETHPORTS] = { 0 }; + uint16_t len = BondingMemberDevicesGet(bond_pid, bonded_devs, RTE_MAX_ETHPORTS); + + const char *driver_name = NULL, *first_driver_name = NULL; + struct rte_eth_dev_info di = { 0 }; + + for (uint16_t i = 0; i < len; i++) { + int32_t ret = rte_eth_dev_info_get(bonded_devs[i], &di); + if (ret < 0) + FatalError("%s: unable to get device info (err: %s)", + DPDKGetPortNameByPortID(bonded_devs[i]), rte_strerror(-ret)); + + if (i == 0) { + first_driver_name = di.driver_name; + } else { + driver_name = di.driver_name; + if (strncmp(first_driver_name, driver_name, + MIN(strlen(first_driver_name), strlen(driver_name))) != 0) { + return -EINVAL; // inconsistent drivers + } + } + } + + return 0; +} + +/** + * Translates to the driver that is actually used by the bonded ports + * \param bond_pid + * \return driver name, FatalError otherwise + */ +const char *BondingDeviceDriverGet(uint16_t bond_pid) +{ + uint16_t bonded_devs[RTE_MAX_ETHPORTS] = { 0 }; + BondingMemberDevicesGet(bond_pid, bonded_devs, RTE_MAX_ETHPORTS); + + struct rte_eth_dev_info di = { 0 }; + int32_t ret = rte_eth_dev_info_get(bonded_devs[0], &di); + if (ret < 0) + FatalError("%s: unable to get device info (err: %s)", + DPDKGetPortNameByPortID(bonded_devs[0]), rte_strerror(-ret)); + + return di.driver_name; +} + +#endif /* HAVE_DPDK */ + +#endif /* UTIL_DPDK_BONDING_C */ diff --git a/src/util-dpdk-bonding.h b/src/util-dpdk-bonding.h new file mode 100644 index 000000000000..f7fad5e64852 --- /dev/null +++ b/src/util-dpdk-bonding.h @@ -0,0 +1,39 @@ +/* Copyright (C) 2023 Open Information Security Foundation + * + * You can copy, redistribute or modify this Program under the terms of + * the GNU General Public License version 2 as published by the Free + * Software Foundation. + * + * 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 + * version 2 along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +/** + * \file + * + * \author Lukas Sismis + */ + +#ifndef UTIL_DPDK_BONDING_H +#define UTIL_DPDK_BONDING_H + +#include "suricata-common.h" + +#ifdef HAVE_DPDK + +int32_t BondingIsBond(uint16_t pid); +uint16_t BondingMemberDevicesGet( + uint16_t bond_pid, uint16_t bonded_devs[], uint16_t bonded_devs_length); +int32_t BondingAllDevicesSameDriver(uint16_t bond_pid); +const char *BondingDeviceDriverGet(uint16_t bond_pid); + +#endif /* HAVE_DPDK */ + +#endif /* UTIL_DPDK_BONDING_H */ diff --git a/src/util-dpdk-i40e.c b/src/util-dpdk-i40e.c index 4191b7750c82..2484b45c793b 100644 --- a/src/util-dpdk-i40e.c +++ b/src/util-dpdk-i40e.c @@ -33,6 +33,7 @@ #include "util-dpdk-i40e.h" #include "util-dpdk.h" #include "util-debug.h" +#include "util-dpdk-bonding.h" #ifdef HAVE_DPDK @@ -110,7 +111,7 @@ static int i40eDeviceSetSymHash(int port_id, const char *port_name, int enable) return 0; } -static int i40eDeviceSetRSSWithFilter(int port_id, const char *port_name) +static int i40eDeviceApplyRSSFilter(int port_id, const char *port_name) { int retval = 0; @@ -142,6 +143,27 @@ static int i40eDeviceSetRSSWithFilter(int port_id, const char *port_name) return retval; } +static int32_t i40eDeviceSetRSSWithFilter(int port_id, const char *port_name) +{ + int32_t ret = BondingIsBond(port_id); + if (ret < 0) + return -ret; + + if (ret == 1) { // regular device + i40eDeviceApplyRSSFilter(port_id, port_name); + } else if (ret == 0) { // the device is Bond PMD + uint16_t bonded_devs[RTE_MAX_ETHPORTS]; + ret = BondingMemberDevicesGet(port_id, bonded_devs, RTE_MAX_ETHPORTS); + for (int i = 0; i < ret; i++) { + i40eDeviceApplyRSSFilter(bonded_devs[i], port_name); + } + } else { + FatalError("Unknown return value from BondingIsBond()"); + } + + return 0; +} + #else static int i40eDeviceSetRSSFlowQueues( @@ -372,16 +394,19 @@ int i40eDeviceSetRSS(int port_id, int nb_rx_queues) return 0; } -void i40eDeviceSetRSSHashFunction(uint64_t *rss_hf) +void i40eDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf) { #if RTE_VERSION >= RTE_VERSION_NUM(20, 0, 0, 0) - *rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | RTE_ETH_RSS_FRAG_IPV6 | - RTE_ETH_RSS_NONFRAG_IPV6_OTHER; + rss_conf->rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | + RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_OTHER; + rss_conf->rss_key = NULL; + rss_conf->rss_key_len = 0; #else - *rss_hf = RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV4_UDP | - RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | - RTE_ETH_RSS_FRAG_IPV6 | RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_NONFRAG_IPV6_UDP | - RTE_ETH_RSS_NONFRAG_IPV6_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_OTHER | RTE_ETH_RSS_SCTP; + rss_conf->rss_hf = + RTE_ETH_RSS_FRAG_IPV4 | RTE_ETH_RSS_NONFRAG_IPV4_TCP | RTE_ETH_RSS_NONFRAG_IPV4_UDP | + RTE_ETH_RSS_NONFRAG_IPV4_SCTP | RTE_ETH_RSS_NONFRAG_IPV4_OTHER | RTE_ETH_RSS_FRAG_IPV6 | + RTE_ETH_RSS_NONFRAG_IPV6_TCP | RTE_ETH_RSS_NONFRAG_IPV6_UDP | + RTE_ETH_RSS_NONFRAG_IPV6_SCTP | RTE_ETH_RSS_NONFRAG_IPV6_OTHER | RTE_ETH_RSS_SCTP; #endif } diff --git a/src/util-dpdk-i40e.h b/src/util-dpdk-i40e.h index 6b1eb7fd13cf..6133aed5d771 100644 --- a/src/util-dpdk-i40e.h +++ b/src/util-dpdk-i40e.h @@ -28,8 +28,10 @@ #ifdef HAVE_DPDK +#include "util-dpdk.h" + int i40eDeviceSetRSS(int port_id, int nb_rx_queues); -void i40eDeviceSetRSSHashFunction(uint64_t *rss_conf); +void i40eDeviceSetRSSConf(struct rte_eth_rss_conf *rss_conf); #endif /* HAVE_DPDK */ diff --git a/src/util-dpdk.c b/src/util-dpdk.c index 83284411fe2a..291ab075e08f 100644 --- a/src/util-dpdk.c +++ b/src/util-dpdk.c @@ -57,3 +57,23 @@ void DPDKCloseDevice(LiveDevice *ldev) } #endif } + +#ifdef HAVE_DPDK + +/** + * Retrieves name of the port from port id + * Not thread-safe + * @param pid + * @return static dev_name on success + */ +const char *DPDKGetPortNameByPortID(uint16_t pid) +{ + static char dev_name[RTE_ETH_NAME_MAX_LEN]; + int32_t ret = rte_eth_dev_get_name_by_port(pid, dev_name); + if (ret < 0) { + FatalError("Port %d: Failed to obtain port name (err: %s)", pid, rte_strerror(-ret)); + } + return dev_name; +} + +#endif /* HAVE_DPDK */ diff --git a/src/util-dpdk.h b/src/util-dpdk.h index e711eaf6cecb..f6a54a8323e4 100644 --- a/src/util-dpdk.h +++ b/src/util-dpdk.h @@ -28,6 +28,9 @@ #include #include +#ifdef HAVE_DPDK_BOND +#include +#endif #include #include #include @@ -44,6 +47,24 @@ #define RTE_ETH_TX_OFFLOAD_MBUF_FAST_FREE DEV_TX_OFFLOAD_MBUF_FAST_FREE #define RTE_ETH_RX_OFFLOAD_CHECKSUM DEV_RX_OFFLOAD_CHECKSUM + +#define RTE_ETH_RX_OFFLOAD_VLAN_STRIP DEV_RX_OFFLOAD_VLAN_STRIP +#define RTE_ETH_RX_OFFLOAD_IPV4_CKSUM DEV_RX_OFFLOAD_IPV4_CKSUM +#define RTE_ETH_RX_OFFLOAD_UDP_CKSUM DEV_RX_OFFLOAD_UDP_CKSUM +#define RTE_ETH_RX_OFFLOAD_TCP_CKSUM DEV_RX_OFFLOAD_TCP_CKSUM +#define RTE_ETH_RX_OFFLOAD_TCP_LRO DEV_RX_OFFLOAD_TCP_LRO +#define RTE_ETH_RX_OFFLOAD_QINQ_STRIP DEV_RX_OFFLOAD_QINQ_STRIP +#define RTE_ETH_RX_OFFLOAD_OUTER_IPV4_CKSUM DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM +#define RTE_ETH_RX_OFFLOAD_MACSEC_STRIP DEV_RX_OFFLOAD_MACSEC_STRIP +#define RTE_ETH_RX_OFFLOAD_HEADER_SPLIT DEV_RX_OFFLOAD_HEADER_SPLIT +#define RTE_ETH_RX_OFFLOAD_VLAN_FILTER DEV_RX_OFFLOAD_VLAN_FILTER +#define RTE_ETH_RX_OFFLOAD_VLAN_EXTEND DEV_RX_OFFLOAD_VLAN_EXTEND +#define RTE_ETH_RX_OFFLOAD_SCATTER DEV_RX_OFFLOAD_SCATTER +#define RTE_ETH_RX_OFFLOAD_TIMESTAMP DEV_RX_OFFLOAD_TIMESTAMP +#define RTE_ETH_RX_OFFLOAD_SECURITY DEV_RX_OFFLOAD_SECURITY +#define RTE_ETH_RX_OFFLOAD_KEEP_CRC DEV_RX_OFFLOAD_KEEP_CRC +#define RTE_ETH_RX_OFFLOAD_SCTP_CKSUM DEV_RX_OFFLOAD_SCTP_CKSUM +#define RTE_ETH_RX_OFFLOAD_OUTER_UDP_CKSUM DEV_RX_OFFLOAD_OUTER_UDP_CKSUM #define RTE_ETH_RX_OFFLOAD_RSS_HASH DEV_RX_OFFLOAD_RSS_HASH #define RTE_ETH_MQ_TX_NONE ETH_MQ_TX_NONE @@ -100,4 +121,8 @@ void DPDKCleanupEAL(void); void DPDKCloseDevice(LiveDevice *ldev); +#ifdef HAVE_DPDK +const char *DPDKGetPortNameByPortID(uint16_t pid); +#endif /* HAVE_DPDK */ + #endif /* UTIL_DPDK_H */ diff --git a/src/util-ebpf.c b/src/util-ebpf.c index af99dca227a7..13eaea828d9b 100644 --- a/src/util-ebpf.c +++ b/src/util-ebpf.c @@ -751,12 +751,14 @@ static int EBPFForEachFlowV4Table(ThreadVars *th_v, LiveDevice *dev, const char flow_key.dst.addr_data32[3] = 0; flow_key.vlan_id[0] = next_key.vlan0; flow_key.vlan_id[1] = next_key.vlan1; + flow_key.vlan_id[2] = next_key.vlan2; if (next_key.ip_proto == 1) { flow_key.proto = IPPROTO_TCP; } else { flow_key.proto = IPPROTO_UDP; } flow_key.recursion_level = 0; + flow_key.livedev_id = dev->id; dead_flow = EBPFOpFlowForKey(&flowstats, dev, &next_key, sizeof(next_key), &flow_key, ctime, pkts_cnt, bytes_cnt, mapfd, tcfg->cpus_count); @@ -868,12 +870,14 @@ static int EBPFForEachFlowV6Table(ThreadVars *th_v, } flow_key.vlan_id[0] = next_key.vlan0; flow_key.vlan_id[1] = next_key.vlan1; + flow_key.vlan_id[2] = next_key.vlan2; if (next_key.ip_proto == 1) { flow_key.proto = IPPROTO_TCP; } else { flow_key.proto = IPPROTO_UDP; } flow_key.recursion_level = 0; + flow_key.livedev_id = dev->id; pkts_cnt = EBPFOpFlowForKey(&flowstats, dev, &next_key, sizeof(next_key), &flow_key, ctime, pkts_cnt, bytes_cnt, mapfd, tcfg->cpus_count); diff --git a/src/util-ebpf.h b/src/util-ebpf.h index fa77ad2c9e02..bf1768a69da7 100644 --- a/src/util-ebpf.h +++ b/src/util-ebpf.h @@ -44,6 +44,7 @@ struct flowv4_keys { __u8 ip_proto:1; __u16 vlan0:15; __u16 vlan1; + __u16 vlan2; }; struct flowv6_keys { @@ -56,6 +57,7 @@ struct flowv6_keys { __u8 ip_proto:1; __u16 vlan0:15; __u16 vlan1; + __u16 vlan2; }; struct pair { diff --git a/src/util-running-modes.c b/src/util-running-modes.c index a88885c0a26f..dd50c85ab420 100644 --- a/src/util-running-modes.c +++ b/src/util-running-modes.c @@ -31,6 +31,7 @@ int ListKeywords(const char *keyword_info) { + EngineModeSetIDS(); SCLogLoadConfig(0, 0, 0, 0); MpmTableSetup(); SpmTableSetup(); @@ -41,6 +42,7 @@ int ListKeywords(const char *keyword_info) int ListAppLayerProtocols(const char *conf_filename) { + EngineModeSetIDS(); if (ConfYamlLoadFile(conf_filename) != -1) SCLogLoadConfig(0, 0, 0, 0); MpmTableSetup(); diff --git a/suricata.yaml.in b/suricata.yaml.in index 96d3bc4ad714..f9a575d72627 100644 --- a/suricata.yaml.in +++ b/suricata.yaml.in @@ -1414,6 +1414,12 @@ flow: vlan: use-for-tracking: true +# This option controls the use of livedev ids in the flow (and defrag) +# hashing. This is enabled by default and should be disabled if +# multiple live devices are used to capture traffic from the same network +livedev: + use-for-tracking: true + # Specific timeouts for flows. Here you can specify the timeouts that the # active flows will wait to transit from the current state to another, on each # protocol. The value of "new" determines the seconds to wait after a handshake or