| # Create and setup a network bridge.
|
| nnet_bridge_up() {
|
| local bridge_iface="$1"
|
| local network_iface="$2"
|
| local aux_ifaces=( "${@:3}" )
|
| # CHECK if a bridge iface has been specified, otherwise use the default.
|
| if [[ -z "${bridge_iface}" ]]; then
|
| local bridge_iface="${DEFAULT_BRIDGE_IFACE}"
|
| print_info "Bridge iface not specified, using default: \`${bridge_iface}\`."
|
| fi
|
| # SET the bridge conf file full path.
|
| local bridge_conf_file="${BRIDGE_CONF_PATH}/${bridge_iface}"
|
| # CHECK for the presence of needed programs.
|
| if ! command_is_present ip; then
|
| print_err "nnet_bridge_up: Program \`ip\` not present."
|
| return 1
|
| fi
|
| if ! command_is_present grep; then
|
| print_err "nnet_bridge_up: Program \`grep\` not present."
|
| return 1
|
| fi
|
| if ! command_is_present tee; then
|
| print_err "Program \`tee\` not present."
|
| return 1
|
| fi
|
| if ! command_root_is_present systemctl; then
|
| print_err "nnet_bridge_up: Program \`systemctl\` not present."
|
| return 1
|
| fi
|
| # CHECK if we already have a bridge up.
|
| if nnet_iface_exists "${bridge_iface}"; then
|
| print_err "nnet_bridge_up: It seems a bridge interface \`${bridge_iface}\`" \
|
| "already exists."
|
| return 0
|
| fi
|
| # CHECK if the bridge packages are present.
|
| if ! package_is_present "${BRIDGE_PACKAGE}"; then
|
| if ! sudo apt-get update; then
|
| print_err "nnet_bridge_up: apt-get update: failed."
|
| return 1
|
| fi
|
| if ! sudo apt-get -y install "${BRIDGE_PACKAGE}"; then
|
| print_err "nnet_bridge_up: apt-get install ${BRIDGE_PACKAGE}: failed."
|
| return 1
|
| fi
|
| fi
|
| # CHECK if we have 'brctl' after installation of bridge packages.
|
| if ! command_root_is_present brctl; then
|
| print_err "nnet_bridge_up: Program \`brctl\` not present, despite" \
|
| "installation of package: \`${BRIDGE_PACKAGE}\`."
|
| return 1
|
| fi
|
| # CHECK if we did NOT get a manually specified network interface.
|
| if [[ -z "${network_iface}" ]]; then
|
| # GET the first network interface marked as 'UP'.
|
| local network_iface=$( ip -br link show up | awk '{if($2=="UP"){print $1;exit}}' )
|
| # CHECK for network interface.
|
| if [[ -z "${network_iface}" ]]; then
|
| print_err "nnet_bridge_up: Can't get a proper main network interface" \
|
| "which is UP."
|
| return 1
|
| else
|
| print_success "Got main network interface: \`${network_iface}\`."
|
| fi
|
| else
|
| print_info "Network interface \`${network_iface}\` manually specified."
|
| fi
|
| # GET the actual MAC address of the current main network interface.
|
| # We'll set this MAC address as the bridge MAC address: in this way, the
|
| # router will give to the bridge the machine's IP (if there is a static
|
| # routing configured into the router), since the bridge's ip address will
|
| # be the machine ip address.
|
| # REMEMBER: The bridge interface ip address, will be the host machine ip addr.
|
| SYSFS_MACADDR_FILE="/sys/class/net/${network_iface}/address"
|
| if [[ -f "${SYSFS_MACADDR_FILE}" ]]; then
|
| local network_iface_macaddr=$( cat "${SYSFS_MACADDR_FILE}" )
|
| if [[ -n "${network_iface_macaddr}" ]]; then
|
| print_success "Got main network iface \`${network_iface}\` MAC address:" \
|
| "\`${network_iface_macaddr}\`."
|
| else
|
| print_err "nnet_bridge_up: sysfs file \`${SYSFS_MACADDR_FILE}\` contains" \
|
| "empty string."
|
| return 1
|
| fi
|
| else
|
| print_err "nnet_bridge_up: sysfs file \`${SYSFS_MACADDR_FILE}\` doesn't" \
|
| "exist, unable to get main network iface \`${network_iface}\` MAC address."
|
| return 1
|
| fi
|
| # GET main network interface metric.
|
| local metric=$( ip route show dev "${network_iface}" | \
|
| grep -oP 'metric \K\d+' | uniq )
|
| if [[ -z "${metric}" ]]; then
|
| local metric="${BRIDGE_DEFAULT_METRIC}"
|
| print_warn "nnet_bridge_up: Unable to retrieve ${network_interface}" \
|
| "metric, using default: ${BRIDGE_DEFAULT_METRIC}."
|
| else
|
| print_info "Retrieved ${network_interface} metric: ${metric}."
|
| fi
|
| # FLUSH all ip addresses stored in the current main network interface.
|
| # Setting down eno1 should have already flushed all, but just to be sure that
|
| # eno1 won't have any ip addresses, let's do this again.
|
| if ! sudo ip addr flush dev "${network_iface}"; then
|
| print_err "nnet_bridge_up: ip addr flush dev ${network_iface}: failed."
|
| return 1
|
| fi
|
| # SET DOWN the main network interface: we need this because we have to reset
|
| # the classic eno1 interface, to be a bridge's port.
|
| if ! sudo ip link set "${network_iface}" down; then
|
| print_err "nnet_bridge_up: ip link set ${network_iface} down: failed."
|
| return 1
|
| fi
|
| # FLUSH + SET DOWN for all the aux interfaces too.
|
| for aux_iface in "${aux_ifaces[@]}"
|
| do
|
| if ! sudo ip addr flush dev "${aux_iface}"; then
|
| print_err "nnet_bridge_up: ip addr flush dev ${aux_iface}: failed."
|
| return 1
|
| fi
|
| if ! sudo ip link set "${aux_iface}" down; then
|
| print_err "nnet_bridge_up: ip link set ${aux_iface} down: failed."
|
| return 1
|
| fi
|
| done
|
| # CREATE the new bridge interface.
|
| if ! sudo brctl addbr "${bridge_iface}"; then
|
| print_err "nnet_bridge_up: brctl addbr ${bridge_iface}: failed."
|
| return 1
|
| fi
|
| # SET the current main network iface (e.g. eno1)'s MAC addr to the bridge
|
| # iface.
|
| if ! sudo ip link set "${bridge_iface}" address "${network_iface_macaddr}";
|
| then
|
| print_err "nnet_bridge_up: ip link set ${bridge_iface} address" \
|
| "${network_iface_macaddr}: failed."
|
| return 1
|
| fi
|
| # SET UP the main network interface.
|
| # NOTE: This time we set up eno1 not with `ifup` of the NetworkManager, but
|
| # with the normal `ip` program: with this we avoid NetworkManager to reset
|
| # eno1 to be the main network manager with its ip addresses; instead we want
|
| # it to be a bridge port.
|
| if ! sudo ip link set "${network_iface}" up; then
|
| print_err "nnet_bridge_up: ip link set "${network_iface}" up: failed."
|
| return 1
|
| fi
|
| # FLUSH all ip addresses stored in the current main network interface.
|
| # Setting down eno1 should have already flushed all, but just to be sure that
|
| # eno1 won't have any ip addresses, let's do this again.
|
| if ! sudo ip addr flush dev "${network_iface}"; then
|
| print_err "nnet_bridge_up: ip addr flush dev ${network_iface}: failed."
|
| return 1
|
| fi
|
| # ADD the current network iface (e.g. eno1) to the created bridge, as one
|
| # bridge's port.
|
| if ! sudo brctl addif "${bridge_iface}" "${network_iface}"; then
|
| print_err "nnet_bridge_up: brctl addif ${bridge_iface} ${network_iface}:" \
|
| "failed."
|
| return 1
|
| fi
|
| # SET UP + FLUSH + ADD to the bridge, all the aux interfaces too.
|
| for aux_iface in "${aux_ifaces[@]}"
|
| do
|
| if ! sudo ip link set "${aux_iface}" up; then
|
| print_err "nnet_bridge_up: ip link set ${aux_iface} up: failed."
|
| return 1
|
| fi
|
| if ! sudo ip addr flush dev "${aux_iface}"; then
|
| print_err "nnet_bridge_up: ip addr flush dev ${aux_iface}: failed."
|
| return 1
|
| fi
|
| if ! sudo brctl addif "${bridge_iface}" "${aux_iface}"; then
|
| print_err "nnet_bridge_up: brctl addif ${bridge_iface} ${aux_iface}:" \
|
| "failed."
|
| return 1
|
| fi
|
| done
|
| # SET UP the bridge interface.
|
| if ! sudo ip link set "${bridge_iface}" up; then
|
| print_err "nnet_bridge_up: ip link set ${bridge_iface} up: failed."
|
| return 1
|
| fi
|
| # SET bridge metric.
|
| if ! sudo ip route replace default dev "${bridge_iface}" metric "${metric}";
|
| then
|
| print_warn "nnet_bridge_up: Unable to set ${bridge_iface} metric" \
|
| "to '${metric}': ip route replace: failed."
|
| fi
|
| # SAVE the bridge configs to make changes persist reboots.
|
| #
|
| # Options:
|
| # bridge_stp off -> disable Spanning Tree Protocol
|
| # bridge_waitport 0 -> no delay before a port becomes available
|
| # bridge_fd 0 -> no forwarding delay
|
| #
|
| # NOTE: We trying to keep the same metric of the main network device the
|
| # bridge will "substitute": so, if there are other NICs or other network
|
| # interfaces with different metric (e.g. wifi interface), the priority of
|
| # the main network interface is preserved.
|
| if ! sudo tee "${bridge_conf_file}" >/dev/null <<- EOF
|
| auto ${bridge_iface}
|
| iface ${bridge_iface} inet dhcp
|
| bridge_ports ${network_iface} ${aux_ifaces[*]}
|
| hwaddress ether ${network_iface_macaddr}
|
| bridge_stp off
|
| bridge_waitport 0
|
| bridge_fd 0
|
| bridge_maxwait 0
|
| post-up ip route replace default dev ${bridge_iface} metric ${metric}
|
| EOF
|
| then
|
| print_err "nnet_bridge_up: Unable to edit network manager bridge conf" \
|
| "file: \`${bridge_conf_file}\`."
|
| return 1
|
| else
|
| print_success "SAVED NETWORK CONF: Saved bridge \`${bridge_iface}\`" \
|
| "configuration into conf file \`${bridge_conf_file}\`."
|
| fi
|
| # RESTART networking.
|
| if ! sudo systemctl restart NetworkManager; then
|
| print_err "nnet_bridge_up: Unable to restart NetworkManager service."
|
| return 1
|
| fi
|
| if ! sudo systemctl restart networking; then
|
| print_err "nnet_bridge_up: Unable to restart networking service."
|
| return 1
|
| fi
|
| # DONE!
|
| print_success "BRIDGE UP: ${bridge_iface}."
|
| return 0
|
| }
|