#!/usr/bin/env bash # Creates a systemd service to disable NIC offloading features for Intel e1000e interfaces # Author: rcastley # License: MIT YW=$(echo "\033[33m") YWB=$'\e[93m' BL=$(echo "\033[36m") RD=$(echo "\033[01;31m") BGN=$(echo "\033[4;92m") GN=$(echo "\033[1;92m") DGN=$(echo "\033[32m") CL=$(echo "\033[m") TAB=" " CM="${TAB}✔️${TAB}" CROSS="${TAB}✖️${TAB}" INFO="${TAB}ℹ️${TAB}${CL}" WARN="${TAB}⚠️${TAB}${CL}" function header_info { clear cat <<"EOF" _ ____________ ____ __________ ___ ____ _ __ __ / | / / _/ ____/ / __ \/ __/ __/ /___ ____ _____/ (_)___ ____ _ / __ \(_)________ _/ /_ / /__ _____ / |/ // // / / / / / /_/ /_/ / __ \/ __ `/ __ / / __ \/ __ `/ / / / / / ___/ __ `/ __ \/ / _ \/ ___/ / /| // // /___ / /_/ / __/ __/ / /_/ / /_/ / /_/ / / / / / /_/ / / /_/ / (__ ) /_/ / /_/ / / __/ / /_/ |_/___/\____/ \____/_/ /_/ /_/\____/\__,_/\__,_/_/_/ /_/\__, / /_____/_/____/\__,_/_.___/_/\___/_/ /____/ EOF } header_info function msg_info() { echo -e "${INFO} ${YW}${1}...${CL}"; } function msg_ok() { echo -e "${CM} ${GN}${1}${CL}"; } function msg_error() { echo -e "${CROSS} ${RD}${1}${CL}"; } function msg_warn() { echo -e "${WARN} ${YWB}${1}"; } # Check for root privileges if [ "$(id -u)" -ne 0 ]; then msg_error "Error: This script must be run as root." exit 1 fi if ! command -v ethtool >/dev/null 2>&1; then msg_info "Installing ethtool" apt-get update &>/dev/null apt-get install -y ethtool &>/dev/null || { msg_error "Failed to install ethtool. Exiting."; exit 1; } msg_ok "ethtool installed successfully" fi # Get list of network interfaces using Intel e1000e driver INTERFACES=() COUNT=0 msg_info "Searching for Intel e1000e interfaces" for device in /sys/class/net/*; do interface="$(basename "$device")" # or adjust the rest of the usages below, as mostly you'll use the path anyway # Skip loopback interface and virtual interfaces if [[ "$interface" != "lo" ]] && [[ ! "$interface" =~ ^(tap|fwbr|veth|vmbr|bonding_masters) ]]; then # Check if the interface uses the e1000e driver driver=$(basename $(readlink -f /sys/class/net/$interface/device/driver 2>/dev/null) 2>/dev/null) if [[ "$driver" == "e1000e" ]]; then # Get MAC address for additional identification mac=$(cat /sys/class/net/$interface/address 2>/dev/null) INTERFACES+=("$interface" "Intel e1000e NIC ($mac)") ((COUNT++)) fi fi done # Check if any Intel e1000e interfaces were found if [ ${#INTERFACES[@]} -eq 0 ]; then whiptail --title "Error" --msgbox "No Intel e1000e network interfaces found!" 10 60 msg_error "No Intel e1000e network interfaces found! Exiting." exit 1 fi msg_ok "Found ${BL}$COUNT${GN} Intel e1000e interfaces" # Create a checklist for interface selection with all interfaces initially checked INTERFACES_CHECKLIST=() for ((i=0; i<${#INTERFACES[@]}; i+=2)); do INTERFACES_CHECKLIST+=("${INTERFACES[i]}" "${INTERFACES[i+1]}" "ON") done # Show interface selection checklist SELECTED_INTERFACES=$(whiptail --backtitle "Intel e1000e NIC Offloading Disabler" --title "Network Interfaces" \ --separate-output --checklist "Select Intel e1000e network interfaces\n(Space to toggle, Enter to confirm):" 15 80 6 \ "${INTERFACES_CHECKLIST[@]}" 3>&1 1>&2 2>&3) exitstatus=$? if [ $exitstatus != 0 ]; then msg_info "User canceled. Exiting." exit 0 fi # Check if any interfaces were selected if [ -z "$SELECTED_INTERFACES" ]; then msg_error "No interfaces selected. Exiting." exit 0 fi # Convert the selected interfaces into an array readarray -t INTERFACE_ARRAY <<< "$SELECTED_INTERFACES" # Show the number of selected interfaces INTERFACE_COUNT=${#INTERFACE_ARRAY[@]} # Print selected interfaces for iface in "${INTERFACE_ARRAY[@]}"; do msg_ok "Selected interface: ${BL}$iface${CL}" done # Ask for confirmation with the list of selected interfaces CONFIRMATION_MSG="You have selected the following interface(s):\n\n" for iface in "${INTERFACE_ARRAY[@]}"; do SPEED=$(cat /sys/class/net/$iface/speed 2>/dev/null) MAC=$(cat /sys/class/net/$iface/address 2>/dev/null) CONFIRMATION_MSG+="- $iface (MAC: $MAC, Speed: ${SPEED}Mbps)\n" done CONFIRMATION_MSG+="\nThis will create systemd service(s) to disable offloading features.\n\nProceed?" if ! whiptail --backtitle "Intel e1000e NIC Offloading Disabler" --title "Confirmation" \ --yesno "$CONFIRMATION_MSG" 20 80; then msg_info "User canceled. Exiting." exit 0 fi # Loop through all selected interfaces and create services for each for SELECTED_INTERFACE in "${INTERFACE_ARRAY[@]}"; do # Create service name for this interface SERVICE_NAME="disable-nic-offload-$SELECTED_INTERFACE.service" SERVICE_PATH="/etc/systemd/system/$SERVICE_NAME" # Create the service file with e1000e specific optimizations msg_info "Creating systemd service for interface: ${BL}$SELECTED_INTERFACE${YW}" # Start with the common part of the service file cat > "$SERVICE_PATH" << EOF [Unit] Description=Disable NIC offloading for Intel e1000e interface $SELECTED_INTERFACE After=network.target [Service] Type=oneshot # Disable all offloading features for Intel e1000e ExecStart=/sbin/ethtool -K $SELECTED_INTERFACE gso off gro off tso off tx off rx off rxvlan off txvlan off sg off RemainAfterExit=true [Install] WantedBy=multi-user.target EOF # Check if service file was created successfully if [ ! -f "$SERVICE_PATH" ]; then whiptail --title "Error" --msgbox "Failed to create service file for $SELECTED_INTERFACE!" 10 50 msg_error "Failed to create service file for $SELECTED_INTERFACE! Skipping to next interface." continue fi # Configure this service { echo "25"; sleep 0.2 # Reload systemd to recognize the new service systemctl daemon-reload echo "50"; sleep 0.2 # Start the service systemctl start "$SERVICE_NAME" echo "75"; sleep 0.2 # Enable the service to start on boot systemctl enable "$SERVICE_NAME" echo "100"; sleep 0.2 } | whiptail --backtitle "Intel e1000e NIC Offloading Disabler" --gauge "Configuring service for $SELECTED_INTERFACE..." 10 80 0 # Individual service status if systemctl is-active --quiet "$SERVICE_NAME"; then SERVICE_STATUS="Active" else SERVICE_STATUS="Inactive" fi if systemctl is-enabled --quiet "$SERVICE_NAME"; then BOOT_STATUS="Enabled" else BOOT_STATUS="Disabled" fi # Show individual service results msg_ok "Service for ${BL}$SELECTED_INTERFACE${GN} created and enabled!" msg_info "${TAB}Service: ${BL}$SERVICE_NAME${YW}" msg_info "${TAB}Status: ${BL}$SERVICE_STATUS${YW}" msg_info "${TAB}Start on boot: ${BL}$BOOT_STATUS${YW}" done # Prepare summary of all interfaces SUMMARY_MSG="Services created successfully!\n\n" SUMMARY_MSG+="Configured Interfaces:\n" for iface in "${INTERFACE_ARRAY[@]}"; do SERVICE_NAME="disable-nic-offload-$iface.service" if systemctl is-active --quiet "$SERVICE_NAME"; then SVC_STATUS="Active" else SVC_STATUS="Inactive" fi if systemctl is-enabled --quiet "$SERVICE_NAME"; then BOOT_SVC_STATUS="Enabled" else BOOT_SVC_STATUS="Disabled" fi SUMMARY_MSG+="- $iface: $SVC_STATUS, Boot: $BOOT_SVC_STATUS\n" done # Show summary results whiptail --backtitle "Intel e1000e NIC Offloading Disabler" --title "Success" --msgbox "$SUMMARY_MSG" 20 80 msg_ok "Intel e1000e optimization complete for ${#INTERFACE_ARRAY[@]} interface(s)!" exit 0