eth0
create-bridge-eth0.sh
#!/bin/bash
#===============================================================================
# Script Name: create-bridge-eth0.sh
# Description: Create bridge configuration using NetworkManager
#===============================================================================
#-------------------------------------------------------------------------------
# Configuration Area - Modify according to your environment
#-------------------------------------------------------------------------------
BRIDGE_NAME="br-lan"
BRIDGE_IP="192.168.2.99/24"
BRIDGE_GATEWAY="192.168.2.1"
BRIDGE_DNS="192.168.2.1"
PHYSICAL_IFACE="eth0"
SLAVE_CONN_NAME="eth0-bridge-port"
# Bridge Advanced Options
BRIDGE_STP="no"
BRIDGE_FORWARD_DELAY="0"
# Background Execution Options
BACKGROUND_MODE="yes"
LOG_FILE=""
#-------------------------------------------------------------------------------
# Color Definitions
#-------------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
#-------------------------------------------------------------------------------
# Logging Functions
#-------------------------------------------------------------------------------
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $1" >> "$LOG_FILE"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] $1" >> "$LOG_FILE"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $1" >> "$LOG_FILE"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1" >> "$LOG_FILE"; }
#-------------------------------------------------------------------------------
# Background Mode Functions
#-------------------------------------------------------------------------------
init_background_mode() {
if [[ "$BACKGROUND_MODE" == "yes" ]]; then
LOG_FILE="$(dirname "$0")/bridge-setup-$(date +%Y%m%d-%H%M%S).log"
exec > >(tee -a "$LOG_FILE")
exec 2>&1
log_info "Running in background mode, log file: $LOG_FILE"
fi
}
write_error_exit() {
local exit_code=$1
local error_msg=$2
if [[ -n "$LOG_FILE" ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [FATAL] Script failed with exit code $exit_code" >> "$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [FATAL] Error: $error_msg" >> "$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [FATAL] Failed at: ${BASH_SOURCE[1]}:${BASH_LINENO[0]}" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
echo "=== Last 20 lines of NetworkManager log ===" >> "$LOG_FILE"
journalctl -u NetworkManager -n 20 --no-pager 2>/dev/null >> "$LOG_FILE" || true
echo "" >> "$LOG_FILE"
echo "=== Current network status ===" >> "$LOG_FILE"
ip addr >> "$LOG_FILE" 2>&1
echo "" >> "$LOG_FILE"
echo "=== NetworkManager connections ===" >> "$LOG_FILE"
nmcli connection show >> "$LOG_FILE" 2>&1
fi
exit $exit_code
}
#-------------------------------------------------------------------------------
# Check Root Privileges
#-------------------------------------------------------------------------------
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "This script requires root privileges"
log_error "Please run: sudo $0"
exit 1
fi
}
#-------------------------------------------------------------------------------
# Check Physical Interface Exists
#-------------------------------------------------------------------------------
check_physical_iface() {
log_info "Checking physical interface: $PHYSICAL_IFACE"
if ! ip link show "$PHYSICAL_IFACE" &>/dev/null; then
log_error "Physical interface $PHYSICAL_IFACE does not exist!"
log_error "Available interfaces:"
ip link show | grep -E '^[0-9]+:' | awk -F': ' '{print " - " $2}'
exit 1
fi
log_success "Physical interface $PHYSICAL_IFACE exists"
}
#-------------------------------------------------------------------------------
# Validate Configuration Parameters
#-------------------------------------------------------------------------------
validate_params() {
log_info "Validating configuration parameters..."
if ! echo "$BRIDGE_IP" | grep -qE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$'; then
log_error "Invalid BRIDGE_IP format! Must be CIDR (e.g., 192.168.2.99/24)"
exit 1
fi
BRIDGE_STP=$(echo "$BRIDGE_STP" | tr '[:upper:]' '[:lower:]')
if [[ "$BRIDGE_STP" != "yes" && "$BRIDGE_STP" != "no" ]]; then
log_error "Invalid BRIDGE_STP value! Must be 'yes' or 'no'"
exit 1
fi
if ! echo "$BRIDGE_FORWARD_DELAY" | grep -qE '^[0-9]+$'; then
log_error "Invalid BRIDGE_FORWARD_DELAY value! Must be a number"
exit 1
fi
log_success "Configuration parameters validation passed"
}
#-------------------------------------------------------------------------------
# Check NetworkManager Service
#-------------------------------------------------------------------------------
check_nm() {
if ! systemctl is-active --quiet NetworkManager; then
log_error "NetworkManager service is not running"
log_error "Please start: systemctl start NetworkManager"
exit 1
fi
log_success "NetworkManager service is running"
}
#-------------------------------------------------------------------------------
# Check nmcli Tool
#-------------------------------------------------------------------------------
check_nmcli() {
if ! command -v nmcli &> /dev/null; then
log_error "nmcli command not found, please install network-manager"
exit 1
fi
log_success "nmcli tool is available"
}
#-------------------------------------------------------------------------------
# Disable Competing Services
#-------------------------------------------------------------------------------
disable_competing_services() {
log_info "Disabling competing network services..."
if systemctl is-active --quiet systemd-networkd 2>/dev/null; then
log_warn "systemd-networkd is running. Disabling it..."
if ! systemctl stop systemd-networkd 2>/dev/null ||
! systemctl disable systemd-networkd 2>/dev/null ||
! systemctl mask systemd-networkd 2>/dev/null; then
log_error "Failed to disable systemd-networkd"
exit 1
fi
log_success "systemd-networkd disabled"
else
log_info "systemd-networkd is not running"
fi
if [[ -f /etc/network/interfaces ]]; then
log_info "Checking /etc/network/interfaces for conflicts..."
cp /etc/network/interfaces /etc/network/interfaces.bak.$(date +%s) 2>/dev/null
grep -v "^auto $PHYSICAL_IFACE" /etc/network/interfaces 2>/dev/null | \
grep -v "^iface $PHYSICAL_IFACE" | \
grep -v "^auto $BRIDGE_NAME" | \
grep -v "^iface $BRIDGE_NAME" > /etc/network/interfaces.tmp 2>/dev/null
if ! diff -q /etc/network/interfaces /etc/network/interfaces.tmp &>/dev/null; then
mv /etc/network/interfaces.tmp /etc/network/interfaces
log_warn "Cleaned /etc/network/interfaces (backup saved)"
else
rm -f /etc/network/interfaces.tmp 2>/dev/null
log_info "/etc/network/interfaces is clean"
fi
fi
log_success "Competing services disabled/cleaned"
}
#-------------------------------------------------------------------------------
# Detect and Remove Conflicting Connections
#-------------------------------------------------------------------------------
cleanup_conflicts() {
log_info "Checking and cleaning up conflicting network connections..."
local all_conns=""
while read conn; do
if nmcli connection show "$conn" 2>/dev/null | grep -q "interface-name: $PHYSICAL_IFACE"; then
all_conns="$all_conns $conn"
fi
done < <(nmcli -g NAME connection show 2>/dev/null)
for conn in $all_conns; do
if [[ "$conn" != "$SLAVE_CONN_NAME" ]]; then
log_warn "Found conflicting connection: $conn (manages $PHYSICAL_IFACE)"
log_info "Deleting conflicting connection..."
if ! nmcli connection delete "$conn" &>/dev/null; then
log_error "Failed to delete conflicting connection: $conn"
return 1
fi
log_success "Deleted conflicting connection: $conn"
fi
done
if nmcli connection show 2>/dev/null | grep -qE "^$BRIDGE_NAME"; then
log_warn "Found existing bridge connection: $BRIDGE_NAME"
log_info "Deleting old bridge connection..."
if ! nmcli connection delete "$BRIDGE_NAME" &>/dev/null; then
log_error "Failed to delete old bridge connection"
return 1
fi
log_success "Deleted old bridge connection"
fi
if nmcli connection show 2>/dev/null | grep -q "^$SLAVE_CONN_NAME "; then
log_warn "Found existing slave connection: $SLAVE_CONN_NAME"
log_info "Deleting old slave connection..."
if ! nmcli connection delete "$SLAVE_CONN_NAME" &>/dev/null; then
log_error "Failed to delete old slave connection"
return 1
fi
log_success "Deleted old slave connection"
fi
return 0
}
#-------------------------------------------------------------------------------
# Create Bridge
#-------------------------------------------------------------------------------
create_bridge() {
log_info "Creating bridge: $BRIDGE_NAME"
if ! nmcli connection add type bridge ifname "$BRIDGE_NAME" con-name "$BRIDGE_NAME" \
ip4 "$BRIDGE_IP" gw4 "$BRIDGE_GATEWAY" \
ipv4.dns "$BRIDGE_DNS" \
bridge.stp "$BRIDGE_STP" \
bridge.forward-delay "$BRIDGE_FORWARD_DELAY" \
connection.autoconnect yes \
connection.autoconnect-priority 100 &>/dev/null; then
log_error "Failed to create bridge"
return 1
fi
log_success "Bridge created successfully"
return 0
}
#-------------------------------------------------------------------------------
# Create Slave Interface
#-------------------------------------------------------------------------------
create_slave() {
log_info "Creating slave interface: $SLAVE_CONN_NAME (binding $PHYSICAL_IFACE to $BRIDGE_NAME)"
if ! nmcli connection add \
type bridge-slave \
con-name "$SLAVE_CONN_NAME" \
ifname "$PHYSICAL_IFACE" \
master "$BRIDGE_NAME" \
connection.autoconnect yes \
connection.autoconnect-priority 200 &>/dev/null; then
log_error "Failed to create slave connection (detailed error below):"
nmcli connection add type bridge-slave con-name "$SLAVE_CONN_NAME" ifname "$PHYSICAL_IFACE" master "$BRIDGE_NAME"
return 1
fi
log_success "Slave connection created"
return 0
}
#-------------------------------------------------------------------------------
# Activate Connections
#-------------------------------------------------------------------------------
activate_connections() {
log_info "Activating network connections..."
ip link set "$PHYSICAL_IFACE" down 2>/dev/null
sleep 1
log_info "Activating bridge: $BRIDGE_NAME"
if ! nmcli connection up "$BRIDGE_NAME" &>/dev/null; then
log_error "Failed to activate bridge connection"
return 1
fi
sleep 2
log_info "Activating slave interface: $SLAVE_CONN_NAME"
if ! nmcli connection up "$SLAVE_CONN_NAME" &>/dev/null; then
log_error "Failed to activate slave connection"
return 1
fi
sleep 3
log_success "All connections activated successfully"
return 0
}
#-------------------------------------------------------------------------------
# Verify Configuration
#-------------------------------------------------------------------------------
verify_config() {
log_info "Verifying network configuration..."
local errors=0
if nmcli connection show 2>/dev/null | grep -q "^$BRIDGE_NAME "; then
log_success "✓ Bridge connection exists"
else
log_error "✗ Bridge connection does not exist"
((errors++))
fi
if nmcli connection show "$SLAVE_CONN_NAME" 2>/dev/null | grep -q "$PHYSICAL_IFACE"; then
log_success "✓ Slave connection exists and bound to device"
else
log_error "✗ Slave connection not properly bound"
((errors++))
fi
if ip link show "$BRIDGE_NAME" 2>/dev/null | grep -q "state UP"; then
log_success "✓ Bridge state is UP"
else
log_error "✗ Bridge state is not UP"
((errors++))
fi
if ip addr show "$BRIDGE_NAME" 2>/dev/null | grep -q "inet $BRIDGE_IP"; then
log_success "✓ Bridge IP address is correct"
else
log_error "✗ Bridge IP address is incorrect"
((errors++))
fi
if ! ip addr show "$PHYSICAL_IFACE" 2>/dev/null | grep -qE "inet [0-9.]+"; then
log_success "✓ Physical interface has no independent IP"
else
log_error "✗ Physical interface still has independent IP"
((errors++))
fi
if bridge link show 2>/dev/null | grep -q "$PHYSICAL_IFACE.*master $BRIDGE_NAME"; then
log_success "✓ Physical interface joined bridge"
else
log_error "✗ Physical interface not joined bridge"
((errors++))
fi
log_info "Testing network connectivity..."
if ping -c 2 -W 2 "$BRIDGE_GATEWAY" &>/dev/null; then
log_success "✓ Gateway connectivity normal"
else
log_warn "⚠ Gateway connectivity test failed (may be temporary)"
fi
echo ""
if [[ $errors -eq 0 ]]; then
log_success "========================================="
log_success "All verifications passed! Bridge configured successfully!"
log_success "========================================="
return 0
else
log_error "========================================="
log_error "Found $errors issues, please check configuration"
log_error "========================================="
return 1
fi
}
#-------------------------------------------------------------------------------
# Display Summary
#-------------------------------------------------------------------------------
show_summary() {
echo ""
log_info "========== Network Configuration Summary =========="
echo ""
echo "Bridge Name: $BRIDGE_NAME"
echo "Bridge IP: $BRIDGE_IP"
echo "Gateway: $BRIDGE_GATEWAY"
echo "DNS: $BRIDGE_DNS"
echo "Physical Interface: $PHYSICAL_IFACE"
echo "Slave Connection: $SLAVE_CONN_NAME"
echo ""
echo "Current Connection Status:"
nmcli connection show 2>/dev/null | grep -E "$BRIDGE_NAME|$SLAVE_CONN_NAME|$PHYSICAL_IFACE" || echo " No relevant connections found"
echo ""
echo "Bridge Interface Info:"
ip addr show "$BRIDGE_NAME" 2>/dev/null | head -6 || echo " No info available"
echo ""
echo "Physical Interface Info:"
ip addr show "$PHYSICAL_IFACE" 2>/dev/null | head -6 || echo " No info available"
echo ""
echo "Bridge Ports:"
bridge link show 2>/dev/null | grep "$PHYSICAL_IFACE" || echo " None"
echo ""
log_info "========================================="
}
#-------------------------------------------------------------------------------
# Reboot Guide
#-------------------------------------------------------------------------------
show_reboot_guide() {
echo ""
log_warn "========== IMPORTANT: Post-Reboot Verification =========="
echo ""
echo "After reboot, please verify:"
echo " 1. Run: ip addr show $BRIDGE_NAME → Should show IP: $BRIDGE_IP"
echo " 2. Run: ip addr show $PHYSICAL_IFACE → Should NOT show any IPv4 address"
echo " 3. Run: bridge link show → $PHYSICAL_IFACE should show master $BRIDGE_NAME"
echo " 4. Run: nmcli connection show → Both connections should be 'connected'"
echo ""
echo "If physical interface gets IP after reboot:"
echo " - Check: systemctl status systemd-networkd"
echo " - Check /etc/network/interfaces for static configs"
echo " - Re-run this script to reapply configuration"
echo ""
log_warn "========================================="
}
#-------------------------------------------------------------------------------
# Main Function
#-------------------------------------------------------------------------------
main() {
init_background_mode
echo ""
echo "========================================="
echo " NetworkManager Bridge Configuration Script"
echo "========================================="
echo ""
if [[ "$BACKGROUND_MODE" != "yes" ]]; then
log_info "Tip: Run with -b to execute in background"
log_info "Usage: sudo $0 -b"
echo ""
fi
check_root || write_error_exit 1 "Root check failed"
check_nm || write_error_exit 1 "NetworkManager check failed"
check_nmcli || write_error_exit 1 "nmcli check failed"
check_physical_iface || write_error_exit 1 "Physical interface check failed"
validate_params || write_error_exit 1 "Parameter validation failed"
disable_competing_services || write_error_exit 1 "Disable competing services failed"
if [[ "$BACKGROUND_MODE" != "yes" ]]; then
echo ""
log_warn "========================================="
log_warn "WARNING: This operation will interrupt network for 10-30 seconds"
log_warn "Ensure you have physical access (HDMI/Serial)"
log_warn "========================================="
echo ""
read -p "Continue? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Operation cancelled"
exit 0
fi
else
log_warn "Running in background mode - proceeding automatically"
fi
if ! cleanup_conflicts; then
log_error "Cleanup failed - exiting"
write_error_exit 1 "Cleanup conflicts failed"
fi
if ! create_bridge; then
log_error "Bridge creation failed - exiting"
write_error_exit 1 "Bridge creation failed"
fi
if ! create_slave; then
log_error "Slave interface creation failed - exiting"
write_error_exit 1 "Slave creation failed"
fi
if ! activate_connections; then
log_error "Connection activation failed - exiting"
write_error_exit 1 "Connection activation failed"
fi
sleep 5
verify_config
local verify_result=$?
show_summary
show_reboot_guide
echo ""
if [[ $verify_result -eq 0 ]]; then
log_success "========================================="
log_success "Bridge configuration completed!"
log_success "========================================="
[[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] Bridge setup completed successfully" >> "$LOG_FILE"
exit 0
else
log_error "========================================="
log_error "Configuration completed but verification failed"
log_error "Please check network configuration"
log_error "========================================="
write_error_exit 1 "Verification failed"
fi
}
#-------------------------------------------------------------------------------
# Parse Command Line Arguments
#-------------------------------------------------------------------------------
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-b|--background)
BACKGROUND_MODE="yes"
shift
;;
-h|--help)
echo "Usage: sudo $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -b, --background Run in background mode (no interaction required)"
echo " -h, --help Show this help message"
echo ""
echo "Background mode is recommended for SSH connections to prevent network interruption issues."
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use -h or --help for usage information"
exit 1
;;
esac
done
}
parse_args "$@"
main "$@"
enp1s0
create-bridge-enp1s0.sh
#!/bin/bash
#===============================================================================
# Script Name: create-bridge-enp1s0.sh
# Description: Create bridge configuration using NetworkManager
#===============================================================================
#-------------------------------------------------------------------------------
# Configuration Area - Modify according to your environment
#-------------------------------------------------------------------------------
BRIDGE_NAME="br-lan"
BRIDGE_IP="192.168.2.99/24"
BRIDGE_GATEWAY="192.168.2.1"
BRIDGE_DNS="192.168.2.1"
PHYSICAL_IFACE="enp1s0"
SLAVE_CONN_NAME="enp1s0-bridge-port"
# Bridge Advanced Options
BRIDGE_STP="no"
BRIDGE_FORWARD_DELAY="0"
# Background Execution Options
BACKGROUND_MODE="yes"
LOG_FILE=""
#-------------------------------------------------------------------------------
# Color Definitions
#-------------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
#-------------------------------------------------------------------------------
# Logging Functions
#-------------------------------------------------------------------------------
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $1" >> "$LOG_FILE"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] $1" >> "$LOG_FILE"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $1" >> "$LOG_FILE"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1" >> "$LOG_FILE"; }
#-------------------------------------------------------------------------------
# Background Mode Functions
#-------------------------------------------------------------------------------
init_background_mode() {
if [[ "$BACKGROUND_MODE" == "yes" ]]; then
LOG_FILE="$(dirname "$0")/bridge-setup-$(date +%Y%m%d-%H%M%S).log"
exec > >(tee -a "$LOG_FILE")
exec 2>&1
log_info "Running in background mode, log file: $LOG_FILE"
fi
}
write_error_exit() {
local exit_code=$1
local error_msg=$2
if [[ -n "$LOG_FILE" ]]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [FATAL] Script failed with exit code $exit_code" >> "$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [FATAL] Error: $error_msg" >> "$LOG_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] [FATAL] Failed at: ${BASH_SOURCE[1]}:${BASH_LINENO[0]}" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
echo "=== Last 20 lines of NetworkManager log ===" >> "$LOG_FILE"
journalctl -u NetworkManager -n 20 --no-pager 2>/dev/null >> "$LOG_FILE" || true
echo "" >> "$LOG_FILE"
echo "=== Current network status ===" >> "$LOG_FILE"
ip addr >> "$LOG_FILE" 2>&1
echo "" >> "$LOG_FILE"
echo "=== NetworkManager connections ===" >> "$LOG_FILE"
nmcli connection show >> "$LOG_FILE" 2>&1
fi
exit $exit_code
}
#-------------------------------------------------------------------------------
# Check Root Privileges
#-------------------------------------------------------------------------------
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "This script requires root privileges"
log_error "Please run: sudo $0"
exit 1
fi
}
#-------------------------------------------------------------------------------
# Check Physical Interface Exists
#-------------------------------------------------------------------------------
check_physical_iface() {
log_info "Checking physical interface: $PHYSICAL_IFACE"
if ! ip link show "$PHYSICAL_IFACE" &>/dev/null; then
log_error "Physical interface $PHYSICAL_IFACE does not exist!"
log_error "Available interfaces:"
ip link show | grep -E '^[0-9]+:' | awk -F': ' '{print " - " $2}'
exit 1
fi
log_success "Physical interface $PHYSICAL_IFACE exists"
}
#-------------------------------------------------------------------------------
# Validate Configuration Parameters
#-------------------------------------------------------------------------------
validate_params() {
log_info "Validating configuration parameters..."
if ! echo "$BRIDGE_IP" | grep -qE '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$'; then
log_error "Invalid BRIDGE_IP format! Must be CIDR (e.g., 192.168.2.99/24)"
exit 1
fi
BRIDGE_STP=$(echo "$BRIDGE_STP" | tr '[:upper:]' '[:lower:]')
if [[ "$BRIDGE_STP" != "yes" && "$BRIDGE_STP" != "no" ]]; then
log_error "Invalid BRIDGE_STP value! Must be 'yes' or 'no'"
exit 1
fi
if ! echo "$BRIDGE_FORWARD_DELAY" | grep -qE '^[0-9]+$'; then
log_error "Invalid BRIDGE_FORWARD_DELAY value! Must be a number"
exit 1
fi
log_success "Configuration parameters validation passed"
}
#-------------------------------------------------------------------------------
# Check NetworkManager Service
#-------------------------------------------------------------------------------
check_nm() {
if ! systemctl is-active --quiet NetworkManager; then
log_error "NetworkManager service is not running"
log_error "Please start: systemctl start NetworkManager"
exit 1
fi
log_success "NetworkManager service is running"
}
#-------------------------------------------------------------------------------
# Check nmcli Tool
#-------------------------------------------------------------------------------
check_nmcli() {
if ! command -v nmcli &> /dev/null; then
log_error "nmcli command not found, please install network-manager"
exit 1
fi
log_success "nmcli tool is available"
}
#-------------------------------------------------------------------------------
# Disable Competing Services
#-------------------------------------------------------------------------------
disable_competing_services() {
log_info "Disabling competing network services..."
if systemctl is-active --quiet systemd-networkd 2>/dev/null; then
log_warn "systemd-networkd is running. Disabling it..."
if ! systemctl stop systemd-networkd 2>/dev/null ||
! systemctl disable systemd-networkd 2>/dev/null ||
! systemctl mask systemd-networkd 2>/dev/null; then
log_error "Failed to disable systemd-networkd"
exit 1
fi
log_success "systemd-networkd disabled"
else
log_info "systemd-networkd is not running"
fi
if [[ -f /etc/network/interfaces ]]; then
log_info "Checking /etc/network/interfaces for conflicts..."
cp /etc/network/interfaces /etc/network/interfaces.bak.$(date +%s) 2>/dev/null
grep -v "^auto $PHYSICAL_IFACE" /etc/network/interfaces 2>/dev/null | \
grep -v "^iface $PHYSICAL_IFACE" | \
grep -v "^auto $BRIDGE_NAME" | \
grep -v "^iface $BRIDGE_NAME" > /etc/network/interfaces.tmp 2>/dev/null
if ! diff -q /etc/network/interfaces /etc/network/interfaces.tmp &>/dev/null; then
mv /etc/network/interfaces.tmp /etc/network/interfaces
log_warn "Cleaned /etc/network/interfaces (backup saved)"
else
rm -f /etc/network/interfaces.tmp 2>/dev/null
log_info "/etc/network/interfaces is clean"
fi
fi
log_success "Competing services disabled/cleaned"
}
#-------------------------------------------------------------------------------
# Detect and Remove Conflicting Connections
#-------------------------------------------------------------------------------
cleanup_conflicts() {
log_info "Checking and cleaning up conflicting network connections..."
local all_conns=""
while read conn; do
if nmcli connection show "$conn" 2>/dev/null | grep -q "interface-name: $PHYSICAL_IFACE"; then
all_conns="$all_conns $conn"
fi
done < <(nmcli -g NAME connection show 2>/dev/null)
for conn in $all_conns; do
if [[ "$conn" != "$SLAVE_CONN_NAME" ]]; then
log_warn "Found conflicting connection: $conn (manages $PHYSICAL_IFACE)"
log_info "Deleting conflicting connection..."
if ! nmcli connection delete "$conn" &>/dev/null; then
log_error "Failed to delete conflicting connection: $conn"
return 1
fi
log_success "Deleted conflicting connection: $conn"
fi
done
if nmcli connection show 2>/dev/null | grep -qE "^$BRIDGE_NAME"; then
log_warn "Found existing bridge connection: $BRIDGE_NAME"
log_info "Deleting old bridge connection..."
if ! nmcli connection delete "$BRIDGE_NAME" &>/dev/null; then
log_error "Failed to delete old bridge connection"
return 1
fi
log_success "Deleted old bridge connection"
fi
if nmcli connection show 2>/dev/null | grep -q "^$SLAVE_CONN_NAME "; then
log_warn "Found existing slave connection: $SLAVE_CONN_NAME"
log_info "Deleting old slave connection..."
if ! nmcli connection delete "$SLAVE_CONN_NAME" &>/dev/null; then
log_error "Failed to delete old slave connection"
return 1
fi
log_success "Deleted old slave connection"
fi
return 0
}
#-------------------------------------------------------------------------------
# Create Bridge
#-------------------------------------------------------------------------------
create_bridge() {
log_info "Creating bridge: $BRIDGE_NAME"
if ! nmcli connection add type bridge ifname "$BRIDGE_NAME" con-name "$BRIDGE_NAME" \
ip4 "$BRIDGE_IP" gw4 "$BRIDGE_GATEWAY" \
ipv4.dns "$BRIDGE_DNS" \
bridge.stp "$BRIDGE_STP" \
bridge.forward-delay "$BRIDGE_FORWARD_DELAY" \
connection.autoconnect yes \
connection.autoconnect-priority 100 &>/dev/null; then
log_error "Failed to create bridge"
return 1
fi
log_success "Bridge created successfully"
return 0
}
#-------------------------------------------------------------------------------
# Create Slave Interface
#-------------------------------------------------------------------------------
create_slave() {
log_info "Creating slave interface: $SLAVE_CONN_NAME (binding $PHYSICAL_IFACE to $BRIDGE_NAME)"
if ! nmcli connection add \
type bridge-slave \
con-name "$SLAVE_CONN_NAME" \
ifname "$PHYSICAL_IFACE" \
master "$BRIDGE_NAME" \
connection.autoconnect yes \
connection.autoconnect-priority 200 &>/dev/null; then
log_error "Failed to create slave connection (detailed error below):"
nmcli connection add type bridge-slave con-name "$SLAVE_CONN_NAME" ifname "$PHYSICAL_IFACE" master "$BRIDGE_NAME"
return 1
fi
log_success "Slave connection created"
return 0
}
#-------------------------------------------------------------------------------
# Activate Connections
#-------------------------------------------------------------------------------
activate_connections() {
log_info "Activating network connections..."
ip link set "$PHYSICAL_IFACE" down 2>/dev/null
sleep 1
log_info "Activating bridge: $BRIDGE_NAME"
if ! nmcli connection up "$BRIDGE_NAME" &>/dev/null; then
log_error "Failed to activate bridge connection"
return 1
fi
sleep 2
log_info "Activating slave interface: $SLAVE_CONN_NAME"
if ! nmcli connection up "$SLAVE_CONN_NAME" &>/dev/null; then
log_error "Failed to activate slave connection"
return 1
fi
sleep 3
log_success "All connections activated successfully"
return 0
}
#-------------------------------------------------------------------------------
# Verify Configuration
#-------------------------------------------------------------------------------
verify_config() {
log_info "Verifying network configuration..."
local errors=0
if nmcli connection show 2>/dev/null | grep -q "^$BRIDGE_NAME "; then
log_success "✓ Bridge connection exists"
else
log_error "✗ Bridge connection does not exist"
((errors++))
fi
if nmcli connection show "$SLAVE_CONN_NAME" 2>/dev/null | grep -q "$PHYSICAL_IFACE"; then
log_success "✓ Slave connection exists and bound to device"
else
log_error "✗ Slave connection not properly bound"
((errors++))
fi
if ip link show "$BRIDGE_NAME" 2>/dev/null | grep -q "state UP"; then
log_success "✓ Bridge state is UP"
else
log_error "✗ Bridge state is not UP"
((errors++))
fi
if ip addr show "$BRIDGE_NAME" 2>/dev/null | grep -q "inet $BRIDGE_IP"; then
log_success "✓ Bridge IP address is correct"
else
log_error "✗ Bridge IP address is incorrect"
((errors++))
fi
if ! ip addr show "$PHYSICAL_IFACE" 2>/dev/null | grep -qE "inet [0-9.]+"; then
log_success "✓ Physical interface has no independent IP"
else
log_error "✗ Physical interface still has independent IP"
((errors++))
fi
if bridge link show 2>/dev/null | grep -q "$PHYSICAL_IFACE.*master $BRIDGE_NAME"; then
log_success "✓ Physical interface joined bridge"
else
log_error "✗ Physical interface not joined bridge"
((errors++))
fi
log_info "Testing network connectivity..."
if ping -c 2 -W 2 "$BRIDGE_GATEWAY" &>/dev/null; then
log_success "✓ Gateway connectivity normal"
else
log_warn "⚠ Gateway connectivity test failed (may be temporary)"
fi
echo ""
if [[ $errors -eq 0 ]]; then
log_success "========================================="
log_success "All verifications passed! Bridge configured successfully!"
log_success "========================================="
return 0
else
log_error "========================================="
log_error "Found $errors issues, please check configuration"
log_error "========================================="
return 1
fi
}
#-------------------------------------------------------------------------------
# Display Summary
#-------------------------------------------------------------------------------
show_summary() {
echo ""
log_info "========== Network Configuration Summary =========="
echo ""
echo "Bridge Name: $BRIDGE_NAME"
echo "Bridge IP: $BRIDGE_IP"
echo "Gateway: $BRIDGE_GATEWAY"
echo "DNS: $BRIDGE_DNS"
echo "Physical Interface: $PHYSICAL_IFACE"
echo "Slave Connection: $SLAVE_CONN_NAME"
echo ""
echo "Current Connection Status:"
nmcli connection show 2>/dev/null | grep -E "$BRIDGE_NAME|$SLAVE_CONN_NAME|$PHYSICAL_IFACE" || echo " No relevant connections found"
echo ""
echo "Bridge Interface Info:"
ip addr show "$BRIDGE_NAME" 2>/dev/null | head -6 || echo " No info available"
echo ""
echo "Physical Interface Info:"
ip addr show "$PHYSICAL_IFACE" 2>/dev/null | head -6 || echo " No info available"
echo ""
echo "Bridge Ports:"
bridge link show 2>/dev/null | grep "$PHYSICAL_IFACE" || echo " None"
echo ""
log_info "========================================="
}
#-------------------------------------------------------------------------------
# Reboot Guide
#-------------------------------------------------------------------------------
show_reboot_guide() {
echo ""
log_warn "========== IMPORTANT: Post-Reboot Verification =========="
echo ""
echo "After reboot, please verify:"
echo " 1. Run: ip addr show $BRIDGE_NAME → Should show IP: $BRIDGE_IP"
echo " 2. Run: ip addr show $PHYSICAL_IFACE → Should NOT show any IPv4 address"
echo " 3. Run: bridge link show → $PHYSICAL_IFACE should show master $BRIDGE_NAME"
echo " 4. Run: nmcli connection show → Both connections should be 'connected'"
echo ""
echo "If physical interface gets IP after reboot:"
echo " - Check: systemctl status systemd-networkd"
echo " - Check /etc/network/interfaces for static configs"
echo " - Re-run this script to reapply configuration"
echo ""
log_warn "========================================="
}
#-------------------------------------------------------------------------------
# Main Function
#-------------------------------------------------------------------------------
main() {
init_background_mode
echo ""
echo "========================================="
echo " NetworkManager Bridge Configuration Script"
echo "========================================="
echo ""
if [[ "$BACKGROUND_MODE" != "yes" ]]; then
log_info "Tip: Run with -b to execute in background"
log_info "Usage: sudo $0 -b"
echo ""
fi
check_root || write_error_exit 1 "Root check failed"
check_nm || write_error_exit 1 "NetworkManager check failed"
check_nmcli || write_error_exit 1 "nmcli check failed"
check_physical_iface || write_error_exit 1 "Physical interface check failed"
validate_params || write_error_exit 1 "Parameter validation failed"
disable_competing_services || write_error_exit 1 "Disable competing services failed"
if [[ "$BACKGROUND_MODE" != "yes" ]]; then
echo ""
log_warn "========================================="
log_warn "WARNING: This operation will interrupt network for 10-30 seconds"
log_warn "Ensure you have physical access (HDMI/Serial)"
log_warn "========================================="
echo ""
read -p "Continue? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Operation cancelled"
exit 0
fi
else
log_warn "Running in background mode - proceeding automatically"
fi
if ! cleanup_conflicts; then
log_error "Cleanup failed - exiting"
write_error_exit 1 "Cleanup conflicts failed"
fi
if ! create_bridge; then
log_error "Bridge creation failed - exiting"
write_error_exit 1 "Bridge creation failed"
fi
if ! create_slave; then
log_error "Slave interface creation failed - exiting"
write_error_exit 1 "Slave creation failed"
fi
if ! activate_connections; then
log_error "Connection activation failed - exiting"
write_error_exit 1 "Connection activation failed"
fi
sleep 5
verify_config
local verify_result=$?
show_summary
show_reboot_guide
echo ""
if [[ $verify_result -eq 0 ]]; then
log_success "========================================="
log_success "Bridge configuration completed!"
log_success "========================================="
[[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] Bridge setup completed successfully" >> "$LOG_FILE"
exit 0
else
log_error "========================================="
log_error "Configuration completed but verification failed"
log_error "Please check network configuration"
log_error "========================================="
write_error_exit 1 "Verification failed"
fi
}
#-------------------------------------------------------------------------------
# Parse Command Line Arguments
#-------------------------------------------------------------------------------
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-b|--background)
BACKGROUND_MODE="yes"
shift
;;
-h|--help)
echo "Usage: sudo $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -b, --background Run in background mode (no interaction required)"
echo " -h, --help Show this help message"
echo ""
echo "Background mode is recommended for SSH connections to prevent network interruption issues."
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use -h or --help for usage information"
exit 1
;;
esac
done
}
parse_args "$@"
main "$@"
eth0 恢复
rollback-network-eth0.sh
#!/bin/bash
#===============================================================================
# Script Name: rollback-network-eth0.sh
# Description: Rollback bridge network configuration to restore original state
#===============================================================================
BRIDGE_NAME="br-lan"
PHYSICAL_IFACE="eth0"
SLAVE_CONN_NAME="eth0-bridge-port"
#-------------------------------------------------------------------------------
# Physical Interface Configuration - Configure before rolling back
#-------------------------------------------------------------------------------
# Set to "dhcp" for automatic IP, or "static" for manual configuration
PHYSICAL_IFACE_METHOD="static"
# Static IP configuration (only used when PHYSICAL_IFACE_METHOD="static")
PHYSICAL_IFACE_IP="192.168.2.99/24"
PHYSICAL_IFACE_GATEWAY="192.168.2.1"
PHYSICAL_IFACE_DNS="192.168.2.1"
# Background Execution Options
BACKGROUND_MODE="yes"
LOG_FILE=""
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $1" >> "$LOG_FILE"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] $1" >> "$LOG_FILE"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $1" >> "$LOG_FILE"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1" >> "$LOG_FILE"; }
init_background_mode() {
if [[ "$BACKGROUND_MODE" == "yes" ]]; then
LOG_FILE="$(dirname "$0")/rollback-$(date +%Y%m%d-%H%M%S).log"
exec > >(tee -a "$LOG_FILE")
exec 2>&1
log_info "Running in background mode, log file: $LOG_FILE"
fi
}
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "This script requires root privileges"
log_error "Please run: sudo $0"
exit 1
fi
}
rollback_bridge() {
log_info "Rolling back bridge configuration..."
log_info "Deleting bridge connection: $BRIDGE_NAME"
if nmcli connection show "$BRIDGE_NAME" &>/dev/null; then
nmcli connection down "$BRIDGE_NAME" &>/dev/null || true
nmcli connection delete "$BRIDGE_NAME" &>/dev/null && \
log_success "Bridge connection deleted" || \
log_warn "Failed to delete bridge connection"
else
log_info "Bridge connection does not exist"
fi
log_info "Deleting slave connection: $SLAVE_CONN_NAME"
if nmcli connection show "$SLAVE_CONN_NAME" &>/dev/null; then
nmcli connection down "$SLAVE_CONN_NAME" &>/dev/null || true
nmcli connection delete "$SLAVE_CONN_NAME" &>/dev/null && \
log_success "Slave connection deleted" || \
log_warn "Failed to delete slave connection"
else
log_info "Slave connection does not exist"
fi
}
cleanup_bridge_interface() {
log_info "Cleaning up bridge interface..."
if ip link show "$BRIDGE_NAME" &>/dev/null; then
ip link set "$BRIDGE_NAME" down &>/dev/null || true
ip link delete "$BRIDGE_NAME" &>/dev/null && \
log_success "Bridge interface deleted" || \
log_warn "Failed to delete bridge interface"
else
log_info "Bridge interface does not exist"
fi
}
restore_physical_interface() {
log_info "Restoring physical interface: $PHYSICAL_IFACE"
ip link set "$PHYSICAL_IFACE" down &>/dev/null || true
sleep 1
log_info "Cleaning up existing connections for $PHYSICAL_IFACE..."
local existing_conns=$(nmcli connection show 2>/dev/null | grep -E "ethernet.*$PHYSICAL_IFACE" | awk '{print $1}')
for conn in $existing_conns; do
log_info "Deleting existing connection: $conn"
nmcli connection down "$conn" &>/dev/null || true
nmcli connection delete "$conn" &>/dev/null && \
log_success "Deleted: $conn" || \
log_warn "Failed to delete: $conn"
done
log_info "Creating new connection for physical interface: $PHYSICAL_IFACE"
local conn_name="Wired connection 1"
nmcli connection add \
type ethernet \
con-name "$conn_name" \
ifname "$PHYSICAL_IFACE" \
connection.autoconnect yes &>/dev/null && \
log_success "Connection created: $conn_name" || \
log_warn "Failed to create connection"
if [[ "$PHYSICAL_IFACE_METHOD" == "static" ]]; then
log_info "Configuring static IP: $PHYSICAL_IFACE_IP"
nmcli connection modify "$conn_name" \
ipv4.method manual \
ipv4.address "$PHYSICAL_IFACE_IP" \
ipv4.gateway "$PHYSICAL_IFACE_GATEWAY" \
ipv4.dns "$PHYSICAL_IFACE_DNS" &>/dev/null && \
log_success "Static IP configured" || \
log_warn "Failed to configure static IP"
else
log_info "Configuring DHCP"
nmcli connection modify "$conn_name" \
ipv4.method auto &>/dev/null && \
log_success "DHCP configured" || \
log_warn "Failed to configure DHCP"
fi
nmcli connection up "$conn_name" &>/dev/null && \
log_success "Physical interface activated" || \
log_warn "Failed to activate physical interface"
ip link set "$PHYSICAL_IFACE" up &>/dev/null || true
sleep 2
}
verify_restore() {
log_info "Verifying restoration..."
local has_bridge=false
if ip link show "$BRIDGE_NAME" &>/dev/null; then
log_warn "Bridge interface still exists: $BRIDGE_NAME"
has_bridge=true
else
log_success "Bridge interface removed"
fi
local has_slave=false
if nmcli connection show 2>/dev/null | grep -q "^$SLAVE_CONN_NAME"; then
log_warn "Slave connection still exists: $SLAVE_CONN_NAME"
has_slave=true
else
log_success "Slave connection removed"
fi
if ip link show "$PHYSICAL_IFACE" &>/dev/null; then
log_success "Physical interface exists: $PHYSICAL_IFACE"
if ip link show "$PHYSICAL_IFACE" | grep -q "state UP"; then
log_success "Physical interface is UP"
fi
else
log_error "Physical interface not found: $PHYSICAL_IFACE"
fi
if [[ "$has_bridge" == "false" && "$has_slave" == "false" ]]; then
return 0
else
return 1
fi
}
show_status() {
echo ""
echo "========================================="
echo " Network Configuration Status"
echo "========================================="
echo ""
echo "Bridge: $BRIDGE_NAME"
echo "Physical: $PHYSICAL_IFACE"
echo "Slave Conn: $SLAVE_CONN_NAME"
echo ""
echo "=== Active NetworkManager Connections ==="
nmcli connection show 2>/dev/null | grep -E "^[^-]" | head -10 || echo " No connections"
echo ""
echo "=== Physical Interface Status ==="
ip addr show "$PHYSICAL_IFACE" 2>/dev/null | head -6 || echo " Not available"
echo ""
echo "=== Bridge Interface Status ==="
ip addr show "$BRIDGE_NAME" 2>/dev/null | head -6 || echo " Not available"
}
main() {
init_background_mode
check_root
echo ""
echo "========================================="
echo " Network Configuration Rollback"
echo "========================================="
echo ""
if [[ "$BACKGROUND_MODE" != "yes" ]]; then
log_info "Tip: Run with -b to execute in background"
log_info "Usage: sudo $0 -b"
echo ""
fi
log_warn "This will remove bridge configuration and restore original network"
log_warn "Network will be temporarily interrupted"
if [[ "$BACKGROUND_MODE" != "yes" ]]; then
echo ""
read -p "Continue? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Operation cancelled"
exit 0
fi
else
log_warn "Running in background mode - proceeding automatically"
fi
rollback_bridge
cleanup_bridge_interface
restore_physical_interface
show_status
echo ""
if verify_restore; then
log_success "========================================="
log_success "Rollback completed successfully!"
log_success "Physical interface should be restored"
log_success "========================================="
exit 0
else
log_error "========================================="
log_error "Rollback completed with warnings"
log_error "Please check network configuration manually"
log_error "========================================="
exit 1
fi
}
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-b|--background)
BACKGROUND_MODE="yes"
shift
;;
-h|--help)
echo "Usage: sudo $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -b, --background Run in background mode (no interaction required)"
echo " -h, --help Show this help message"
echo ""
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use -h or --help for usage information"
exit 1
;;
esac
done
}
parse_args "$@"
main "$@"
enp1s0 恢复
rollback-network-enp1s0.sh
#!/bin/bash
#===============================================================================
# Script Name: rollback-network-enp1s0.sh
# Description: Rollback bridge network configuration to restore original state
#===============================================================================
BRIDGE_NAME="br-lan"
PHYSICAL_IFACE="enp1s0"
SLAVE_CONN_NAME="enp1s0-bridge-port"
#-------------------------------------------------------------------------------
# Physical Interface Configuration - Configure before rolling back
#-------------------------------------------------------------------------------
# Set to "dhcp" for automatic IP, or "static" for manual configuration
PHYSICAL_IFACE_METHOD="static"
# Static IP configuration (only used when PHYSICAL_IFACE_METHOD="static")
PHYSICAL_IFACE_IP="192.168.2.99/24"
PHYSICAL_IFACE_GATEWAY="192.168.2.1"
PHYSICAL_IFACE_DNS="192.168.2.1"
# Background Execution Options
BACKGROUND_MODE="yes"
LOG_FILE=""
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [INFO] $1" >> "$LOG_FILE"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [SUCCESS] $1" >> "$LOG_FILE"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [WARN] $1" >> "$LOG_FILE"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; [[ -n "$LOG_FILE" ]] && echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] $1" >> "$LOG_FILE"; }
init_background_mode() {
if [[ "$BACKGROUND_MODE" == "yes" ]]; then
LOG_FILE="$(dirname "$0")/rollback-$(date +%Y%m%d-%H%M%S).log"
exec > >(tee -a "$LOG_FILE")
exec 2>&1
log_info "Running in background mode, log file: $LOG_FILE"
fi
}
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "This script requires root privileges"
log_error "Please run: sudo $0"
exit 1
fi
}
rollback_bridge() {
log_info "Rolling back bridge configuration..."
log_info "Deleting bridge connection: $BRIDGE_NAME"
if nmcli connection show "$BRIDGE_NAME" &>/dev/null; then
nmcli connection down "$BRIDGE_NAME" &>/dev/null || true
nmcli connection delete "$BRIDGE_NAME" &>/dev/null && \
log_success "Bridge connection deleted" || \
log_warn "Failed to delete bridge connection"
else
log_info "Bridge connection does not exist"
fi
log_info "Deleting slave connection: $SLAVE_CONN_NAME"
if nmcli connection show "$SLAVE_CONN_NAME" &>/dev/null; then
nmcli connection down "$SLAVE_CONN_NAME" &>/dev/null || true
nmcli connection delete "$SLAVE_CONN_NAME" &>/dev/null && \
log_success "Slave connection deleted" || \
log_warn "Failed to delete slave connection"
else
log_info "Slave connection does not exist"
fi
}
cleanup_bridge_interface() {
log_info "Cleaning up bridge interface..."
if ip link show "$BRIDGE_NAME" &>/dev/null; then
ip link set "$BRIDGE_NAME" down &>/dev/null || true
ip link delete "$BRIDGE_NAME" &>/dev/null && \
log_success "Bridge interface deleted" || \
log_warn "Failed to delete bridge interface"
else
log_info "Bridge interface does not exist"
fi
}
restore_physical_interface() {
log_info "Restoring physical interface: $PHYSICAL_IFACE"
ip link set "$PHYSICAL_IFACE" down &>/dev/null || true
sleep 1
log_info "Cleaning up existing connections for $PHYSICAL_IFACE..."
local existing_conns=$(nmcli connection show 2>/dev/null | grep -E "ethernet.*$PHYSICAL_IFACE" | awk '{print $1}')
for conn in $existing_conns; do
log_info "Deleting existing connection: $conn"
nmcli connection down "$conn" &>/dev/null || true
nmcli connection delete "$conn" &>/dev/null && \
log_success "Deleted: $conn" || \
log_warn "Failed to delete: $conn"
done
log_info "Creating new connection for physical interface: $PHYSICAL_IFACE"
local conn_name="Wired connection 1"
nmcli connection add \
type ethernet \
con-name "$conn_name" \
ifname "$PHYSICAL_IFACE" \
connection.autoconnect yes &>/dev/null && \
log_success "Connection created: $conn_name" || \
log_warn "Failed to create connection"
if [[ "$PHYSICAL_IFACE_METHOD" == "static" ]]; then
log_info "Configuring static IP: $PHYSICAL_IFACE_IP"
nmcli connection modify "$conn_name" \
ipv4.method manual \
ipv4.address "$PHYSICAL_IFACE_IP" \
ipv4.gateway "$PHYSICAL_IFACE_GATEWAY" \
ipv4.dns "$PHYSICAL_IFACE_DNS" &>/dev/null && \
log_success "Static IP configured" || \
log_warn "Failed to configure static IP"
else
log_info "Configuring DHCP"
nmcli connection modify "$conn_name" \
ipv4.method auto &>/dev/null && \
log_success "DHCP configured" || \
log_warn "Failed to configure DHCP"
fi
nmcli connection up "$conn_name" &>/dev/null && \
log_success "Physical interface activated" || \
log_warn "Failed to activate physical interface"
ip link set "$PHYSICAL_IFACE" up &>/dev/null || true
sleep 2
}
verify_restore() {
log_info "Verifying restoration..."
local has_bridge=false
if ip link show "$BRIDGE_NAME" &>/dev/null; then
log_warn "Bridge interface still exists: $BRIDGE_NAME"
has_bridge=true
else
log_success "Bridge interface removed"
fi
local has_slave=false
if nmcli connection show 2>/dev/null | grep -q "^$SLAVE_CONN_NAME"; then
log_warn "Slave connection still exists: $SLAVE_CONN_NAME"
has_slave=true
else
log_success "Slave connection removed"
fi
if ip link show "$PHYSICAL_IFACE" &>/dev/null; then
log_success "Physical interface exists: $PHYSICAL_IFACE"
if ip link show "$PHYSICAL_IFACE" | grep -q "state UP"; then
log_success "Physical interface is UP"
fi
else
log_error "Physical interface not found: $PHYSICAL_IFACE"
fi
if [[ "$has_bridge" == "false" && "$has_slave" == "false" ]]; then
return 0
else
return 1
fi
}
show_status() {
echo ""
echo "========================================="
echo " Network Configuration Status"
echo "========================================="
echo ""
echo "Bridge: $BRIDGE_NAME"
echo "Physical: $PHYSICAL_IFACE"
echo "Slave Conn: $SLAVE_CONN_NAME"
echo ""
echo "=== Active NetworkManager Connections ==="
nmcli connection show 2>/dev/null | grep -E "^[^-]" | head -10 || echo " No connections"
echo ""
echo "=== Physical Interface Status ==="
ip addr show "$PHYSICAL_IFACE" 2>/dev/null | head -6 || echo " Not available"
echo ""
echo "=== Bridge Interface Status ==="
ip addr show "$BRIDGE_NAME" 2>/dev/null | head -6 || echo " Not available"
}
main() {
init_background_mode
check_root
echo ""
echo "========================================="
echo " Network Configuration Rollback"
echo "========================================="
echo ""
if [[ "$BACKGROUND_MODE" != "yes" ]]; then
log_info "Tip: Run with -b to execute in background"
log_info "Usage: sudo $0 -b"
echo ""
fi
log_warn "This will remove bridge configuration and restore original network"
log_warn "Network will be temporarily interrupted"
if [[ "$BACKGROUND_MODE" != "yes" ]]; then
echo ""
read -p "Continue? (y/N): " -n 1 -r
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
log_info "Operation cancelled"
exit 0
fi
else
log_warn "Running in background mode - proceeding automatically"
fi
rollback_bridge
cleanup_bridge_interface
restore_physical_interface
show_status
echo ""
if verify_restore; then
log_success "========================================="
log_success "Rollback completed successfully!"
log_success "Physical interface should be restored"
log_success "========================================="
exit 0
else
log_error "========================================="
log_error "Rollback completed with warnings"
log_error "Please check network configuration manually"
log_error "========================================="
exit 1
fi
}
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-b|--background)
BACKGROUND_MODE="yes"
shift
;;
-h|--help)
echo "Usage: sudo $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -b, --background Run in background mode (no interaction required)"
echo " -h, --help Show this help message"
echo ""
exit 0
;;
*)
echo "Unknown option: $1"
echo "Use -h or --help for usage information"
exit 1
;;
esac
done
}
parse_args "$@"
main "$@"