better limits

This commit is contained in:
goldsquid
2026-01-08 09:38:38 +07:00
parent e9bd0dd120
commit 624b1da9a6

View File

@@ -1,11 +1,18 @@
#!/bin/bash #!/bin/bash
# General script to limit bandwidth for all public ports in a Docker Compose file # General script to limit OUTGOING bandwidth for all public ports in a Docker Compose file
# Limits each port to specified bandwidth (default: 100 MBit/s) # Limits each port's outgoing traffic to specified bandwidth (default: 100 MBit/s)
#
# Note: This script limits OUTGOING bandwidth only. Limiting incoming bandwidth is
# impractical for P2P networks because:
# - You can't control what other nodes send you
# - Dropping incoming packets causes retransmissions and wastes bandwidth
# - P2P protocols have backpressure - if you're slow to respond, peers back off
# - Limiting outgoing is usually sufficient to control your bandwidth usage
# #
# Usage: # Usage:
# ./limit-bandwidth.sh <compose-file> [start|stop|status] [--limit BANDWIDTH] # ./limit-bandwidth.sh <compose-file> [start|stop|status] [--limit BANDWIDTH]
# ./limit-bandwidth.sh rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace.yml start # ./limit-bandwidth.sh rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace start
# ./limit-bandwidth.sh rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace.yml start --limit 20mbit # ./limit-bandwidth.sh rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace start --limit 20mbit
# #
# Environment variable: # Environment variable:
# BANDWIDTH_LIMIT=20mbit ./limit-bandwidth.sh <compose-file> start # BANDWIDTH_LIMIT=20mbit ./limit-bandwidth.sh <compose-file> start
@@ -61,10 +68,11 @@ if [ $# -lt 1 ]; then
echo " Can also use BANDWIDTH_LIMIT environment variable" echo " Can also use BANDWIDTH_LIMIT environment variable"
echo "" echo ""
echo "Examples:" echo "Examples:"
echo " $0 rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace start"
echo " $0 rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace.yml start" echo " $0 rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace.yml start"
echo " $0 rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace.yml start --limit 20mbit" echo " $0 rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace start --limit 20mbit"
echo " BANDWIDTH_LIMIT=20mbit $0 rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace.yml start" echo " BANDWIDTH_LIMIT=20mbit $0 rpc/gnosis/reth/gnosis-mainnet-reth-pruned-trace start"
echo " $0 rpc/ethereum/geth/ethereum-mainnet-geth-pruned-pebble-path.yml status" echo " $0 rpc/ethereum/geth/ethereum-mainnet-geth-pruned-pebble-path status"
exit 1 exit 1
fi fi
@@ -86,6 +94,12 @@ elif [ "$ACTION" = "--limit" ]; then
exit 1 exit 1
fi fi
# Handle .yml extension (like latest.sh does)
# If filename doesn't end in .yml, append it
if [[ ! "$COMPOSE_FILE" == *.yml ]]; then
COMPOSE_FILE="${COMPOSE_FILE}.yml"
fi
# Resolve compose file path # Resolve compose file path
if [ ! -f "$COMPOSE_FILE" ]; then if [ ! -f "$COMPOSE_FILE" ]; then
# Try relative to BASEPATH # Try relative to BASEPATH
@@ -93,6 +107,7 @@ if [ ! -f "$COMPOSE_FILE" ]; then
COMPOSE_FILE="$BASEPATH/$COMPOSE_FILE" COMPOSE_FILE="$BASEPATH/$COMPOSE_FILE"
else else
echo -e "${RED}Error: Compose file not found: $1${NC}" echo -e "${RED}Error: Compose file not found: $1${NC}"
echo "Tried: $COMPOSE_FILE and $BASEPATH/$COMPOSE_FILE"
exit 1 exit 1
fi fi
fi fi
@@ -222,7 +237,12 @@ case "$ACTION" in
# Remove existing qdisc if any # Remove existing qdisc if any
tc qdisc del dev "$BRIDGE" root 2>/dev/null || true tc qdisc del dev "$BRIDGE" root 2>/dev/null || true
# Create HTB (Hierarchical Token Bucket) qdisc # Create HTB (Hierarchical Token Bucket) qdisc for egress (outgoing traffic only)
# We only limit outgoing because:
# - You control what you send (outgoing)
# - You can't control what others send (incoming)
# - Dropping incoming packets causes retransmissions and wastes bandwidth
# - P2P protocols have backpressure mechanisms
tc qdisc add dev "$BRIDGE" root handle 1: htb default 30 tc qdisc add dev "$BRIDGE" root handle 1: htb default 30
# Create root class with high bandwidth # Create root class with high bandwidth
@@ -236,39 +256,31 @@ case "$ACTION" in
for port in "${PORTS[@]}"; do for port in "${PORTS[@]}"; do
echo -e "${BLUE} Limiting port ${port} to ${BANDWIDTH_LIMIT}...${NC}" echo -e "${BLUE} Limiting port ${port} to ${BANDWIDTH_LIMIT}...${NC}"
# Create limited class for this port # Create limited class for this port (outgoing traffic only)
tc class add dev "$BRIDGE" parent 1:1 classid 1:${PORT_ID} htb rate ${BANDWIDTH_LIMIT} burst ${BURST} ceil ${BANDWIDTH_LIMIT} tc class add dev "$BRIDGE" parent 1:1 classid 1:${PORT_ID} htb rate ${BANDWIDTH_LIMIT} burst ${BURST} ceil ${BANDWIDTH_LIMIT}
# Add filter to route marked packets to this class # Add filter to route marked packets to this class (outgoing only)
tc filter add dev "$BRIDGE" parent 1: protocol ip prio ${PORT_ID} handle ${PORT_ID} fw flowid 1:${PORT_ID} tc filter add dev "$BRIDGE" parent 1: protocol ip prio ${PORT_ID} handle ${PORT_ID} fw flowid 1:${PORT_ID}
# Mark TCP traffic for this port # Mark outgoing traffic in OUTPUT chain (traffic from host)
iptables -t mangle -C OUTPUT -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \ iptables -t mangle -C OUTPUT -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \
iptables -t mangle -A OUTPUT -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} iptables -t mangle -A OUTPUT -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID}
iptables -t mangle -C OUTPUT -p tcp --dport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \
iptables -t mangle -A OUTPUT -p tcp --dport ${port} -j MARK --set-mark ${PORT_ID}
# Mark UDP traffic for this port
iptables -t mangle -C OUTPUT -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \ iptables -t mangle -C OUTPUT -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \
iptables -t mangle -A OUTPUT -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} iptables -t mangle -A OUTPUT -p udp --sport ${port} -j MARK --set-mark ${PORT_ID}
iptables -t mangle -C OUTPUT -p udp --dport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \
iptables -t mangle -A OUTPUT -p udp --dport ${port} -j MARK --set-mark ${PORT_ID}
# Mark in FORWARD chain (container traffic) # Mark outgoing traffic in FORWARD chain (traffic from containers)
# This catches traffic from containers going out through the bridge
iptables -t mangle -C FORWARD -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \ iptables -t mangle -C FORWARD -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \
iptables -t mangle -A FORWARD -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} iptables -t mangle -A FORWARD -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID}
iptables -t mangle -C FORWARD -p tcp --dport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \
iptables -t mangle -A FORWARD -p tcp --dport ${port} -j MARK --set-mark ${PORT_ID}
iptables -t mangle -C FORWARD -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \ iptables -t mangle -C FORWARD -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \
iptables -t mangle -A FORWARD -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} iptables -t mangle -A FORWARD -p udp --sport ${port} -j MARK --set-mark ${PORT_ID}
iptables -t mangle -C FORWARD -p udp --dport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || \
iptables -t mangle -A FORWARD -p udp --dport ${port} -j MARK --set-mark ${PORT_ID}
PORT_ID=$((PORT_ID + 1)) PORT_ID=$((PORT_ID + 1))
done done
echo -e "${GREEN}Bandwidth limiting configured!${NC}" echo -e "${GREEN}Outgoing bandwidth limiting configured!${NC}"
echo -e "${GREEN}All ports are now limited to ${BANDWIDTH_LIMIT} each${NC}" echo -e "${GREEN}All ports are now limited to ${BANDWIDTH_LIMIT} outgoing traffic each${NC}"
echo -e "${YELLOW}Note: Only OUTGOING traffic is limited. Incoming traffic is not limited.${NC}"
;; ;;
stop) stop)
echo -e "${YELLOW}Removing bandwidth limiting...${NC}" echo -e "${YELLOW}Removing bandwidth limiting...${NC}"
@@ -278,14 +290,13 @@ case "$ACTION" in
for port in "${PORTS[@]}"; do for port in "${PORTS[@]}"; do
echo -e "${BLUE} Removing limits for port ${port}...${NC}" echo -e "${BLUE} Removing limits for port ${port}...${NC}"
# Remove OUTPUT rules (outgoing from host)
iptables -t mangle -D OUTPUT -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true iptables -t mangle -D OUTPUT -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true
iptables -t mangle -D OUTPUT -p tcp --dport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true
iptables -t mangle -D OUTPUT -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true iptables -t mangle -D OUTPUT -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true
iptables -t mangle -D OUTPUT -p udp --dport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true
# Remove FORWARD rules (outgoing from containers)
iptables -t mangle -D FORWARD -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true iptables -t mangle -D FORWARD -p tcp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true
iptables -t mangle -D FORWARD -p tcp --dport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true
iptables -t mangle -D FORWARD -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true iptables -t mangle -D FORWARD -p udp --sport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true
iptables -t mangle -D FORWARD -p udp --dport ${port} -j MARK --set-mark ${PORT_ID} 2>/dev/null || true
PORT_ID=$((PORT_ID + 1)) PORT_ID=$((PORT_ID + 1))
done done
@@ -304,12 +315,15 @@ case "$ACTION" in
echo -e "${BLUE}TC Classes:${NC}" echo -e "${BLUE}TC Classes:${NC}"
tc class show dev "$BRIDGE" 2>/dev/null || echo " No classes configured" tc class show dev "$BRIDGE" 2>/dev/null || echo " No classes configured"
echo "" echo ""
echo -e "${BLUE}Iptables rules (OUTPUT):${NC}" echo -e "${BLUE}Iptables rules (OUTPUT - outgoing from host):${NC}"
iptables -t mangle -L OUTPUT -n --line-numbers | grep -E "MARK|${PORTS[0]}" || echo " No rules found" iptables -t mangle -L OUTPUT -n --line-numbers | grep -E "MARK|${PORTS[0]}" || echo " No rules found"
echo "" echo ""
echo -e "${BLUE}Iptables rules (FORWARD):${NC}" echo -e "${BLUE}Iptables rules (FORWARD - outgoing from containers):${NC}"
iptables -t mangle -L FORWARD -n --line-numbers | grep -E "MARK|${PORTS[0]}" || echo " No rules found" iptables -t mangle -L FORWARD -n --line-numbers | grep -E "MARK|${PORTS[0]}" || echo " No rules found"
echo "" echo ""
echo -e "${YELLOW}Note: Only outgoing traffic is limited. Incoming traffic is not limited${NC}"
echo -e "${YELLOW} because you can't control what other nodes send you.${NC}"
echo ""
echo -e "${BLUE}Monitored ports: ${PORTS[*]}${NC}" echo -e "${BLUE}Monitored ports: ${PORTS[*]}${NC}"
;; ;;
*) *)