#!/bin/bash
# fix_rcvbuf.sh
# Fixes 26 million RcvbufErrors on PowerEdge R730 with 125GB RAM
# Run as root, takes effect immediately, no restart needed

echo "=== Before ==="
cat /proc/net/snmp | grep "^Udp:" | tail -1 | awk '
NR==1{
    print "RcvbufErrors=" $6
    print "InErrors=" $4
}'
# Actually print properly
awk '/^Udp:/{if(NR%2==0) printf "RcvbufErrors=%s  InErrors=%s\n",$6,$4}' /proc/net/snmp

echo ""
echo "=== Applying fixes ==="

# You have 125GB RAM � give UDP massive buffers
# Each socket gets up to 256MB
sysctl -w net.core.rmem_max=268435456        # 256MB max per socket
sysctl -w net.core.rmem_default=134217728    # 128MB default per socket
sysctl -w net.core.wmem_max=268435456
sysctl -w net.core.wmem_default=134217728

# NIC receive queue � process more packets before dropping
sysctl -w net.core.netdev_max_backlog=500000
sysctl -w net.core.netdev_budget=1000
sysctl -w net.core.netdev_budget_usecs=20000

# UDP memory pool � you have 125GB, give it 32GB
# values are in PAGES (4KB each)
# 32GB = 32*1024*1024*1024 / 4096 = 8388608 pages
sysctl -w net.ipv4.udp_mem="4194304 6291456 8388608"
sysctl -w net.ipv4.udp_rmem_min=65536

# IGMP � 300 multicast groups
sysctl -w net.ipv4.igmp_max_memberships=1024
sysctl -w net.ipv4.igmp_max_msf=1024

# Persist across reboots
cat > /etc/sysctl.d/99-udp-hls.conf << 'SYSCTL'
net.core.rmem_max=268435456
net.core.rmem_default=134217728
net.core.wmem_max=268435456
net.core.wmem_default=134217728
net.core.netdev_max_backlog=500000
net.core.netdev_budget=1000
net.core.netdev_budget_usecs=20000
net.ipv4.udp_mem=4194304 6291456 8388608
net.ipv4.udp_rmem_min=65536
net.ipv4.igmp_max_memberships=1024
SYSCTL
echo "Saved to /etc/sysctl.d/99-udp-hls.conf"

# NIC ring buffers � maximize for all NICs
echo ""
echo "=== NIC ring buffers ==="
for nic in $(ip link show | awk -F': ' '/^[0-9]/{print $2}' | grep -v lo); do
    MAX=$(ethtool -g $nic 2>/dev/null | awk '/Pre-set/{found=1} found && /RX:/{print $2; exit}')
    if [ -n "$MAX" ] && [ "$MAX" -gt 0 ]; then
        ethtool -G $nic rx $MAX 2>/dev/null && echo "  $nic: rx ring = $MAX" || true
    fi
done

# Spread NIC IRQs across all 72 CPUs
echo ""
echo "=== IRQ affinity across 72 CPUs ==="
NCPU=72
CPU=0
for IRQ in $(cat /proc/interrupts | grep -E "mlx|bnx|ixgbe|i40e|ens|eth" | awk -F: '{print $1}' | tr -d ' '); do
    MASK=$(printf "%x" $((1 << (CPU % NCPU))))
    echo $MASK > /proc/irq/$IRQ/smp_affinity 2>/dev/null || true
    CPU=$((CPU+1))
done
echo "  Spread $(echo $CPU) IRQs across $NCPU CPUs"

echo ""
echo "=== After (restart udp_hls now, then check again in 60s) ==="
awk '/^Udp:/{if(NR%2==0) printf "RcvbufErrors=%s  InErrors=%s\n",$6,$4}' /proc/net/snmp
echo ""
echo "Monitor with:"
echo "  watch -n5 \"awk '/^Udp:/{if(NR%2==0) printf \\\"RcvbufErrors=%s\\\\n\\\",\\\$6}' /proc/net/snmp\""
