mirror of https://github.com/OISF/suricata
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.7 KiB
Bash
207 lines
5.7 KiB
Bash
|
5 months ago
|
#!/bin/bash
|
||
|
|
#
|
||
|
|
# DPDK configuration check script.
|
||
|
|
#
|
||
|
|
|
||
|
|
set -o pipefail
|
||
|
|
|
||
|
|
usage() {
|
||
|
|
cat <<'EOF'
|
||
|
|
Start Suricata with a DPDK config, optionally overriding per-interface
|
||
|
|
settings, and verify expected log output. Supports both positive tests
|
||
|
|
(Suricata starts) and negative tests (Suricata fails with expected error).
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
dpdk-checklog.sh [OPTIONS] <yaml>
|
||
|
|
|
||
|
|
Options:
|
||
|
|
--interface-cfg-set <iface>.<key>=<value>
|
||
|
|
Override a DPDK interface setting (repeatable).
|
||
|
|
Resolved to: --set dpdk.interfaces.<N>.<key>=<value>
|
||
|
|
where <N> is the YAML index of <iface>.
|
||
|
|
|
||
|
|
--suricata-log-check-grep <regex>
|
||
|
|
Verify regex is found in the Suricata log (repeatable).
|
||
|
|
|
||
|
|
--expect-start Expect Suricata to start successfully (default).
|
||
|
|
--expect-fail Expect Suricata to fail during startup.
|
||
|
|
|
||
|
|
-h, --help Show this help message.
|
||
|
|
|
||
|
|
Examples:
|
||
|
|
dpdk-checklog.sh \
|
||
|
|
--interface-cfg-set net_null0.mempool-size=auto \
|
||
|
|
--interface-cfg-set net_null0.mempool-cache-size=auto \
|
||
|
|
--suricata-log-check-grep "mempools of size 31, cache size 1" \
|
||
|
|
--expect-start \
|
||
|
|
suricata-null-ids.yaml
|
||
|
|
|
||
|
|
dpdk-checklog.sh \
|
||
|
|
--interface-cfg-set net_null0.mempool-size=15 \
|
||
|
|
--suricata-log-check-grep "mempool size is likely too small" \
|
||
|
|
--expect-fail \
|
||
|
|
suricata-null-ids.yaml
|
||
|
|
EOF
|
||
|
|
}
|
||
|
|
|
||
|
|
# Argument parsing
|
||
|
|
YAML=""
|
||
|
|
EXPECT="start" # "start" or "fail"
|
||
|
|
declare -a CFG_SETS=()
|
||
|
|
declare -a LOG_CHECKS=()
|
||
|
|
|
||
|
|
while [ $# -gt 0 ]; do
|
||
|
|
case "$1" in
|
||
|
|
--interface-cfg-set)
|
||
|
|
CFG_SETS+=("$2"); shift 2 ;;
|
||
|
|
--suricata-log-check-grep)
|
||
|
|
LOG_CHECKS+=("$2"); shift 2 ;;
|
||
|
|
--expect-start)
|
||
|
|
EXPECT="start"; shift ;;
|
||
|
|
--expect-fail)
|
||
|
|
EXPECT="fail"; shift ;;
|
||
|
|
-h|--help)
|
||
|
|
usage; exit 0 ;;
|
||
|
|
-*)
|
||
|
|
echo "ERROR: unknown option: $1"; exit 1 ;;
|
||
|
|
*)
|
||
|
|
if [ -z "$YAML" ]; then YAML="$1"; else
|
||
|
|
echo "ERROR: unexpected argument: $1"; exit 1
|
||
|
|
fi
|
||
|
|
shift ;;
|
||
|
|
esac
|
||
|
|
done
|
||
|
|
|
||
|
|
if [ -z "$YAML" ]; then
|
||
|
|
usage
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Install trap early so all temp files are cleaned up on any exit path.
|
||
|
|
TMPFILES=()
|
||
|
|
trap 'rm -f "${TMPFILES[@]}"' EXIT
|
||
|
|
|
||
|
|
# DPDK version compatibility (member= / slave=)
|
||
|
|
DPDK_YAML="$YAML"
|
||
|
|
if grep -q "net_bonding" "$YAML"; then
|
||
|
|
DPDK_VER=$(pkg-config --modversion libdpdk 2>/dev/null || echo "0.0")
|
||
|
|
DPDK_MAJOR=$(echo "$DPDK_VER" | cut -d. -f1)
|
||
|
|
DPDK_MINOR=$(echo "$DPDK_VER" | cut -d. -f2)
|
||
|
|
|
||
|
|
DPDK_YAML=$(mktemp /tmp/dpdk-checklog-XXXXXX.yaml)
|
||
|
|
TMPFILES+=("$DPDK_YAML")
|
||
|
|
|
||
|
|
if [ "$DPDK_MAJOR" -lt 23 ] || { [ "$DPDK_MAJOR" -eq 23 ] && [ "$DPDK_MINOR" -lt 11 ]; }; then
|
||
|
|
sed 's/member=/slave=/g' "$YAML" > "$DPDK_YAML"
|
||
|
|
else
|
||
|
|
sed 's/slave=/member=/g' "$YAML" > "$DPDK_YAML"
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Resolve --interface-cfg-set to Suricata --set arguments
|
||
|
|
# Build a map: interface-name -> YAML index (0-based).
|
||
|
|
# Parses lines like " - interface: net_null0" from the YAML.
|
||
|
|
declare -A IFACE_INDEX=()
|
||
|
|
idx=0
|
||
|
|
while IFS= read -r iface_name; do
|
||
|
|
IFACE_INDEX["$iface_name"]=$idx
|
||
|
|
idx=$((idx + 1))
|
||
|
|
done < <(grep -E '^\s*-\s*interface:' "$YAML" | sed 's/.*interface:\s*//' | awk '{print $1}')
|
||
|
|
|
||
|
|
SURI_SET_ARGS=()
|
||
|
|
for entry in "${CFG_SETS[@]}"; do
|
||
|
|
# entry format: <iface>.<key>=<value>
|
||
|
|
iface="${entry%%.*}"
|
||
|
|
key_value="${entry#*.}"
|
||
|
|
|
||
|
|
if [ -z "${IFACE_INDEX[$iface]+x}" ]; then
|
||
|
|
echo "ERROR: interface '$iface' not found in $YAML"
|
||
|
|
echo " Available interfaces: ${!IFACE_INDEX[*]}"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
suri_idx="${IFACE_INDEX[$iface]}"
|
||
|
|
SURI_SET_ARGS+=(--set "dpdk.interfaces.${suri_idx}.${key_value}")
|
||
|
|
done
|
||
|
|
|
||
|
|
# Run Suricata
|
||
|
|
SURILOG=$(mktemp /tmp/dpdk-checklog-log-XXXXXX.log)
|
||
|
|
TMPFILES+=("$SURILOG")
|
||
|
|
|
||
|
|
TIMEOUT_SEC=30
|
||
|
|
|
||
|
|
./src/suricata -c "$DPDK_YAML" -S /dev/null -l ./ --dpdk \
|
||
|
|
"${SURI_SET_ARGS[@]}" > "$SURILOG" 2>&1 &
|
||
|
|
SURIPID=$!
|
||
|
|
|
||
|
|
# Poll: wait for "Engine started" (success) or process exit (failure).
|
||
|
|
ENGINE_STARTED=false
|
||
|
|
SURI_EXIT=0
|
||
|
|
# $SECONDS is a bash builtin: total seconds since shell start (does not wrap at 60).
|
||
|
|
T0=$SECONDS
|
||
|
|
while [ $((SECONDS - T0)) -lt "$TIMEOUT_SEC" ]; do
|
||
|
|
if grep -q "Engine started" "$SURILOG" 2>/dev/null; then
|
||
|
|
ENGINE_STARTED=true
|
||
|
|
break
|
||
|
|
fi
|
||
|
|
if ! kill -0 "$SURIPID" 2>/dev/null; then
|
||
|
|
wait "$SURIPID"
|
||
|
|
SURI_EXIT=$?
|
||
|
|
break
|
||
|
|
fi
|
||
|
|
sleep 0.2
|
||
|
|
done
|
||
|
|
|
||
|
|
# Clean up: kill Suricata if still running (engine started or timeout).
|
||
|
|
if kill -0 "$SURIPID" 2>/dev/null; then
|
||
|
|
kill "$SURIPID" 2>/dev/null
|
||
|
|
wait "$SURIPID" 2>/dev/null || true
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Evaluate results
|
||
|
|
RES=0
|
||
|
|
|
||
|
|
echo "=========================================="
|
||
|
|
echo " DPDK checklog: $(basename "$YAML")"
|
||
|
|
echo " expect=$EXPECT exit=$SURI_EXIT engine_started=$ENGINE_STARTED"
|
||
|
|
echo "=========================================="
|
||
|
|
|
||
|
|
# Check startup expectation
|
||
|
|
if [ "$EXPECT" = "start" ]; then
|
||
|
|
if [ "$ENGINE_STARTED" = true ]; then
|
||
|
|
echo " PASS Engine started as expected"
|
||
|
|
else
|
||
|
|
echo " FAIL Engine did NOT start (expected start)"
|
||
|
|
RES=1
|
||
|
|
fi
|
||
|
|
elif [ "$EXPECT" = "fail" ]; then
|
||
|
|
if [ "$ENGINE_STARTED" = false ] && [ "$SURI_EXIT" -ne 0 ]; then
|
||
|
|
echo " PASS Engine failed as expected (exit=$SURI_EXIT)"
|
||
|
|
else
|
||
|
|
echo " FAIL Engine did not fail as expected (exit=$SURI_EXIT, started=$ENGINE_STARTED)"
|
||
|
|
RES=1
|
||
|
|
fi
|
||
|
|
fi
|
||
|
|
|
||
|
|
# Check log patterns
|
||
|
|
for pattern in "${LOG_CHECKS[@]}"; do
|
||
|
|
if grep -qE "$pattern" "$SURILOG"; then
|
||
|
|
echo " PASS log-check: $pattern"
|
||
|
|
else
|
||
|
|
echo " FAIL log-check: $pattern"
|
||
|
|
RES=1
|
||
|
|
fi
|
||
|
|
done
|
||
|
|
|
||
|
|
echo "=========================================="
|
||
|
|
|
||
|
|
# Dump log on failure for debugging
|
||
|
|
if [ "$RES" -ne 0 ]; then
|
||
|
|
echo ""
|
||
|
|
echo "--- Suricata log (failure) ---"
|
||
|
|
cat "$SURILOG"
|
||
|
|
echo "--- end log ---"
|
||
|
|
fi
|
||
|
|
|
||
|
|
exit $RES
|