#!/bin/sh set -e # Copyright (C) 2012, 2020 Natanael Copa # Copyright (C) 2020 Ariadne Conill # Copyright (C) 2020 Maximilian Wilhelm # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above # copyright notice and this permission notice appear in all copies. # # This software is provided 'as is' and without any warranty, express or # implied. In no event shall the authors be liable for any damages arising # from the use of this software. all_ports_exist() { local i= for i in "$@"; do [ -d /sys/class/net/$i ] || return 1 done return 0 } wait_ports() { local timeout= waitports= [ -z "$IF_BRIDGE_WAITPORT" ] && return 0 set -- $IF_BRIDGE_WAITPORT timeout="$1" shift waitports="$@" [ -z "$waitports" ] && waitports="$PORTS" while ! all_ports_exist $waitports; do [ "$timeout" -eq 0 ] && return 0 timeout=$(($timeout - 1)) sleep 1 done } all_ports() { local i= for i in /sys/class/net/*/ifindex; do i=${i%/*} i=${i##*/} case "$i" in lo|$IFACE) continue;; *) echo $i;; esac done } add_ports() { local port= for port in $PORTS; do if [ -n "$IF_BRIDGE_HW" ]; then ip link set dev $port addr $IF_BRIDGE_HW fi ip link set dev $port master $IFACE && ip link set dev $port up done } del_ports() { local port= for port in $PORTS; do ip link set dev $port down ip link set dev $port nomaster done } set_bridge_opts_brctl() { [ -n "$IF_BRIDGE_AGEING" ] \ && brctl setageing $IFACE $IF_BRIDGE_AGEING [ -n "$IF_BRIDGE_BRIDGEPRIO" ] \ && brctl setbridgeprio $IFACE $IF_BRIDGE_BRIDGEPRIO [ -n "$IF_BRIDGE_FD" ] \ && brctl setfd $IFACE $IF_BRIDGE_FD [ -n "$IF_BRIDGE_HELLO" ] \ && brctl sethello $IFACE $IF_BRIDGE_HELLO [ -n "$IF_BRIDGE_MAXAGE" ] \ && brctl setmaxage $IFACE $IF_BRIDGE_MAXAGE [ -n "$IF_BRIDGE_PATHCOST" ] \ && brctl setpathcost $IFACE $IF_BRIDGE_PATHCOST [ -n "$IF_BRIDGE_PORTPRIO" ] \ && brctl setportprio $IFACE $IF_BRIDGE_PORTPRIO [ -n "$IF_BRIDGE_STP" ] \ && brctl stp $IFACE $IF_BRIDGE_STP } yesno() { case "$1" in yes|YES|true|TRUE|1) echo 1 ;; *) echo 0 ;; esac } set_bridge_opts_iproute2() { [ -n "$IF_BRIDGE_AGEING" ] \ && ip link set dev $IFACE type bridge ageing_time $IF_BRIDGE_AGEING [ -n "$IF_BRIDGE_BRIDGEPRIO" ] \ && ip link set dev $IFACE type bridge priority $IF_BRIDGE_BRIDGEPRIO [ -n "$IF_BRIDGE_FD" ] \ && ip link set dev $IFACE type bridge forward_delay $IF_BRIDGE_FD [ -n "$IF_BRIDGE_HELLO" ] \ && ip link set dev $IFACE type bridge hello_time $IF_BRIDGE_HELLO [ -n "$IF_BRIDGE_MAXAGE" ] \ && ip link set dev $IFACE type bridge max_age $IF_BRIDGE_MAXAGE [ -n "$IF_BRIDGE_PATHCOST" ] \ && bridge link set dev $IFACE cost $IF_BRIDGE_PATHCOST [ -n "$IF_BRIDGE_PORTPRIO" ] \ && bridge link set dev $IFACE priority $IF_BRIDGE_PORTPRIO [ -n "$IF_BRIDGE_STP" ] \ && ip link set dev $IFACE type bridge stp $IF_BRIDGE_STP [ -n "$IF_BRIDGE_VLAN_AWARE" ] \ && ip link set dev $IFACE type bridge vlan_filtering $(yesno $IF_BRIDGE_VLAN_AWARE) } set_bridge_opts() { [ -x /sbin/bridge ] && set_bridge_opts_iproute2 && return 0 [ -x /sbin/brctl ] && set_bridge_opts_brctl && return 0 } set_bridge_default_vlans() { [ -x /sbin/bridge ] || return 0 [ -z "$IF_BRIDGE_PORTS" ] && return 0 for port in $IF_BRIDGE_PORTS; do vids=$(ifquery -p bridge-vids $port) [ -z "$vids" ] && vids="$IF_BRIDGE_VIDS" for vid in $vids; do bridge vlan add vid $vid dev $port done done } set_bridge_access_vlans() { [ -z "$IF_BRIDGE_PORTS" ] || return 0 [ -z "$IF_BRIDGE_ACCESS" ] && return 0 [ -x /sbin/bridge ] || return 0 if [ "$IF_BRIDGE_PVID" = "$IF_BRIDGE_ACCESS" ]; then PVID="pvid" else PVID="" fi bridge vlan add vid $IF_BRIDGE_ACCESS $PVID untagged dev $IFACE } all_ports_ready() { local port= for port in $PORTS; do case $(cat /sys/class/net/$IFACE/brif/$port/state) in ""|0|3) ;; # 0 = disabled, 3 = forwarding [12]) return 1;; esac done return 0 } find_maxwait() { awk '{printf("%.f\n", 2 * $0 / 100); }' \ /sys/class/net/$IFACE/bridge/forward_delay } wait_bridge() { local timeout=$IF_BRIDGE_MAXWAIT if [ -z "$timeout" ]; then timeout=$(find_maxwait) fi ip link set dev $IFACE up while ! all_ports_ready; do [ $timeout -eq 0 ] && break timeout=$(($timeout - 1)) sleep 1 done } [ -z "$IF_BRIDGE_PORTS" ] && IF_BRIDGE_PORTS="$IF_REQUIRES" case "$IF_BRIDGE_PORTS" in "") ;; none) PORTS="";; all) PORTS=$(all_ports);; *) PORTS="$IF_BRIDGE_PORTS";; esac [ -z "$PORTS" ] && ! env | grep -q "^IF_BRIDGE" && exit case "$PHASE" in depend) echo "$PORTS" ;; create) if [ ! -d "/sys/class/net/${IFACE}" ]; then ip link add "${IFACE}" type bridge fi ;; pre-up) wait_ports set_bridge_opts set_bridge_default_vlans set_bridge_access_vlans add_ports wait_bridge ;; post-down) del_ports ip link set dev $IFACE down ;; destroy) if [ -d "/sys/class/net/${IFACE}" ]; then ip link del "${IFACE}" fi ;; esac