Last active
March 2, 2026 11:00
-
-
Save g3rhard/73b3476736217d0d6a53e8c8b5800d6e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # ============================================================================= | |
| # e1000e Data Collector - MINIMAL BusyBox Version (Enhanced v2) | |
| # Purpose: Collect data in initramfs environment with minimal dependencies | |
| # ============================================================================= | |
| # | |
| # DEPENDENCIES (ALL standard BusyBox applets): | |
| # sh, cat, echo, test, mkdir, cp, ls, readlink, cut, tr, basename | |
| # find, sort, grep, head, tail, date, sync, dd, od | |
| # | |
| # OPTIONAL (if available in your BusyBox build): | |
| # md5sum, ip, dmesg, mount, umount | |
| # | |
| # OPTIONAL EXTERNAL TOOLS (greatly enhance diagnostics): | |
| # ethtool - NIC configuration and register dumps | |
| # | |
| # ENHANCED DATA COLLECTED (v2): | |
| # - PCI config space dump | |
| # - PCIe link status (speed/width) | |
| # - MSI/MSI-X state | |
| # - ACPI/power management | |
| # - Full ethtool diagnostics (pause, coalesce, rings, EEE, register dump) | |
| # - TX/RX queue information | |
| # - IRQ affinity | |
| # - debugfs data (if accessible) | |
| # - Boot timing extraction | |
| # | |
| # TO INCLUDE IN INITRAMFS: | |
| # 1. Copy this script to /etc/initramfs-tools/scripts/init-premount/ | |
| # or /usr/lib/dracut/modules.d/99e1000e-debug/ | |
| # 2. Rebuild initramfs: update-initramfs -u -k $(uname -r) | |
| # | |
| # ============================================================================= | |
| # Output directory - change to your mounted USB/boot partition | |
| OUT="${1:-/tmp/e1000e-busybox-$(cat /proc/uptime | cut -d. -f1)}" | |
| # PCI device for e1000e NIC | |
| PCIDEV="0000:00:1f.6" | |
| # Create output directory | |
| mkdir -p "$OUT" | |
| echo "=== E1000E BusyBox Data Collector ===" > "$OUT/00_header.txt" | |
| echo "Timestamp: $(date 2>/dev/null || echo 'unknown')" >> "$OUT/00_header.txt" | |
| echo "Uptime: $(cat /proc/uptime)" >> "$OUT/00_header.txt" | |
| # ----------------------------------------------------------------------------- | |
| # 1. Boot Identity | |
| # ----------------------------------------------------------------------------- | |
| echo "Collecting boot identity..." | |
| uname -a > "$OUT/uname_a.txt" 2>&1 | |
| cat /proc/cmdline > "$OUT/proc_cmdline.txt" 2>&1 | |
| cat /proc/version > "$OUT/proc_version.txt" 2>&1 | |
| # UEFI detection | |
| if [ -d /sys/firmware/efi ]; then | |
| echo "UEFI" > "$OUT/firmware_mode.txt" | |
| else | |
| echo "BIOS" > "$OUT/firmware_mode.txt" | |
| fi | |
| # PID 1 (init system) | |
| cat /proc/1/comm > "$OUT/pid1_comm.txt" 2>&1 | |
| tr '\0' ' ' < /proc/1/cmdline > "$OUT/pid1_cmdline.txt" 2>/dev/null | |
| # Secure boot indicators | |
| grep -oE '(module\.sig_enforce|secureboot|efi=)[^ ]*' /proc/cmdline > "$OUT/secureboot_cmdline.txt" 2>/dev/null || echo "none" > "$OUT/secureboot_cmdline.txt" | |
| cat /proc/sys/kernel/module_sig_enforce > "$OUT/module_sig_enforce.txt" 2>/dev/null || echo "unavailable" > "$OUT/module_sig_enforce.txt" | |
| # ----------------------------------------------------------------------------- | |
| # 2. Modules | |
| # ----------------------------------------------------------------------------- | |
| echo "Collecting modules info..." | |
| cat /proc/modules > "$OUT/proc_modules.txt" 2>&1 | |
| ls -1 /sys/module > "$OUT/sys_module_list.txt" 2>&1 | |
| # e1000e parameters | |
| if [ -d /sys/module/e1000e/parameters ]; then | |
| echo "loaded" > "$OUT/e1000e_loaded.txt" | |
| for p in /sys/module/e1000e/parameters/*; do | |
| [ -r "$p" ] && echo "$(basename "$p")=$(cat "$p" 2>/dev/null)" >> "$OUT/e1000e_params.txt" | |
| done | |
| # === NEW: Full e1000e module sysfs tree === | |
| ls -laR /sys/module/e1000e/ > "$OUT/e1000e_sysfs_full.txt" 2>&1 | |
| # === NEW: Driver info from sysfs === | |
| for attr in /sys/module/e1000e/*; do | |
| [ -f "$attr" ] && [ -r "$attr" ] && echo "$(basename "$attr")=$(cat "$attr" 2>/dev/null)" >> "$OUT/e1000e_module_attrs.txt" | |
| done | |
| else | |
| echo "not_loaded" > "$OUT/e1000e_loaded.txt" | |
| fi | |
| # Modprobe config (if accessible) | |
| if [ -d /etc/modprobe.d ]; then | |
| cat /etc/modprobe.d/*.conf > "$OUT/modprobe_d.txt" 2>/dev/null || echo "empty" > "$OUT/modprobe_d.txt" | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 3. PCI Device State | |
| # ----------------------------------------------------------------------------- | |
| echo "Collecting PCI device state..." | |
| PCISYS="/sys/bus/pci/devices/$PCIDEV" | |
| if [ -d "$PCISYS" ]; then | |
| echo "present" > "$OUT/pci_device_status.txt" | |
| # Basic attributes | |
| for attr in vendor device subsystem_vendor subsystem_device class irq enable; do | |
| [ -r "$PCISYS/$attr" ] && echo "$attr=$(cat "$PCISYS/$attr" 2>/dev/null)" >> "$OUT/pci_attrs.txt" | |
| done | |
| # Driver binding | |
| readlink "$PCISYS/driver" > "$OUT/pci_driver_link.txt" 2>&1 || echo "none" > "$OUT/pci_driver_link.txt" | |
| # Power state | |
| if [ -d "$PCISYS/power" ]; then | |
| for attr in control runtime_status runtime_suspended_time; do | |
| [ -r "$PCISYS/power/$attr" ] && echo "$attr=$(cat "$PCISYS/power/$attr" 2>/dev/null)" >> "$OUT/pci_power.txt" | |
| done | |
| fi | |
| # Resources | |
| cat "$PCISYS/resource" > "$OUT/pci_resource.txt" 2>/dev/null | |
| # === NEW: PCI config space (first 256 bytes as hex) === | |
| if [ -r "$PCISYS/config" ]; then | |
| od -A x -t x1 -N 256 "$PCISYS/config" > "$OUT/pci_config_space.txt" 2>&1 | |
| fi | |
| # === NEW: MSI/MSI-X capability === | |
| [ -d "$PCISYS/msi_irqs" ] && ls "$PCISYS/msi_irqs" > "$OUT/pci_msi_irqs.txt" 2>&1 | |
| [ -r "$PCISYS/msi_bus" ] && cat "$PCISYS/msi_bus" > "$OUT/pci_msi_bus.txt" 2>&1 | |
| # === NEW: PCIe link status === | |
| for attr in current_link_speed current_link_width max_link_speed max_link_width; do | |
| [ -r "$PCISYS/$attr" ] && echo "$attr=$(cat "$PCISYS/$attr" 2>/dev/null)" >> "$OUT/pci_link_status.txt" | |
| done | |
| # === NEW: D3cold and ASPM status === | |
| [ -r "$PCISYS/d3cold_allowed" ] && echo "d3cold_allowed=$(cat "$PCISYS/d3cold_allowed")" >> "$OUT/pci_power_extended.txt" | |
| [ -r "$PCISYS/link/l1_aspm" ] && echo "l1_aspm=$(cat "$PCISYS/link/l1_aspm" 2>/dev/null)" >> "$OUT/pci_power_extended.txt" | |
| # === NEW: All sysfs attributes for this device === | |
| ls -la "$PCISYS/" > "$OUT/pci_sysfs_listing.txt" 2>&1 | |
| else | |
| echo "not_found" > "$OUT/pci_device_status.txt" | |
| fi | |
| # List all PCI devices | |
| ls /sys/bus/pci/devices/ > "$OUT/all_pci_devices.txt" 2>&1 | |
| # ----------------------------------------------------------------------------- | |
| # 3b. ACPI & Power Management (NEW SECTION) | |
| # ----------------------------------------------------------------------------- | |
| echo "Collecting ACPI/power management info..." | |
| # ACPI tables list | |
| ls /sys/firmware/acpi/tables/ > "$OUT/acpi_tables.txt" 2>/dev/null || echo "no acpi tables" > "$OUT/acpi_tables.txt" | |
| # ACPI power state | |
| cat /sys/power/state > "$OUT/power_state.txt" 2>/dev/null || echo "unavailable" > "$OUT/power_state.txt" | |
| cat /sys/power/mem_sleep > "$OUT/power_mem_sleep.txt" 2>/dev/null || true | |
| # PCI device power management for all devices | |
| for dev in /sys/bus/pci/devices/*/power/runtime_status; do | |
| [ -r "$dev" ] && echo "$(dirname "$dev" | xargs basename): $(cat "$dev")" >> "$OUT/all_pci_power.txt" | |
| done 2>/dev/null | |
| # Check for ASPM state | |
| if [ -r /sys/module/pcie_aspm/parameters/policy ]; then | |
| cat /sys/module/pcie_aspm/parameters/policy > "$OUT/pcie_aspm_policy.txt" 2>&1 | |
| fi | |
| # Intel ME status if available | |
| [ -d /sys/bus/mei/devices ] && ls -la /sys/bus/mei/devices/ > "$OUT/mei_devices.txt" 2>&1 | |
| # ----------------------------------------------------------------------------- | |
| # 4. Interrupts | |
| # ----------------------------------------------------------------------------- | |
| echo "Collecting interrupt info..." | |
| cat /proc/interrupts > "$OUT/proc_interrupts.txt" 2>&1 | |
| grep -E "(e1000|eth|enp|eno)" /proc/interrupts > "$OUT/nic_interrupts.txt" 2>/dev/null || echo "none" > "$OUT/nic_interrupts.txt" | |
| # ----------------------------------------------------------------------------- | |
| # 5. Network State | |
| # ----------------------------------------------------------------------------- | |
| echo "Collecting network state..." | |
| # sysfs network interfaces | |
| ls -la /sys/class/net/ > "$OUT/net_interfaces.txt" 2>&1 | |
| # Find our interface | |
| IFACE="" | |
| for i in eth0 enp0s31f6 eno1 eno2; do | |
| if [ -d "/sys/class/net/$i" ]; then | |
| IFACE="$i" | |
| break | |
| fi | |
| done | |
| echo "$IFACE" > "$OUT/detected_iface.txt" | |
| # Interface sysfs data | |
| if [ -n "$IFACE" ] && [ -d "/sys/class/net/$IFACE" ]; then | |
| NETSYS="/sys/class/net/$IFACE" | |
| for attr in operstate carrier speed duplex mtu address; do | |
| [ -r "$NETSYS/$attr" ] && echo "$attr=$(cat "$NETSYS/$attr" 2>/dev/null)" >> "$OUT/iface_attrs.txt" | |
| done | |
| readlink "$NETSYS/device" >> "$OUT/iface_pci_link.txt" 2>/dev/null | |
| # === NEW: TX/RX queue information === | |
| if [ -d "$NETSYS/queues" ]; then | |
| ls -la "$NETSYS/queues/" > "$OUT/iface_queues_list.txt" 2>&1 | |
| for q in $NETSYS/queues/tx-*; do | |
| [ -d "$q" ] && { | |
| QN=$(basename "$q") | |
| for attr in tx_timeout byte_queue_limits/limit byte_queue_limits/limit_max; do | |
| [ -r "$q/$attr" ] && echo "$QN/$attr=$(cat "$q/$attr" 2>/dev/null)" >> "$OUT/iface_tx_queues.txt" | |
| done | |
| } | |
| done | |
| for q in $NETSYS/queues/rx-*; do | |
| [ -d "$q" ] && { | |
| QN=$(basename "$q") | |
| for attr in rps_cpus rps_flow_cnt; do | |
| [ -r "$q/$attr" ] && echo "$QN/$attr=$(cat "$q/$attr" 2>/dev/null)" >> "$OUT/iface_rx_queues.txt" | |
| done | |
| } | |
| done | |
| fi | |
| # === NEW: Interface statistics from sysfs === | |
| if [ -d "$NETSYS/statistics" ]; then | |
| for stat in $NETSYS/statistics/*; do | |
| [ -r "$stat" ] && echo "$(basename "$stat")=$(cat "$stat" 2>/dev/null)" >> "$OUT/iface_sysfs_stats.txt" | |
| done | |
| fi | |
| # === NEW: Interface flags === | |
| [ -r "$NETSYS/flags" ] && echo "flags=$(cat "$NETSYS/flags")" >> "$OUT/iface_flags.txt" | |
| [ -r "$NETSYS/tx_queue_len" ] && echo "tx_queue_len=$(cat "$NETSYS/tx_queue_len")" >> "$OUT/iface_flags.txt" | |
| fi | |
| # ip command if available | |
| if command -v ip >/dev/null 2>&1; then | |
| ip link show > "$OUT/ip_link.txt" 2>&1 | |
| ip addr show > "$OUT/ip_addr.txt" 2>&1 | |
| fi | |
| # /proc/net/dev | |
| cat /proc/net/dev > "$OUT/proc_net_dev.txt" 2>&1 | |
| # ethtool if available (comprehensive collection) | |
| if command -v ethtool >/dev/null 2>&1 && [ -n "$IFACE" ]; then | |
| ethtool "$IFACE" > "$OUT/ethtool.txt" 2>&1 || true | |
| ethtool -i "$IFACE" > "$OUT/ethtool_i.txt" 2>&1 || true | |
| ethtool -S "$IFACE" > "$OUT/ethtool_S.txt" 2>&1 || true | |
| # Additional ethtool diagnostics | |
| ethtool -a "$IFACE" > "$OUT/ethtool_pause.txt" 2>&1 || true # Pause/flow control | |
| ethtool -c "$IFACE" > "$OUT/ethtool_coalesce.txt" 2>&1 || true # Interrupt coalescing | |
| ethtool -g "$IFACE" > "$OUT/ethtool_ring.txt" 2>&1 || true # Ring buffer sizes | |
| ethtool -k "$IFACE" > "$OUT/ethtool_offload.txt" 2>&1 || true # Offload features | |
| ethtool -d "$IFACE" > "$OUT/ethtool_dump.txt" 2>&1 || true # Register dump (PHY!) | |
| ethtool --show-eee "$IFACE" > "$OUT/ethtool_eee.txt" 2>&1 || true # Energy Efficient Ethernet | |
| ethtool -m "$IFACE" > "$OUT/ethtool_module.txt" 2>&1 || true # Module/SFP info | |
| ethtool -e "$IFACE" > "$OUT/ethtool_eeprom.txt" 2>&1 || true # EEPROM dump | |
| ethtool --show-priv-flags "$IFACE" > "$OUT/ethtool_privflags.txt" 2>&1 || true | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 6. Kernel Messages | |
| # ----------------------------------------------------------------------------- | |
| echo "Collecting kernel messages..." | |
| if command -v dmesg >/dev/null 2>&1; then | |
| dmesg > "$OUT/dmesg_full.txt" 2>&1 | |
| dmesg | grep -iE "(e1000|intel.*eth)" > "$OUT/dmesg_e1000e.txt" 2>/dev/null || true | |
| dmesg | grep -iE "(error|fail|timeout|reset|watchdog)" > "$OUT/dmesg_errors.txt" 2>/dev/null || true | |
| dmesg | tail -n 200 > "$OUT/dmesg_tail.txt" 2>&1 | |
| # === NEW: More specific dmesg filters === | |
| dmesg | grep -iE "(pci|pcie|aspm|d3cold|d3hot)" > "$OUT/dmesg_pci.txt" 2>/dev/null || true | |
| dmesg | grep -iE "(acpi|power|pm|sleep|wake)" > "$OUT/dmesg_power.txt" 2>/dev/null || true | |
| dmesg | grep -iE "(dma|iommu|iova|swiotlb)" > "$OUT/dmesg_dma.txt" 2>/dev/null || true | |
| dmesg | grep -iE "(irq|interrupt|msi)" > "$OUT/dmesg_irq.txt" 2>/dev/null || true | |
| dmesg | grep -iE "(firmware|microcode|mei)" > "$OUT/dmesg_firmware.txt" 2>/dev/null || true | |
| # === NEW: Boot timing extraction === | |
| dmesg | grep -E "^\[[ ]*[0-9]+\.[0-9]+\]" | head -50 > "$OUT/dmesg_boot_timing.txt" 2>&1 | |
| else | |
| echo "dmesg not available" > "$OUT/dmesg_full.txt" | |
| fi | |
| # === NEW: Kernel ring buffer size === | |
| [ -r /proc/sys/kernel/printk ] && cat /proc/sys/kernel/printk > "$OUT/kernel_printk.txt" | |
| # ----------------------------------------------------------------------------- | |
| # 6b. Debug Filesystem (NEW SECTION) | |
| # ----------------------------------------------------------------------------- | |
| echo "Checking debugfs..." | |
| if [ -d /sys/kernel/debug ]; then | |
| ls /sys/kernel/debug/ > "$OUT/debugfs_root.txt" 2>&1 || echo "no access" > "$OUT/debugfs_root.txt" | |
| # e1000e debug info if available | |
| if [ -d /sys/kernel/debug/e1000e ]; then | |
| ls -la /sys/kernel/debug/e1000e/ > "$OUT/debugfs_e1000e.txt" 2>&1 | |
| for f in /sys/kernel/debug/e1000e/$PCIDEV/*; do | |
| [ -r "$f" ] && { | |
| echo "=== $(basename "$f") ===" >> "$OUT/debugfs_e1000e_data.txt" | |
| cat "$f" >> "$OUT/debugfs_e1000e_data.txt" 2>&1 | |
| } | |
| done | |
| fi | |
| # PCIe debug info | |
| [ -d /sys/kernel/debug/pcie_aspm ] && cat /sys/kernel/debug/pcie_aspm/* > "$OUT/debugfs_aspm.txt" 2>/dev/null | |
| # DMA debug | |
| [ -r /sys/kernel/debug/dma-api/stats ] && cat /sys/kernel/debug/dma-api/stats > "$OUT/debugfs_dma_stats.txt" 2>&1 | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 7. Processes, Mounts & System State | |
| # ----------------------------------------------------------------------------- | |
| echo "Collecting process/mount/system info..." | |
| cat /proc/mounts > "$OUT/proc_mounts.txt" 2>&1 | |
| cat /proc/meminfo > "$OUT/meminfo.txt" 2>&1 | |
| if command -v ps >/dev/null 2>&1; then | |
| ps > "$OUT/ps.txt" 2>&1 | |
| fi | |
| # === NEW: CPU info (may affect interrupt handling) === | |
| cat /proc/cpuinfo > "$OUT/cpuinfo.txt" 2>&1 || true | |
| grep -E "^(processor|model name|cpu MHz|flags)" /proc/cpuinfo > "$OUT/cpuinfo_summary.txt" 2>/dev/null | |
| # === NEW: IRQ affinity for NIC === | |
| if [ -n "$IFACE" ]; then | |
| for irqdir in /proc/irq/*; do | |
| if grep -q "$IFACE\|e1000" "$irqdir/smp_affinity_list" 2>/dev/null; then | |
| IRQNUM=$(basename "$irqdir") | |
| echo "IRQ $IRQNUM:" >> "$OUT/nic_irq_affinity.txt" | |
| cat "$irqdir/smp_affinity" >> "$OUT/nic_irq_affinity.txt" 2>&1 | |
| cat "$irqdir/smp_affinity_list" >> "$OUT/nic_irq_affinity.txt" 2>&1 | |
| fi | |
| done 2>/dev/null | |
| fi | |
| # === NEW: Kernel timers/delays === | |
| [ -r /proc/timer_list ] && head -100 /proc/timer_list > "$OUT/timer_list.txt" 2>&1 | |
| # === NEW: Softirq statistics === | |
| cat /proc/softirqs > "$OUT/softirqs.txt" 2>&1 || true | |
| # === NEW: System uptime at collection moment === | |
| echo "Collection uptime: $(cat /proc/uptime)" > "$OUT/collection_timing.txt" | |
| echo "System clock: $(date 2>/dev/null || echo 'unavailable')" >> "$OUT/collection_timing.txt" | |
| # ----------------------------------------------------------------------------- | |
| # 8. Initramfs contents (if we can see /boot) | |
| # ----------------------------------------------------------------------------- | |
| echo "Checking initramfs..." | |
| ls -la /boot/init* /boot/vmlinuz* > "$OUT/boot_files.txt" 2>/dev/null || echo "no /boot access" > "$OUT/boot_files.txt" | |
| # Detect initramfs compression via magic bytes | |
| INITRD="" | |
| KVER=$(uname -r) | |
| for f in "/boot/initrd.img-$KVER" "/boot/initramfs-$KVER.img"; do | |
| [ -r "$f" ] && INITRD="$f" && break | |
| done | |
| if [ -n "$INITRD" ]; then | |
| echo "Found: $INITRD" > "$OUT/initrd_found.txt" | |
| # Magic byte detection | |
| MAGIC=$(dd if="$INITRD" bs=1 count=4 2>/dev/null | od -An -tx1 | tr -d ' ') | |
| case "$MAGIC" in | |
| 1f8b*) echo "gzip" ;; | |
| fd37*) echo "xz" ;; | |
| 28b5*) echo "zstd" ;; | |
| 0422*) echo "lz4" ;; | |
| 3037*) echo "cpio" ;; | |
| *) echo "unknown:$MAGIC" ;; | |
| esac > "$OUT/initrd_compression.txt" | |
| # Hash if possible | |
| if command -v md5sum >/dev/null 2>&1; then | |
| md5sum "$INITRD" > "$OUT/initrd_md5.txt" 2>&1 | |
| fi | |
| else | |
| echo "no initrd found" > "$OUT/initrd_found.txt" | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 9. Create file list manifest | |
| # ----------------------------------------------------------------------------- | |
| echo "Creating manifest..." | |
| ls -la "$OUT"/ > "$OUT/00_manifest.txt" 2>&1 | |
| # Checksums | |
| if command -v md5sum >/dev/null 2>&1; then | |
| (cd "$OUT" && md5sum * 2>/dev/null) > "$OUT/00_checksums.txt" | |
| fi | |
| # ----------------------------------------------------------------------------- | |
| # 10. Post-hang Repeated Collection (NEW SECTION) | |
| # ----------------------------------------------------------------------------- | |
| # If the hang is happening, this captures state AFTER the hang started | |
| echo "Capturing post-hang state..." | |
| # Wait a brief moment then re-capture critical info | |
| sleep 2 2>/dev/null || true | |
| if command -v ethtool >/dev/null 2>&1 && [ -n "$IFACE" ]; then | |
| ethtool -S "$IFACE" > "$OUT/ethtool_S_post.txt" 2>&1 || true | |
| fi | |
| cat /proc/interrupts > "$OUT/proc_interrupts_post.txt" 2>&1 | |
| dmesg | tail -100 > "$OUT/dmesg_tail_post.txt" 2>&1 || true | |
| # === NEW: Capture multiple PHY/MAC status samples over time === | |
| echo "Sampling dmesg for Hardware Unit Hang patterns..." | |
| dmesg | grep -A15 "Detected Hardware Unit Hang" | head -50 > "$OUT/hang_details.txt" 2>/dev/null || true | |
| # ----------------------------------------------------------------------------- | |
| # 11. Diagnostic Commands Hints | |
| # ----------------------------------------------------------------------------- | |
| cat > "$OUT/DIAGNOSTIC_HINTS.txt" << 'HINTS_EOF' | |
| === Manual Diagnostic Commands to Try === | |
| 1. PHY Reset (try before hang occurs): | |
| ethtool -s enp0s31f6 autoneg off speed 100 duplex full | |
| sleep 2 | |
| ethtool -s enp0s31f6 autoneg on | |
| 2. Disable Flow Control: | |
| ethtool -A enp0s31f6 rx off tx off autoneg off | |
| 3. Force PCI device reset: | |
| echo 1 > /sys/bus/pci/devices/0000:00:1f.6/reset | |
| 4. Check if PHY registers are readable: | |
| ethtool -d enp0s31f6 | |
| 5. Try different autoneg settings: | |
| ethtool -s enp0s31f6 autoneg on advertise 0x020 | |
| 6. Try disabling EEE (Energy Efficient Ethernet): | |
| ethtool --set-eee enp0s31f6 eee off | |
| 7. If lspci available, check device status: | |
| lspci -vvv -s 00:1f.6 | |
| 8. Reload module with debug: | |
| rmmod e1000e | |
| modprobe e1000e debug=16 | |
| HINTS_EOF | |
| # ----------------------------------------------------------------------------- | |
| # Done | |
| # ----------------------------------------------------------------------------- | |
| echo "" | |
| echo "=== Collection Complete (Enhanced v2) ===" | |
| echo "Output: $OUT" | |
| echo "Files collected: $(ls -1 "$OUT" | wc -l)" | |
| echo "" | |
| echo "To copy to USB:" | |
| echo " mount /dev/sda1 /mnt" | |
| echo " cp -a $OUT /mnt/" | |
| echo " sync && umount /mnt" | |
| echo "" | |
| echo "See $OUT/DIAGNOSTIC_HINTS.txt for manual commands to try" | |
| echo "" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # ============================================================================= | |
| # e1000e Data Collector Script | |
| # Purpose: Collect comprehensive system/driver data for comparison between | |
| # BusyBox/initramfs and full system environments | |
| # ============================================================================= | |
| # ============================================================================= | |
| # DEPENDENCIES / TOOLS REQUIRED | |
| # ============================================================================= | |
| # | |
| # MINIMAL (Required for BusyBox/initramfs - include these in initramfs): | |
| # - sh (BusyBox sh or dash) | |
| # - cat, echo, test, mkdir, cp, ls, readlink | |
| # - dd (for magic byte detection) | |
| # - od (for hex output) | |
| # - cut, tr, basename, dirname | |
| # - find (BusyBox find) | |
| # - sort (BusyBox sort) | |
| # - grep (BusyBox grep) | |
| # - head, tail | |
| # - date (for timestamp) | |
| # - sync | |
| # - mount, umount (if saving to external media) | |
| # | |
| # OPTIONAL (Enhanced data collection - nice to have): | |
| # - md5sum or sha256sum (checksums) | |
| # - ip (iproute2 - network state) | |
| # - ethtool (NIC diagnostics) | |
| # - dmesg (kernel ring buffer) | |
| # - lspci (PCI device info) | |
| # - modinfo (module information) | |
| # - lsmod (formatted module list) | |
| # - zcat/xzcat/zstdcat (config.gz extraction) | |
| # - file (magic detection) | |
| # - cpio (initramfs extraction) | |
| # | |
| # FULL SYSTEM ONLY: | |
| # - journalctl (systemd logs) | |
| # - lsinitramfs / unmkinitramfs (initramfs inspection) | |
| # - update-initramfs / dracut / mkinitcpio (rebuild) | |
| # | |
| # ============================================================================= | |
| set -e | |
| # ============================================================================= | |
| # CONFIGURATION | |
| # ============================================================================= | |
| # Target PCI device (e1000e NIC) | |
| PCI_DEVICE="0000:00:1f.6" | |
| # Network interface name (adjust if different) | |
| NET_IFACE="${NET_IFACE:-eth0}" | |
| # Output directory (override with environment variable or first argument) | |
| OUT_DIR="${1:-${OUT_DIR:-/tmp/e1000e-manifest-$(date +%Y%m%d-%H%M%S)}}" | |
| # ============================================================================= | |
| # HELPER FUNCTIONS | |
| # ============================================================================= | |
| log() { | |
| echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | |
| } | |
| log_section() { | |
| echo "" | |
| echo "==============================================" | |
| echo " $*" | |
| echo "==============================================" | |
| } | |
| # Check if command exists | |
| cmd_exists() { | |
| command -v "$1" >/dev/null 2>&1 | |
| } | |
| # Safe cat with error handling | |
| safe_cat() { | |
| cat "$1" 2>/dev/null || echo "[ERROR: Cannot read $1]" | |
| } | |
| # Safe read of sysfs/procfs value | |
| sysfs_read() { | |
| local path="$1" | |
| local name="$2" | |
| if [ -e "$path" ]; then | |
| echo "${name}=$(cat "$path" 2>/dev/null || echo '[unreadable]')" | |
| else | |
| echo "${name}=[not present]" | |
| fi | |
| } | |
| # Detect environment type | |
| detect_environment() { | |
| local pid1_comm="" | |
| if [ -r /proc/1/comm ]; then | |
| pid1_comm=$(cat /proc/1/comm 2>/dev/null) | |
| fi | |
| case "$pid1_comm" in | |
| systemd) | |
| echo "systemd" | |
| ;; | |
| init) | |
| # Could be sysvinit or busybox init | |
| if [ -x /bin/busybox ] || grep -q "BusyBox" /proc/1/cmdline 2>/dev/null; then | |
| echo "busybox" | |
| else | |
| echo "sysvinit" | |
| fi | |
| ;; | |
| sh|ash|bash|dash) | |
| echo "initramfs-shell" | |
| ;; | |
| *) | |
| if [ -x /bin/busybox ]; then | |
| echo "busybox" | |
| elif [ -d /run/systemd/system ]; then | |
| echo "systemd" | |
| else | |
| echo "unknown" | |
| fi | |
| ;; | |
| esac | |
| } | |
| # ============================================================================= | |
| # DATA COLLECTION FUNCTIONS | |
| # ============================================================================= | |
| collect_boot_identity() { | |
| log_section "Boot Identity" | |
| local section_dir="$OUT_DIR/01_boot_identity" | |
| mkdir -p "$section_dir" | |
| # Kernel version | |
| log "Collecting kernel version..." | |
| uname -a > "$section_dir/uname_a.txt" 2>&1 | |
| uname -r > "$section_dir/uname_r.txt" 2>&1 | |
| # Kernel command line (authoritative boot args) | |
| log "Collecting kernel command line..." | |
| safe_cat /proc/cmdline > "$section_dir/proc_cmdline.txt" | |
| # UEFI vs BIOS detection | |
| log "Detecting firmware mode..." | |
| if [ -d /sys/firmware/efi ]; then | |
| echo "UEFI" > "$section_dir/firmware_mode.txt" | |
| ls -la /sys/firmware/efi/ > "$section_dir/efi_vars_ls.txt" 2>&1 || true | |
| else | |
| echo "BIOS/Legacy" > "$section_dir/firmware_mode.txt" | |
| fi | |
| # PID 1 info (what's running the system) | |
| log "Collecting PID 1 info..." | |
| safe_cat /proc/1/comm > "$section_dir/pid1_comm.txt" | |
| tr '\0' ' ' < /proc/1/cmdline > "$section_dir/pid1_cmdline.txt" 2>/dev/null || echo "[unreadable]" > "$section_dir/pid1_cmdline.txt" | |
| # Environment detection | |
| detect_environment > "$section_dir/environment_type.txt" | |
| # Secure Boot / Module signature enforcement | |
| log "Checking secure boot / module signing..." | |
| { | |
| echo "=== Kernel cmdline secure boot indicators ===" | |
| grep -oE '(module\.sig_enforce=[^ ]*|efi=[^ ]*|secureboot[^ ]*)' /proc/cmdline 2>/dev/null || echo "[none found]" | |
| echo "" | |
| echo "=== Module signature enforce sysctl ===" | |
| sysfs_read /proc/sys/kernel/module_sig_enforce "module_sig_enforce" | |
| echo "" | |
| echo "=== Secure boot EFI variable ===" | |
| if [ -r /sys/firmware/efi/efivars/SecureBoot-* ]; then | |
| echo "SecureBoot EFI var present" | |
| ls -la /sys/firmware/efi/efivars/SecureBoot-* 2>/dev/null || true | |
| else | |
| echo "SecureBoot EFI var not found" | |
| fi | |
| } > "$section_dir/secure_boot_info.txt" 2>&1 | |
| } | |
| collect_kernel_config() { | |
| log_section "Kernel Configuration" | |
| local section_dir="$OUT_DIR/02_kernel_config" | |
| mkdir -p "$section_dir" | |
| log "Collecting kernel config..." | |
| # Try /proc/config.gz first (if CONFIG_IKCONFIG_PROC=y) | |
| if [ -r /proc/config.gz ]; then | |
| log " Found /proc/config.gz" | |
| if cmd_exists zcat; then | |
| zcat /proc/config.gz > "$section_dir/kernel_config.txt" 2>&1 | |
| elif cmd_exists gunzip; then | |
| gunzip -c /proc/config.gz > "$section_dir/kernel_config.txt" 2>&1 | |
| else | |
| cp /proc/config.gz "$section_dir/config.gz" | |
| echo "[config.gz copied, no zcat available to extract]" > "$section_dir/kernel_config.txt" | |
| fi | |
| # Try /boot/config-<version> | |
| elif [ -r "/boot/config-$(uname -r)" ]; then | |
| log " Found /boot/config-$(uname -r)" | |
| cp "/boot/config-$(uname -r)" "$section_dir/kernel_config.txt" | |
| else | |
| echo "[Kernel config not available]" > "$section_dir/kernel_config.txt" | |
| fi | |
| # Extract e1000e-specific config if available | |
| if [ -s "$section_dir/kernel_config.txt" ] && [ "$(head -c 1 "$section_dir/kernel_config.txt")" != "[" ]; then | |
| log " Extracting e1000e config options..." | |
| grep -E '^CONFIG_(E1000|E1000E|INTEL)' "$section_dir/kernel_config.txt" > "$section_dir/e1000e_config.txt" 2>/dev/null || echo "[no e1000e config found]" > "$section_dir/e1000e_config.txt" | |
| # Module vs built-in determination | |
| grep -E '^CONFIG_E1000E=' "$section_dir/kernel_config.txt" > "$section_dir/e1000e_builtin_or_module.txt" 2>/dev/null || echo "[CONFIG_E1000E not found]" > "$section_dir/e1000e_builtin_or_module.txt" | |
| fi | |
| } | |
| collect_modules_info() { | |
| log_section "Modules Information" | |
| local section_dir="$OUT_DIR/03_modules" | |
| mkdir -p "$section_dir" | |
| # Loaded modules | |
| log "Collecting loaded modules..." | |
| safe_cat /proc/modules > "$section_dir/proc_modules.txt" | |
| if cmd_exists lsmod; then | |
| lsmod > "$section_dir/lsmod.txt" 2>&1 | |
| fi | |
| # All modules in /sys/module | |
| log "Listing /sys/module entries..." | |
| ls -1 /sys/module > "$section_dir/sys_module_list.txt" 2>&1 | |
| # e1000e specific module info | |
| log "Collecting e1000e module parameters..." | |
| if [ -d /sys/module/e1000e ]; then | |
| echo "e1000e module is loaded" > "$section_dir/e1000e_status.txt" | |
| # Parameters | |
| if [ -d /sys/module/e1000e/parameters ]; then | |
| mkdir -p "$section_dir/e1000e_parameters" | |
| for param in /sys/module/e1000e/parameters/*; do | |
| if [ -r "$param" ]; then | |
| pname=$(basename "$param") | |
| echo "${pname}=$(cat "$param" 2>/dev/null)" >> "$section_dir/e1000e_params.txt" | |
| cat "$param" > "$section_dir/e1000e_parameters/${pname}" 2>/dev/null | |
| fi | |
| done | |
| else | |
| echo "[no parameters directory]" > "$section_dir/e1000e_params.txt" | |
| fi | |
| # Module refcount and holders | |
| sysfs_read /sys/module/e1000e/refcnt "refcnt" >> "$section_dir/e1000e_status.txt" | |
| if [ -d /sys/module/e1000e/holders ]; then | |
| echo "holders: $(ls /sys/module/e1000e/holders 2>/dev/null | tr '\n' ' ')" >> "$section_dir/e1000e_status.txt" | |
| fi | |
| else | |
| echo "e1000e module is NOT loaded (may be built-in or not present)" > "$section_dir/e1000e_status.txt" | |
| echo "[module not loaded]" > "$section_dir/e1000e_params.txt" | |
| fi | |
| # modinfo if available | |
| if cmd_exists modinfo; then | |
| log "Collecting modinfo for e1000e..." | |
| modinfo e1000e > "$section_dir/modinfo_e1000e.txt" 2>&1 || echo "[modinfo failed]" > "$section_dir/modinfo_e1000e.txt" | |
| fi | |
| # modprobe configuration | |
| log "Collecting modprobe configuration..." | |
| { | |
| echo "=== /etc/modprobe.d/ ===" | |
| if [ -d /etc/modprobe.d ]; then | |
| ls -la /etc/modprobe.d/ 2>/dev/null | |
| echo "" | |
| for f in /etc/modprobe.d/*.conf; do | |
| if [ -r "$f" ]; then | |
| echo "--- $f ---" | |
| cat "$f" | |
| echo "" | |
| fi | |
| done | |
| else | |
| echo "[directory not present]" | |
| fi | |
| echo "" | |
| echo "=== /lib/modprobe.d/ ===" | |
| if [ -d /lib/modprobe.d ]; then | |
| ls -la /lib/modprobe.d/ 2>/dev/null | |
| for f in /lib/modprobe.d/*.conf; do | |
| if [ -r "$f" ]; then | |
| echo "--- $f ---" | |
| cat "$f" | |
| echo "" | |
| fi | |
| done | |
| else | |
| echo "[directory not present]" | |
| fi | |
| echo "" | |
| echo "=== /usr/lib/modprobe.d/ ===" | |
| if [ -d /usr/lib/modprobe.d ]; then | |
| ls -la /usr/lib/modprobe.d/ 2>/dev/null | |
| else | |
| echo "[directory not present]" | |
| fi | |
| } > "$section_dir/modprobe_config.txt" 2>&1 | |
| # e1000e specific modprobe options | |
| log "Extracting e1000e modprobe options..." | |
| grep -r -h "e1000e" /etc/modprobe.d/ /lib/modprobe.d/ /usr/lib/modprobe.d/ 2>/dev/null | grep -v "^#" > "$section_dir/e1000e_modprobe_opts.txt" || echo "[no e1000e options found]" > "$section_dir/e1000e_modprobe_opts.txt" | |
| } | |
| collect_pci_info() { | |
| log_section "PCI Device Information" | |
| local section_dir="$OUT_DIR/04_pci" | |
| mkdir -p "$section_dir" | |
| local pci_path="/sys/bus/pci/devices/${PCI_DEVICE}" | |
| log "Collecting PCI device info for ${PCI_DEVICE}..." | |
| if [ -d "$pci_path" ]; then | |
| echo "PCI device ${PCI_DEVICE} exists" > "$section_dir/device_status.txt" | |
| # Basic device info | |
| { | |
| sysfs_read "$pci_path/vendor" "vendor" | |
| sysfs_read "$pci_path/device" "device" | |
| sysfs_read "$pci_path/subsystem_vendor" "subsystem_vendor" | |
| sysfs_read "$pci_path/subsystem_device" "subsystem_device" | |
| sysfs_read "$pci_path/class" "class" | |
| sysfs_read "$pci_path/revision" "revision" | |
| sysfs_read "$pci_path/irq" "irq" | |
| sysfs_read "$pci_path/numa_node" "numa_node" | |
| sysfs_read "$pci_path/enable" "enable" | |
| sysfs_read "$pci_path/broken_parity_status" "broken_parity_status" | |
| sysfs_read "$pci_path/msi_bus" "msi_bus" | |
| sysfs_read "$pci_path/d3cold_allowed" "d3cold_allowed" | |
| } > "$section_dir/pci_device_attrs.txt" | |
| # Driver binding | |
| log " Checking driver binding..." | |
| if [ -L "$pci_path/driver" ]; then | |
| readlink "$pci_path/driver" > "$section_dir/driver_link.txt" 2>&1 | |
| basename "$(readlink "$pci_path/driver")" > "$section_dir/bound_driver.txt" 2>&1 | |
| else | |
| echo "[no driver bound]" > "$section_dir/driver_link.txt" | |
| echo "[no driver bound]" > "$section_dir/bound_driver.txt" | |
| fi | |
| # Power management | |
| log " Collecting power management state..." | |
| if [ -d "$pci_path/power" ]; then | |
| { | |
| echo "=== Power directory listing ===" | |
| ls -la "$pci_path/power/" | |
| echo "" | |
| echo "=== Power attributes ===" | |
| for attr in control runtime_status runtime_suspended_time runtime_active_time autosuspend_delay_ms; do | |
| sysfs_read "$pci_path/power/$attr" "$attr" | |
| done | |
| } > "$section_dir/power_state.txt" 2>&1 | |
| else | |
| echo "[power directory not present]" > "$section_dir/power_state.txt" | |
| fi | |
| # Resource info | |
| log " Collecting resource info..." | |
| safe_cat "$pci_path/resource" > "$section_dir/resource.txt" | |
| # MSI/MSI-X info | |
| if [ -d "$pci_path/msi_irqs" ]; then | |
| ls -la "$pci_path/msi_irqs/" > "$section_dir/msi_irqs.txt" 2>&1 | |
| else | |
| echo "[no msi_irqs directory]" > "$section_dir/msi_irqs.txt" | |
| fi | |
| # Full sysfs dump of the device | |
| ls -la "$pci_path/" > "$section_dir/sysfs_ls.txt" 2>&1 | |
| else | |
| echo "PCI device ${PCI_DEVICE} NOT FOUND" > "$section_dir/device_status.txt" | |
| log " WARNING: PCI device ${PCI_DEVICE} not found!" | |
| fi | |
| # lspci if available | |
| if cmd_exists lspci; then | |
| log "Collecting lspci output..." | |
| lspci -v > "$section_dir/lspci_v.txt" 2>&1 | |
| lspci -vvv -s "$PCI_DEVICE" > "$section_dir/lspci_vvv_device.txt" 2>&1 || true | |
| lspci -nn > "$section_dir/lspci_nn.txt" 2>&1 | |
| fi | |
| # All network-class PCI devices | |
| log "Listing all PCI devices..." | |
| ls -la /sys/bus/pci/devices/ > "$section_dir/all_pci_devices.txt" 2>&1 | |
| } | |
| collect_interrupt_info() { | |
| log_section "Interrupt Information" | |
| local section_dir="$OUT_DIR/05_interrupts" | |
| mkdir -p "$section_dir" | |
| log "Collecting interrupt info..." | |
| safe_cat /proc/interrupts > "$section_dir/proc_interrupts.txt" | |
| # Filter for e1000e/eth related interrupts | |
| grep -E "(e1000e|eth|enp|eno)" /proc/interrupts > "$section_dir/nic_interrupts.txt" 2>/dev/null || echo "[no NIC interrupts found]" > "$section_dir/nic_interrupts.txt" | |
| # IRQ info | |
| if [ -d /proc/irq ]; then | |
| ls -la /proc/irq/ > "$section_dir/proc_irq_ls.txt" 2>&1 | |
| fi | |
| # Softirqs | |
| safe_cat /proc/softirqs > "$section_dir/proc_softirqs.txt" | |
| } | |
| collect_network_info() { | |
| log_section "Network Information" | |
| local section_dir="$OUT_DIR/06_network" | |
| mkdir -p "$section_dir" | |
| # Detect actual interface name | |
| log "Detecting network interfaces..." | |
| ls -la /sys/class/net/ > "$section_dir/net_interfaces_sysfs.txt" 2>&1 | |
| # Try to find e1000e interface | |
| local actual_iface="$NET_IFACE" | |
| if [ -d "/sys/class/net/${NET_IFACE}/device" ]; then | |
| actual_iface="$NET_IFACE" | |
| else | |
| # Try common names | |
| for iface in eth0 enp0s31f6 eno1 eno2 enp0s25; do | |
| if [ -d "/sys/class/net/${iface}/device" ]; then | |
| # Check if it's our PCI device | |
| if [ "$(readlink /sys/class/net/${iface}/device 2>/dev/null | grep -o '[0-9a-f:.]*$')" = "$PCI_DEVICE" ]; then | |
| actual_iface="$iface" | |
| break | |
| fi | |
| fi | |
| done | |
| fi | |
| echo "$actual_iface" > "$section_dir/detected_interface.txt" | |
| log " Using interface: $actual_iface" | |
| # ip commands if available | |
| if cmd_exists ip; then | |
| log "Collecting ip command output..." | |
| ip link show > "$section_dir/ip_link.txt" 2>&1 | |
| ip addr show > "$section_dir/ip_addr.txt" 2>&1 | |
| ip -s link show > "$section_dir/ip_s_link.txt" 2>&1 | |
| ip route show > "$section_dir/ip_route.txt" 2>&1 | |
| ip -d link show "$actual_iface" > "$section_dir/ip_d_link_iface.txt" 2>&1 || true | |
| fi | |
| # Interface sysfs info | |
| local net_sysfs="/sys/class/net/${actual_iface}" | |
| if [ -d "$net_sysfs" ]; then | |
| log "Collecting interface sysfs info..." | |
| { | |
| sysfs_read "$net_sysfs/operstate" "operstate" | |
| sysfs_read "$net_sysfs/carrier" "carrier" | |
| sysfs_read "$net_sysfs/speed" "speed" | |
| sysfs_read "$net_sysfs/duplex" "duplex" | |
| sysfs_read "$net_sysfs/mtu" "mtu" | |
| sysfs_read "$net_sysfs/flags" "flags" | |
| sysfs_read "$net_sysfs/tx_queue_len" "tx_queue_len" | |
| sysfs_read "$net_sysfs/addr_len" "addr_len" | |
| sysfs_read "$net_sysfs/address" "address" | |
| sysfs_read "$net_sysfs/broadcast" "broadcast" | |
| } > "$section_dir/interface_sysfs.txt" | |
| # Device link | |
| readlink "$net_sysfs/device" > "$section_dir/interface_pci_device.txt" 2>&1 || echo "[no device link]" > "$section_dir/interface_pci_device.txt" | |
| # Statistics | |
| if [ -d "$net_sysfs/statistics" ]; then | |
| for stat in "$net_sysfs/statistics"/*; do | |
| if [ -r "$stat" ]; then | |
| echo "$(basename "$stat")=$(cat "$stat")" | |
| fi | |
| done > "$section_dir/interface_statistics.txt" 2>&1 | |
| fi | |
| else | |
| echo "[interface $actual_iface not found in sysfs]" > "$section_dir/interface_sysfs.txt" | |
| fi | |
| # ethtool if available | |
| if cmd_exists ethtool; then | |
| log "Collecting ethtool output..." | |
| ethtool "$actual_iface" > "$section_dir/ethtool.txt" 2>&1 || true | |
| ethtool -i "$actual_iface" > "$section_dir/ethtool_i.txt" 2>&1 || true | |
| ethtool -k "$actual_iface" > "$section_dir/ethtool_k.txt" 2>&1 || true | |
| ethtool -S "$actual_iface" > "$section_dir/ethtool_S.txt" 2>&1 || true | |
| ethtool -c "$actual_iface" > "$section_dir/ethtool_c.txt" 2>&1 || true | |
| ethtool -g "$actual_iface" > "$section_dir/ethtool_g.txt" 2>&1 || true | |
| ethtool -a "$actual_iface" > "$section_dir/ethtool_a.txt" 2>&1 || true | |
| ethtool -T "$actual_iface" > "$section_dir/ethtool_T.txt" 2>&1 || true | |
| ethtool --show-eee "$actual_iface" > "$section_dir/ethtool_eee.txt" 2>&1 || true | |
| ethtool -d "$actual_iface" > "$section_dir/ethtool_d.txt" 2>&1 || true | |
| ethtool -e "$actual_iface" > "$section_dir/ethtool_e.txt" 2>&1 || true | |
| fi | |
| # /proc/net info | |
| log "Collecting /proc/net info..." | |
| safe_cat /proc/net/dev > "$section_dir/proc_net_dev.txt" | |
| safe_cat /proc/net/dev_mcast > "$section_dir/proc_net_dev_mcast.txt" | |
| } | |
| collect_dmesg() { | |
| log_section "Kernel Messages (dmesg)" | |
| local section_dir="$OUT_DIR/07_dmesg" | |
| mkdir -p "$section_dir" | |
| if cmd_exists dmesg; then | |
| log "Collecting dmesg..." | |
| dmesg > "$section_dir/dmesg_full.txt" 2>&1 | |
| # Timestamps if available | |
| dmesg -T > "$section_dir/dmesg_T.txt" 2>&1 || true | |
| # Filter for relevant messages | |
| log "Extracting e1000e-related messages..." | |
| grep -iE "(e1000e|e1000|intel.*ethernet)" "$section_dir/dmesg_full.txt" > "$section_dir/dmesg_e1000e.txt" 2>/dev/null || echo "[no e1000e messages]" > "$section_dir/dmesg_e1000e.txt" | |
| log "Extracting network-related messages..." | |
| grep -iE "(eth|enp|eno|link|carrier|NIC|network)" "$section_dir/dmesg_full.txt" > "$section_dir/dmesg_network.txt" 2>/dev/null || true | |
| log "Extracting PCI-related messages..." | |
| grep -iE "(pci|00:1f)" "$section_dir/dmesg_full.txt" > "$section_dir/dmesg_pci.txt" 2>/dev/null || true | |
| log "Extracting error/warning messages..." | |
| grep -iE "(error|fail|warn|timeout|reset|hang|watchdog)" "$section_dir/dmesg_full.txt" > "$section_dir/dmesg_errors.txt" 2>/dev/null || true | |
| # Last 500 lines | |
| tail -n 500 "$section_dir/dmesg_full.txt" > "$section_dir/dmesg_tail500.txt" | |
| else | |
| # Fallback: try /dev/kmsg if readable | |
| if [ -r /dev/kmsg ]; then | |
| log "dmesg not available, trying /dev/kmsg..." | |
| timeout 1 cat /dev/kmsg > "$section_dir/kmsg.txt" 2>&1 || true | |
| else | |
| echo "[dmesg not available]" > "$section_dir/dmesg_full.txt" | |
| fi | |
| fi | |
| # Kernel log levels | |
| safe_cat /proc/sys/kernel/printk > "$section_dir/printk_levels.txt" | |
| } | |
| collect_journalctl() { | |
| log_section "Systemd Journal (if available)" | |
| local section_dir="$OUT_DIR/08_journal" | |
| mkdir -p "$section_dir" | |
| if cmd_exists journalctl; then | |
| log "Collecting journalctl output..." | |
| journalctl -b --no-pager > "$section_dir/journalctl_b.txt" 2>&1 || true | |
| journalctl -b -k --no-pager > "$section_dir/journalctl_b_k.txt" 2>&1 || true | |
| journalctl -b -p err --no-pager > "$section_dir/journalctl_b_err.txt" 2>&1 || true | |
| # e1000e specific | |
| journalctl -b --no-pager | grep -iE "e1000e" > "$section_dir/journalctl_e1000e.txt" 2>/dev/null || true | |
| else | |
| echo "[journalctl not available - likely BusyBox/initramfs environment]" > "$section_dir/journalctl_status.txt" | |
| fi | |
| } | |
| collect_initramfs_info() { | |
| log_section "Initramfs Information" | |
| local section_dir="$OUT_DIR/09_initramfs" | |
| mkdir -p "$section_dir" | |
| # Identify which initramfs framework | |
| log "Detecting initramfs framework..." | |
| { | |
| echo "=== Framework Detection ===" | |
| if [ -d /usr/share/initramfs-tools ]; then | |
| echo "initramfs-tools detected" | |
| echo " /usr/share/initramfs-tools exists" | |
| fi | |
| if [ -d /usr/lib/dracut ]; then | |
| echo "dracut detected" | |
| echo " /usr/lib/dracut exists" | |
| fi | |
| if [ -f /etc/mkinitcpio.conf ]; then | |
| echo "mkinitcpio detected" | |
| echo " /etc/mkinitcpio.conf exists" | |
| fi | |
| } > "$section_dir/framework_detection.txt" | |
| # List initramfs files | |
| log "Listing initramfs images..." | |
| { | |
| echo "=== /boot contents ===" | |
| ls -la /boot/initrd* /boot/initramfs* 2>/dev/null || echo "[no initrd/initramfs found in /boot]" | |
| echo "" | |
| echo "=== Current kernel initramfs ===" | |
| local kver=$(uname -r) | |
| for f in "/boot/initrd.img-${kver}" "/boot/initramfs-${kver}.img" "/boot/initrd-${kver}" "/boot/initramfs-linux.img"; do | |
| if [ -e "$f" ]; then | |
| echo "Found: $f" | |
| ls -la "$f" | |
| fi | |
| done | |
| } > "$section_dir/initramfs_files.txt" 2>&1 | |
| # Hash initramfs if found | |
| log "Computing initramfs checksums..." | |
| local kver=$(uname -r) | |
| local initrd="" | |
| for f in "/boot/initrd.img-${kver}" "/boot/initramfs-${kver}.img" "/boot/initrd-${kver}"; do | |
| if [ -e "$f" ]; then | |
| initrd="$f" | |
| break | |
| fi | |
| done | |
| if [ -n "$initrd" ] && [ -e "$initrd" ]; then | |
| if cmd_exists sha256sum; then | |
| sha256sum "$initrd" > "$section_dir/initramfs_sha256.txt" 2>&1 | |
| elif cmd_exists md5sum; then | |
| md5sum "$initrd" > "$section_dir/initramfs_md5.txt" 2>&1 | |
| fi | |
| # Detect compression type | |
| log "Detecting initramfs compression..." | |
| if cmd_exists file; then | |
| file "$initrd" > "$section_dir/initramfs_type.txt" 2>&1 | |
| else | |
| # Manual magic detection | |
| local magic=$(dd if="$initrd" bs=1 count=6 2>/dev/null | od -An -tx1 | tr -d ' \n') | |
| case "$magic" in | |
| 1f8b*) echo "gzip compressed" ;; | |
| fd377a585a00*) echo "xz compressed" ;; | |
| 28b52ffd*) echo "zstd compressed" ;; | |
| 04224d18*) echo "lz4 compressed" ;; | |
| 303730*) echo "cpio archive (uncompressed or multi-segment)" ;; | |
| *) echo "unknown (magic: $magic)" ;; | |
| esac > "$section_dir/initramfs_type.txt" | |
| fi | |
| else | |
| echo "[no initramfs found for kernel $kver]" > "$section_dir/initramfs_type.txt" | |
| fi | |
| # lsinitramfs if available | |
| if cmd_exists lsinitramfs && [ -n "$initrd" ] && [ -e "$initrd" ]; then | |
| log "Listing initramfs contents..." | |
| lsinitramfs "$initrd" > "$section_dir/lsinitramfs_full.txt" 2>&1 || true | |
| # Filter for interesting items | |
| grep -E "(e1000|modprobe|modules)" "$section_dir/lsinitramfs_full.txt" > "$section_dir/lsinitramfs_modules.txt" 2>/dev/null || true | |
| grep -E "\.conf$" "$section_dir/lsinitramfs_full.txt" > "$section_dir/lsinitramfs_configs.txt" 2>/dev/null || true | |
| fi | |
| # initramfs-tools config | |
| if [ -d /etc/initramfs-tools ]; then | |
| log "Collecting initramfs-tools config..." | |
| mkdir -p "$section_dir/initramfs-tools" | |
| cp /etc/initramfs-tools/initramfs.conf "$section_dir/initramfs-tools/" 2>/dev/null || true | |
| cp /etc/initramfs-tools/modules "$section_dir/initramfs-tools/" 2>/dev/null || true | |
| ls -la /etc/initramfs-tools/ > "$section_dir/initramfs-tools/ls.txt" 2>&1 | |
| fi | |
| # dracut config | |
| if [ -d /etc/dracut.conf.d ] || [ -f /etc/dracut.conf ]; then | |
| log "Collecting dracut config..." | |
| mkdir -p "$section_dir/dracut" | |
| cp /etc/dracut.conf "$section_dir/dracut/" 2>/dev/null || true | |
| if [ -d /etc/dracut.conf.d ]; then | |
| cp -r /etc/dracut.conf.d "$section_dir/dracut/" 2>/dev/null || true | |
| fi | |
| fi | |
| } | |
| collect_process_info() { | |
| log_section "Process Information" | |
| local section_dir="$OUT_DIR/10_processes" | |
| mkdir -p "$section_dir" | |
| log "Collecting process list..." | |
| if cmd_exists ps; then | |
| ps aux > "$section_dir/ps_aux.txt" 2>&1 || ps > "$section_dir/ps.txt" 2>&1 || true | |
| fi | |
| # Mount points | |
| log "Collecting mount points..." | |
| cat /proc/mounts > "$section_dir/proc_mounts.txt" 2>&1 | |
| if cmd_exists mount; then | |
| mount > "$section_dir/mount.txt" 2>&1 | |
| fi | |
| # Memory info | |
| safe_cat /proc/meminfo > "$section_dir/meminfo.txt" | |
| # CPU info | |
| safe_cat /proc/cpuinfo > "$section_dir/cpuinfo.txt" | |
| } | |
| collect_system_info() { | |
| log_section "Additional System Information" | |
| local section_dir="$OUT_DIR/11_system" | |
| mkdir -p "$section_dir" | |
| # DMI/SMBIOS info | |
| log "Collecting DMI info..." | |
| if [ -d /sys/class/dmi/id ]; then | |
| { | |
| for f in /sys/class/dmi/id/*; do | |
| if [ -r "$f" ] && [ ! -d "$f" ]; then | |
| echo "$(basename "$f")=$(cat "$f" 2>/dev/null || echo '[unreadable]')" | |
| fi | |
| done | |
| } > "$section_dir/dmi_info.txt" 2>&1 | |
| fi | |
| # Boot time | |
| safe_cat /proc/uptime > "$section_dir/uptime.txt" | |
| # ACPI info (power management related) | |
| if [ -d /sys/firmware/acpi ]; then | |
| ls -la /sys/firmware/acpi/ > "$section_dir/acpi_ls.txt" 2>&1 | |
| fi | |
| # /proc/version | |
| safe_cat /proc/version > "$section_dir/proc_version.txt" | |
| # Available kernel modules in /lib/modules | |
| local kver=$(uname -r) | |
| if [ -d "/lib/modules/${kver}" ]; then | |
| log "Listing available kernel modules..." | |
| find "/lib/modules/${kver}" -name "*.ko*" 2>/dev/null | head -n 1000 > "$section_dir/available_modules.txt" | |
| # Check for e1000e specifically | |
| find "/lib/modules/${kver}" -name "e1000e*" > "$section_dir/e1000e_module_path.txt" 2>/dev/null || echo "[not found]" > "$section_dir/e1000e_module_path.txt" | |
| fi | |
| } | |
| generate_manifest() { | |
| log_section "Generating Manifest" | |
| local manifest="$OUT_DIR/MANIFEST.txt" | |
| { | |
| echo "========================================" | |
| echo " E1000E Data Collection Manifest" | |
| echo "========================================" | |
| echo "" | |
| echo "Collection timestamp: $(date '+%Y-%m-%d %H:%M:%S %Z')" | |
| echo "Kernel version: $(uname -r)" | |
| echo "Environment type: $(detect_environment)" | |
| echo "PCI device: ${PCI_DEVICE}" | |
| echo "Network interface: ${NET_IFACE}" | |
| echo "Output directory: ${OUT_DIR}" | |
| echo "" | |
| echo "========================================" | |
| echo " Available Tools at Collection Time" | |
| echo "========================================" | |
| for cmd in sh cat ls find grep sort dmesg ip ethtool lspci lsmod modinfo journalctl lsinitramfs file sha256sum md5sum zcat; do | |
| if cmd_exists "$cmd"; then | |
| echo " [X] $cmd" | |
| else | |
| echo " [ ] $cmd" | |
| fi | |
| done | |
| echo "" | |
| echo "========================================" | |
| echo " Collected Files" | |
| echo "========================================" | |
| find "$OUT_DIR" -type f | sort | while read -r f; do | |
| echo " $f" | |
| done | |
| } > "$manifest" | |
| # Create checksums for all collected files | |
| log "Creating checksums..." | |
| if cmd_exists sha256sum; then | |
| find "$OUT_DIR" -type f ! -name "CHECKSUMS.txt" -exec sha256sum {} \; > "$OUT_DIR/CHECKSUMS.txt" 2>/dev/null || true | |
| elif cmd_exists md5sum; then | |
| find "$OUT_DIR" -type f ! -name "CHECKSUMS.txt" -exec md5sum {} \; > "$OUT_DIR/CHECKSUMS.txt" 2>/dev/null || true | |
| fi | |
| } | |
| # ============================================================================= | |
| # MAIN EXECUTION | |
| # ============================================================================= | |
| main() { | |
| echo "========================================" | |
| echo " E1000E Data Collector" | |
| echo " Output: ${OUT_DIR}" | |
| echo "========================================" | |
| echo "" | |
| mkdir -p "$OUT_DIR" | |
| # Detect and log environment | |
| ENV_TYPE=$(detect_environment) | |
| log "Detected environment: $ENV_TYPE" | |
| echo "$ENV_TYPE" > "$OUT_DIR/environment_type.txt" | |
| # Run all collection functions | |
| collect_boot_identity | |
| collect_kernel_config | |
| collect_modules_info | |
| collect_pci_info | |
| collect_interrupt_info | |
| collect_network_info | |
| collect_dmesg | |
| collect_journalctl | |
| collect_initramfs_info | |
| collect_process_info | |
| collect_system_info | |
| generate_manifest | |
| log_section "Collection Complete" | |
| echo "" | |
| echo "Data collected to: $OUT_DIR" | |
| echo "" | |
| echo "To save to external media (USB/boot partition):" | |
| echo " mount /dev/sdX1 /mnt" | |
| echo " cp -a $OUT_DIR /mnt/" | |
| echo " sync && umount /mnt" | |
| echo "" | |
| echo "For comparison, run this script on both:" | |
| echo " 1. BusyBox/initramfs environment (boot with break=premount)" | |
| echo " 2. Fully booted system" | |
| echo "" | |
| echo "Then diff the results:" | |
| echo " diff -r /path/to/busybox-manifest /path/to/system-manifest" | |
| echo "" | |
| } | |
| # Run main | |
| main "$@" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # net_collect.sh - collect NIC and driver diagnostics in busybox/initramfs | |
| OUT="${1:-/tmp/netdiag-$(date +%Y%m%d-%H%M%S).log}" | |
| echo "==== NET DIAGNOSTIC DUMP $(date) ====" > "$OUT" | |
| echo >> "$OUT" | |
| echo "== uname -a ==" >> "$OUT" | |
| uname -a >> "$OUT" 2>&1 | |
| echo >> "$OUT" | |
| echo "== /proc/cmdline ==" >> "$OUT" | |
| cat /proc/cmdline >> "$OUT" 2>&1 | |
| echo >> "$OUT" | |
| echo "== Loaded modules ==" >> "$OUT" | |
| # busybox lsmod is fine | |
| lsmod >> "$OUT" 2>&1 | |
| echo >> "$OUT" | |
| echo "== PCI info for Intel NICs (if any) ==" >> "$OUT" | |
| if [ -d /sys/bus/pci/devices ]; then | |
| for p in /sys/bus/pci/devices/*; do | |
| [ -e "$p/vendor" ] || continue | |
| vend=$(cat "$p/vendor" 2>/dev/null) | |
| dev=$(cat "$p/device" 2>/dev/null) | |
| # 0x8086 is Intel | |
| if [ "$vend" = "0x8086" ]; then | |
| echo "--- $p ---" >> "$OUT" | |
| echo "vendor=$vend device=$dev" >> "$OUT" | |
| [ -e "$p/class" ] && echo "class=$(cat "$p/class")" >> "$OUT" | |
| [ -e "$p/subsystem_vendor" ] && echo "subsystem_vendor=$(cat "$p/subsystem_vendor")" >> "$OUT" | |
| [ -e "$p/subsystem_device" ] && echo "subsystem_device=$(cat "$p/subsystem_device")" >> "$OUT" | |
| fi | |
| done | |
| fi | |
| echo >> "$OUT" | |
| echo "== Network interfaces ==" >> "$OUT" | |
| for n in /sys/class/net/*; do | |
| IF=$(basename "$n") | |
| echo "--- $IF ---" >> "$OUT" | |
| if [ -e "$n/device/driver" ]; then | |
| drv=$(readlink -f "$n/device/driver" 2>/dev/null | sed 's#.*/##') | |
| echo "driver=$drv" >> "$OUT" | |
| else | |
| echo "driver=(none)" >> "$OUT" | |
| fi | |
| echo "ip link show $IF:" >> "$OUT" | |
| ip link show "$IF" >> "$OUT" 2>&1 | |
| echo "ethtool $IF:" >> "$OUT" | |
| ethtool "$IF" >> "$OUT" 2>&1 | |
| echo "ethtool -k $IF:" >> "$OUT" | |
| ethtool -k "$IF" >> "$OUT" 2>&1 | |
| echo "ethtool -g $IF:" >> "$OUT" | |
| ethtool -g "$IF" >> "$OUT" 2>&1 | |
| echo "ethtool -S $IF:" >> "$OUT" | |
| ethtool -S "$IF" >> "$OUT" 2>&1 | |
| done | |
| echo >> "$OUT" | |
| echo "== e1000e module parameters (if present) ==" >> "$OUT" | |
| if [ -d /sys/module/e1000e ]; then | |
| for p in /sys/module/e1000e/parameters/*; do | |
| name=$(basename "$p") | |
| val=$(cat "$p" 2>/dev/null) | |
| echo "$name=$val" >> "$OUT" | |
| done | |
| else | |
| echo "e1000e module not loaded" >> "$OUT" | |
| fi | |
| echo >> "$OUT" | |
| echo "== dmesg (last 200 lines) ==" >> "$OUT" | |
| dmesg | tail -n 200 >> "$OUT" 2>&1 | |
| echo >> "$OUT" | |
| echo "==== END ====" >> "$OUT" | |
| echo "Written diagnostics to: $OUT" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/sh | |
| # net_fuzz_e1000e.sh - brute-test e1000e + ethtool combinations in busybox | |
| LOG="${1:-/tmp/e1000e-fuzz-$(date +%Y%m%d-%H%M%S).log}" | |
| SLEEP_SEC="${SLEEP_SEC:-8}" # time to wait after bringing link up | |
| MAX_ITERS="${MAX_ITERS:-999999}" # safety cap if you tweak loops | |
| echo "==== e1000e fuzz run $(date) ====" > "$LOG" | |
| echo "LOG=$LOG" >> "$LOG" | |
| echo >> "$LOG" | |
| # Find all interfaces driven by e1000e | |
| find_e1000e_ifs() { | |
| for n in /sys/class/net/*; do | |
| IF=$(basename "$n") | |
| drv=$(readlink -f "$n"/device/driver 2>/dev/null | sed 's#.*/##') | |
| [ "$drv" = "e1000e" ] && echo "$IF" | |
| done | |
| } | |
| IFS_LIST=$(find_e1000e_ifs) | |
| if [ -z "$IFS_LIST" ]; then | |
| echo "No interfaces with driver e1000e found" | tee -a "$LOG" | |
| exit 1 | |
| fi | |
| echo "Interfaces on e1000e: $IFS_LIST" | tee -a "$LOG" | |
| echo >> "$LOG" | |
| # Helper: reload e1000e with options | |
| reload_e1000e() { | |
| INTMODE="$1" | |
| ITR="$2" | |
| echo "Reloading e1000e IntMode=$INTMODE ITR=$ITR" >> "$LOG" | |
| # remove if loaded | |
| if lsmod | grep -q '^e1000e'; then | |
| rmmod e1000e 2>>"$LOG" | |
| sleep 1 | |
| fi | |
| # now load with given options | |
| modprobe e1000e IntMode="$INTMODE" InterruptThrottleRate="$ITR" 2>>"$LOG" | |
| RET=$? | |
| if [ $RET -ne 0 ]; then | |
| echo "modprobe failed: IntMode=$INTMODE ITR=$ITR ret=$RET" >> "$LOG" | |
| return 1 | |
| fi | |
| return 0 | |
| } | |
| # Helper: configure one interface with ethtool + speed mode | |
| config_if() { | |
| IF="$1" | |
| OFFLOAD_MODE="$2" # on/off | |
| SPEED_MODE="$3" # auto/100 | |
| echo "Configuring $IF offload=$OFFLOAD_MODE speed=$SPEED_MODE" >> "$LOG" | |
| # reset link down | |
| ip link set "$IF" down 2>>"$LOG" | |
| # speed | |
| case "$SPEED_MODE" in | |
| auto) | |
| ethtool -s "$IF" autoneg on 2>>"$LOG" | |
| ;; | |
| 100) | |
| # you might need matching config on switch side | |
| ethtool -s "$IF" speed 100 duplex full autoneg off 2>>"$LOG" | |
| ;; | |
| esac | |
| # offloads | |
| if [ "$OFFLOAD_MODE" = "off" ]; then | |
| ethtool -K "$IF" tso off gso off gro off lro off rx off tx off 2>>"$LOG" | |
| ethtool --set-eee "$IF" eee off 2>>"$LOG" | |
| else | |
| # try to restore defaults best-effort | |
| ethtool -K "$IF" tso on gso on gro on rx on tx on 2>>"$LOG" | |
| ethtool --set-eee "$IF" eee on 2>>"$LOG" | |
| fi | |
| # bring up | |
| ip link set "$IF" up 2>>"$LOG" | |
| } | |
| # Helper: capture dmesg delta | |
| snapshot_dmesg() { | |
| dmesg > "$1" | |
| } | |
| dmesg_has_error() { | |
| # grep for patterns that indicate trouble | |
| dmesg_diff="$1" | |
| grep -E "e1000e.*Hardware Unit Hang|NETDEV WATCHDOG|TX Unit Hang|Detected Hardware Unit Hang" "$dmesg_diff" >/dev/null 2>&1 | |
| } | |
| # main test loop | |
| ITER=0 | |
| for INTMODE in 0 1 2; do | |
| for ITR in 0 3000 1; do | |
| # reload driver for this pair | |
| reload_e1000e "$INTMODE" "$ITR" || continue | |
| # after reloading, recompute interface list (names may change in theory) | |
| IFS_LIST=$(find_e1000e_ifs) | |
| for OFFLOAD_MODE in off on; do | |
| for SPEED_MODE in auto 100; do | |
| ITER=$((ITER+1)) | |
| [ $ITER -gt $MAX_ITERS ] && echo "Reached MAX_ITERS=$MAX_ITERS, stopping" >> "$LOG" && exit 0 | |
| echo "---- TEST #$ITER ----" >> "$LOG" | |
| echo "IntMode=$INTMODE ITR=$ITR offload=$OFFLOAD_MODE speed=$SPEED_MODE" >> "$LOG" | |
| # snapshot dmesg before | |
| BEFORE="/tmp/dmesg_before_$$" | |
| AFTER="/tmp/dmesg_after_$$" | |
| DIFF="/tmp/dmesg_diff_$$" | |
| snapshot_dmesg "$BEFORE" | |
| # apply config to each e1000e interface | |
| for IF in $IFS_LIST; do | |
| echo "Testing interface $IF" >> "$LOG" | |
| config_if "$IF" "$OFFLOAD_MODE" "$SPEED_MODE" | |
| # Optional: you can add a simple ping here if you know a target | |
| # ping -c 2 -w 3 <gateway_or_host> >/dev/null 2>&1 | |
| done | |
| # wait for potential hang/watchdog | |
| sleep "$SLEEP_SEC" | |
| snapshot_dmesg "$AFTER" | |
| # busybox 'diff' might not exist; use a crude way: | |
| # cut new messages from AFTER that are not in BEFORE by tailing | |
| # simplest: just 'tail' and search for patterns | |
| tail -n 100 "$AFTER" > "$DIFF" | |
| if dmesg_has_error "$DIFF"; then | |
| echo "RESULT: PROBLEM DETECTED" >> "$LOG" | |
| echo "Relevant dmesg lines:" >> "$LOG" | |
| grep -E "e1000e.*Hardware Unit Hang|NETDEV WATCHDOG|TX Unit Hang|Detected Hardware Unit Hang" "$DIFF" >> "$LOG" | |
| else | |
| echo "RESULT: OK (no hang/watchdog in last $SLEEP_SEC s)" >> "$LOG" | |
| fi | |
| echo >> "$LOG" | |
| rm -f "$BEFORE" "$AFTER" "$DIFF" | |
| done | |
| done | |
| done | |
| done | |
| echo "==== DONE $(date) ====" >> "$LOG" | |
| echo "Fuzz log written to: $LOG" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment