diff options
Diffstat (limited to 'source/n/network-scripts/scripts/rc.inet1')
-rw-r--r-- | source/n/network-scripts/scripts/rc.inet1 | 594 |
1 files changed, 444 insertions, 150 deletions
diff --git a/source/n/network-scripts/scripts/rc.inet1 b/source/n/network-scripts/scripts/rc.inet1 index 59f89eda7..f63f93ed7 100644 --- a/source/n/network-scripts/scripts/rc.inet1 +++ b/source/n/network-scripts/scripts/rc.inet1 @@ -15,17 +15,20 @@ # LOGGING # ########### -# If possible, log events in /var/log/messages: -if [ -f /var/run/syslogd.pid ] && [ -x /usr/bin/logger ]; then - LOGGER=/usr/bin/logger -else # output to stdout/stderr: - LOGGER=/bin/cat -fi +# Message logging. +info_log() { + # If possible, log events in /var/log/messages: + if [ -f /var/run/syslogd.pid ] && [ -x /usr/bin/logger ]; then + /usr/bin/logger -t "rc.inet1" --id="$$" "$*" + else + printf "%s: %s\\n" "rc.inet1" "$*" + fi +} -# Handy wrapper for verbose logging: +# Verbose logging. debug_log() { if [ "$DEBUG_ETH_UP" = "yes" ]; then - echo "/etc/rc.d/rc.inet1: $*" | $LOGGER + info_log "$*" fi } @@ -46,22 +49,56 @@ do IFNAME[$i]=${IFNAME[$i]:=eth${i}} i=$(($i+1)) done -debug_log "List of interfaces: '${IFNAME[*]}'" +debug_log "List of interfaces: ${IFNAME[*]}" + +#################### +# PRE-LOAD MODULES # +#################### + +for i in "${IFNAME[@]}"; do + # If the interface isn't in the kernel yet (but there's an alias for it in modules.conf), + # then it should be loaded first: + if [ ! -e /sys/class/net/${i%%[:.]*} ]; then # no interface yet + if /sbin/modprobe -c | grep -v "^#" | grep -w "alias ${i%%[:.]*}" | grep -vw "alias ${i%%[:.]*} off" >/dev/null; then + debug_log "/sbin/modprobe ${i%%[:.]*}" + /sbin/modprobe ${i%%[:.]*} + _DID_MODPROBE=1 + fi + fi +done +# Normally the ipv6 module would be automatically loaded when the first IP is assigned to an +# interface (assuming ipv6 has not been disabled entirely), but autoconf/accept_ra need to be +# set to 0 before that happens, so try to pre-load ipv6 here. +if [ ! -e /proc/sys/net/ipv6 ]; then + debug_log "/sbin/modprobe ipv6" + /sbin/modprobe -q ipv6 + _DID_MODPROBE=1 +fi +# If we did any module loading in the blocks above, sleep for a couple of +# seconds to give time for everything to "take" +[ -n "${_DID_MODPROBE}" ] && sleep 2 +unset _DID_MODPROBE ###################### # LOOPBACK FUNCTIONS # ###################### -# Function to bring up the loopback interface. If loopback is +# Function to bring up the loopback interface. If loopback is # already up, do nothing. lo_up() { if [ -e /sys/class/net/lo ]; then if ! /sbin/ip link show dev lo | grep -wq -e "state UP" -e "state UNKNOWN" ; then - echo "/etc/rc.d/rc.inet1: /sbin/ip address add 127.0.0.1/8 dev lo" | $LOGGER - /sbin/ip address add 127.0.0.1/8 dev lo + info_log "lo: configuring interface" + debug_log "/sbin/ip -4 address add 127.0.0.1/8 dev lo" + /sbin/ip -4 address add 127.0.0.1/8 dev lo + if [ -e /proc/sys/net/ipv6 ]; then + debug_log "/sbin/ip -6 address add ::1/128 dev lo" + /sbin/ip -6 address add ::1/128 dev lo + fi + debug_log "/sbin/ip link set dev lo up" /sbin/ip link set dev lo up - echo "/etc/rc.d/rc.inet1: /sbin/ip route add 127.0.0.0/8 dev lo" | $LOGGER - /sbin/ip route add 127.0.0.0/8 dev lo + debug_log "/sbin/ip route add 127.0.0.0/8 dev lo" + /sbin/ip route add 127.0.0.0/8 dev lo fi fi } @@ -69,7 +106,10 @@ lo_up() { # Function to take down the loopback interface: lo_down() { if [ -e /sys/class/net/lo ]; then - echo "/etc/rc.d/rc.inet1: /sbin/ip link set dev lo down" | $LOGGER + info_log "lo: de-configuring interface" + debug_log "/sbin/ip address flush dev lo" + /sbin/ip address flush dev lo + debug_log "/sbin/ip link set dev lo down" /sbin/ip link set dev lo down fi } @@ -78,20 +118,24 @@ lo_down() { # INTERFACE FUNCTIONS # ####################### -# Function to create virtual interfaces. +# Function to create virtual interfaces virtif_create() { # argument is 'i' - the position of this interface in the VIRTIFNAME array. # this loop goes from i=0 to i=number_of_configured_virtual_interfaces_minus_one # which means it doesn't do anything if there are none. for i in $(seq 0 $((${#VIRTIFNAME[@]} - 1))); do + info_log "${VIRTIFNAME[$i]}: creating virtual interface" + debug_log "/sbin/ip tuntap add dev ${VIRTIFNAME[$i]} mode ${VIRTIFTYPE[$i]} user ${VIRTIFUSER[$i]} group ${VIRTIFGROUP[$i]}" /sbin/ip tuntap add dev ${VIRTIFNAME[$i]} mode ${VIRTIFTYPE[$i]} user ${VIRTIFUSER[$i]} group ${VIRTIFGROUP[$i]} done } -# Function to destroy virtual interfaces. +# Function to destory virtual interfaces virtif_destroy() { # argument is 'i' - the position of this interface in the VIRTIFNAME array. for i in $(seq 0 $((${#VIRTIFNAME[@]} - 1))); do + info_log "${VIRTIFNAME[$i]}: destroying virtual interface" + debug_log "/sbin/ip tuntap del dev ${VIRTIFNAME[$i]} mode ${VIRTIFTYPE[$i]}" /sbin/ip tuntap del dev ${VIRTIFNAME[$i]} mode ${VIRTIFTYPE[$i]} done } @@ -99,30 +143,91 @@ virtif_destroy() { # Function to assemble a bridge interface. br_open() { # argument is 'i' - the position of this interface in the IFNAME array. + info_log "${IFNAME[$1]}: creating bridge" + debug_log "/sbin/ip link add name ${IFNAME[$1]} type bridge" /sbin/ip link add name ${IFNAME[$1]} type bridge for BRIF in ${BRNICS[$1]}; do - /sbin/ip link set dev $BRIF down - /sbin/ip address add 0.0.0.0 dev $BRIF + debug_log "/sbin/ip address flush dev $BRIF" + /sbin/ip address flush dev $BRIF + debug_log "/sbin/ip link set dev $BRIF master ${IFNAME[$1]}" /sbin/ip link set dev $BRIF master ${IFNAME[$1]} + debug_log "/sbin/ip link set dev $BRIF up" /sbin/ip link set dev $BRIF up done + while read -r -d \| IFOPT; do + if [ -n "$IFOPT" ]; then + debug_log "/sbin/ip link set dev ${IFNAME[$1]} type bridge $IFOPT" + /sbin/ip link set dev ${IFNAME[$1]} type bridge $IFOPT + fi + done <<<"${IFOPTS[$i]}|" # The | on the end is required. + debug_log "/sbin/ip link set dev ${IFNAME[$1]} up" /sbin/ip link set dev ${IFNAME[$1]} up } # Function to disassemble a bridge interface. br_close() { - /sbin/ip link set dev ${IFNAME[$1]} down # argument is 'i' - the position of this interface in the IFNAME array. - #for BRIF in ${BRNICS[$1]}; do + info_log "${IFNAME[$1]}: destroying bridge" + debug_log "/sbin/ip link set dev ${IFNAME[$1]} down" + /sbin/ip link set dev ${IFNAME[$1]} down for BRIF in $(ls --indicator-style=none /sys/class/net/${IFNAME[$1]}/brif/) do + debug_log "/sbin/ip link set dev $BRIF nomaster" /sbin/ip link set dev $BRIF nomaster done - /sbin/ip link set dev ${IFNAME[$1]} down + for BRIF in ${BRNICS[$1]}; do + debug_log "/sbin/ip link set dev $BRIF down" + /sbin/ip link set dev $BRIF down + done + debug_log "/sbin/ip link del ${IFNAME[$1]}" /sbin/ip link del ${IFNAME[$1]} } -# Function to bring up a network interface. If the interface is +# Function to create a bond. +bond_create() { + # Argument is 'i' - the position of this interface in the IFNAME array. + info_log "${IFNAME[$1]}: creating bond" + debug_log "/sbin/ip link add name ${IFNAME[$1]} type bond" + /sbin/ip link add name ${IFNAME[$1]} type bond + debug_log "/sbin/ip link set dev ${IFNAME[$1]} type bond mode ${BONDMODE[$1]:-balance-rr}" + /sbin/ip link set dev ${IFNAME[$1]} type bond mode ${BONDMODE[$1]:-balance-rr} + for BONDIF in ${BONDNICS[$1]}; do + debug_log "/sbin/ip address flush dev $BONDIF" + /sbin/ip address flush dev $BONDIF + debug_log "/sbin/ip link set $BONDIF master ${IFNAME[$1]}" + /sbin/ip link set $BONDIF master ${IFNAME[$1]} + debug_log "/sbin/ip link set dev $BONDIF up" + /sbin/ip link set dev $BONDIF up + done + # This has to be done *after* the interface is brought up because the + # 'primary <interface>' option has to occur after the interface is active. + while read -r -d \| IFOPT; do + if [ -n "$IFOPT" ]; then + debug_log "/sbin/ip link set dev ${IFNAME[$1]} type bond $IFOPT" + /sbin/ip link set dev ${IFNAME[$1]} type bond $IFOPT + fi + done <<<"${IFOPTS[$1]}|" # The | on the end is required. +} + +# Function to destroy a bond. +bond_destroy() { + # Argument is 'i' - the position of this interface in the IFNAME array. + info_log "${IFNAME[$1]}: destroying bond" + debug_log "/sbin/ip link set dev ${IFNAME[$1]} down" + /sbin/ip link set dev ${IFNAME[$1]} down + debug_log "/sbin/ip address flush dev ${IFNAME[$1]}" + /sbin/ip address flush dev ${IFNAME[$1]} + for BONDIF in ${BONDNICS[$1]}; do + debug_log "/sbin/ip link set $BONDIF nomaster" + /sbin/ip link set $BONDIF nomaster + debug_log "/sbin/ip link set dev $BONDIF down" + /sbin/ip link set dev $BONDIF down + done + debug_log "/sbin/ip link del name ${IFNAME[$1]} type bond" + /sbin/ip link del name ${IFNAME[$1]} type bond +} + +# Function to bring up a network interface. If the interface is # already up or does not yet exist (perhaps because the kernel driver # is not loaded yet), do nothing. if_up() { @@ -133,126 +238,265 @@ if_up() { i=$(($i+1)) done # If "i" is greater or equal to "MAXNICS" at this point, it means we didn't - # find an entry in IFNAME array corresponding to "$1", which likely means + # find an entry in IFNAME array corresponding to "${1}", which likely means # there are more interfaces configured than MAXNICS. Let's err on the # side of caution and do nothing instead of possibly doing the wrong thing. if [ $i -ge $MAXNICS ]; then - echo "/etc/rc.d/rc.inet1: skipping ${1}, you might need to increase MAXNICS" | $LOGGER + info_log "${1}: skipping - you might need to increase MAXNICS" return fi - # If the interface is a bridge, then create it first: + info_log "${1}: configuring interface" + # If you need to set hardware addresses for the underlying interfaces in a + # bond or bridge, configure the interfaces with IPs of 0.0.0.0 and set the + # MAC address with HWADDR. Then, finally, define the bond or bridge. + # If the interface is a bond, create it. + [ -n "${BONDNICS[$i]}" ] && bond_create $i + # If the interface is a bridge, create it. [ -n "${BRNICS[$i]}" ] && br_open $i - # If the interface isn't in the kernel yet (but there's an alias for it in - # modules.conf), then it should be loaded first: - if [ -z "${IPADDR[$i]}" ] && [ "${USE_DHCP[$i]}" != "yes" ]; then # skip unconfigured interfaces - debug_log "skipping ${1} early, interface is not configured in /etc/rc.d/rc.inet1.conf" - return 0 - fi - if [ ! -e /sys/class/net/${1%%:*} ]; then # no interface yet - if /sbin/modprobe -c | grep -v "^#" | grep -w "alias ${1}" | grep -vw "alias ${1} off" > /dev/null ; then - echo "/etc/rc.d/rc.inet1: /sbin/modprobe ${1}" | $LOGGER - /sbin/modprobe ${1} - fi - fi - if [ -e /sys/class/net/${1%%:*} ]; then # interface exists - if ! /sbin/ip address show dev ${1} 2>/dev/null | grep -wq inet || \ - ! /sbin/ip link show dev ${1} | grep -wq "state UP" ; then # interface not up or not configured - if [ -n "${HWADDR[$i]}" ]; then # Set hardware address _before_ the interface goes up: - echo "/etc/rc.d/rc.inet1: /sbin/ip link set dev ${1} address ${HWADDR[$i]}" | $LOGGER - /sbin/ip link set dev ${1} address ${HWADDR[$i]} + if [ -e /sys/class/net/${1%%[:.]*} ]; then # interface exists + if ! /sbin/ip address show scope global dev ${1} 2>/dev/null | grep -Ewq '(inet|inet6)' || \ + ! /sbin/ip link show dev ${1} | grep -wq "state UP"; then # interface not up or not configured + local IF_UP=0 + # Initialize any wireless parameters: + if [ -x /etc/rc.d/rc.wireless ]; then + . /etc/rc.d/rc.wireless ${1} start fi - if [ -n "${MTU[$i]}" ]; then # Set MTU to something else than 1500 - echo "/etc/rc.d/rc.inet1: /sbin/ip link set dev ${1} mtu ${MTU[$i]}" | $LOGGER - /sbin/ip link set dev ${1} mtu ${MTU[$i]} + # Handle VLAN interfaces before trying to configure IP addresses. + if echo "${1}" | grep -Fq .; then + IFACE="${1%.*}" + VLAN="${1##*.}" + # Check if the underlying interface is already up. + if ! /sbin/ip link show dev $IFACE 2>/dev/null| grep -wq "state UP"; then + # Bring up the underlying interface. + debug_log "/sbin/ip link set dev $IFACE up" + if ! /sbin/ip link set dev $IFACE up; then + info_log "${1}: failed to bring up interface $IFACE" + return + fi + IF_UP=1 + fi + # Configure the VLAN interface. + info_log "${1}: creating VLAN interface" + debug_log "/sbin/ip link add link $IFACE name ${1} type vlan id $VLAN" + if ! /sbin/ip link add link $IFACE name ${1} type vlan id $VLAN; then + info_log "${1}: failed to create VLAN interface" + ((IF_UP == 1)) && /sbin/ip link set dev $IFACE down + return + fi + while read -r -d \| IFOPT; do + if [ -n "$IFOPT" ]; then + debug_log "/sbin/ip link set dev ${1} type vlan $IFOPT" + /sbin/ip link set dev ${1} type vlan $IFOPT + fi + done <<<"${IFOPTS[$i]}|" # The | on the end is required. + elif [ -z "${BONDNICS[$i]}" ] && [ -z "${BRNICS[$i]}" ]; then + # Only apply IFOPTS for a physical interface if it's not been handled + # by a higher level interface. + while read -r -d \| IFOPT; do + if [ -n "$IFOPT" ]; then + debug_log "/sbin/ip link set dev ${1} $IFOPT" + /sbin/ip link set dev ${1} $IFOPT + fi + done <<<"${IFOPTS[$i]}|" # The | on the end is required. fi - if /sbin/ip link show dev ${1} | grep -wq "state DOWN" ; then - /sbin/ip link set dev ${1} up # Bring up interface + # Set hardware address: + if [ -n "${HWADDR[$i]}" ]; then + debug_log "/sbin/ip link set dev ${1} address ${HWADDR[$i]}" + if ! /sbin/ip link set dev ${1} address ${HWADDR[$i]} 2>/dev/null; then + info_log "${1}: failed to set hardware address" + fi fi - if [ -x /etc/rc.d/rc.wireless ]; then - . /etc/rc.d/rc.wireless ${1} start # Initialize any wireless parameters + if [ -e /proc/sys/net/ipv6 ]; then # ipv6 networking is available + # Disable v6 IP auto configuration before trying to bring up the interface: + debug_log "${1}: disabling IPv6 autoconf" + echo "0" >/proc/sys/net/ipv6/conf/${1}/autoconf + if [ "${USE_RA[$i]}" = "yes" ]; then + # Unconditionally accept router advertisements on this interface: + debug_log "${1}: accepting IPv6 RA" + echo "1" >/proc/sys/net/ipv6/conf/${1}/accept_ra + else + # Disable router advertisments on this interface until SLAAC is enabled: + debug_log "${1}: ignoring IPv6 RA" + echo "0" >/proc/sys/net/ipv6/conf/${1}/accept_ra + fi fi - if [ "${USE_DHCP[$i]}" = "yes" ]; then # use DHCP to bring interface up - # Clear DHCP_OPTIONS before adding new options to it: - unset DHCP_OPTIONS + debug_log "/sbin/ip address flush dev ${1}" + /sbin/ip address flush dev ${1} + IF_UP=0 + # Slackware historically favours dynamic configuration over fixed IP to configure interfaces, so keep that tradition: + if [ "${USE_DHCP[$i]}" = "yes" ] || { [ -e /proc/sys/net/ipv6 ] && [ "${USE_DHCP6[$i]}" = "yes" ]; }; then # use dhcpcd + info_log "${1}: starting dhcpcd" + # Declare DHCP_OPTIONS array before adding new options to it: + local -a DHCP_OPTIONS=() # Set DHCP_OPTIONS for this interface: - [ -n "${DHCP_HOSTNAME[$i]}" ] && DHCP_OPTIONS="-h ${DHCP_HOSTNAME[$i]}" - [ "${DHCP_KEEPRESOLV[$i]}" = "yes" ] && DHCP_OPTIONS="$DHCP_OPTIONS -C resolv.conf" - [ "${DHCP_KEEPNTP[$i]}" = "yes" ] && DHCP_OPTIONS="$DHCP_OPTIONS -C ntp.conf" - [ "${DHCP_KEEPGW[$i]}" = "yes" ] && DHCP_OPTIONS="$DHCP_OPTIONS -G" - [ "${DHCP_DEBUG[$i]}" = "yes" ] && DHCP_OPTIONS="$DHCP_OPTIONS -d" - [ "${DHCP_NOIPV4LL[$i]}" = "yes" ] && DHCP_OPTIONS="$DHCP_OPTIONS -L" - [ -n "${DHCP_IPADDR[$i]}" ] && DHCP_OPTIONS="$DHCP_OPTIONS -r ${DHCP_IPADDR[$i]}" - echo "Polling for DHCP server on interface ${1}:" - # If you set a timeout, you get one, even if the kernel doesn't think that - # your device is connected, in case /sys isn't right (which it usually isn't - # except right after the device is loaded, when it usually is): - #### (start commented out) - # This is deactivated for now since the kernel has been returning incorrect - # results concerning whether the interface carrier is detected. - #if [ -z "${DHCP_TIMEOUT[$i]}" ]; then - # /sbin/ip link set dev ${1} up && sleep 1 - # CONNSTATUS="$(cat /sys/class/net/${1}/carrier 2> /dev/null)" - # /sbin/ip link set dev ${1} down - # if [ "$CONNSTATUS" = "0" ]; then - # # The kernel has just told us the cable isn't even plugged in, but we will - # # give any DHCP server a short chance to reply anyway: - # echo "No carrier detected on ${1}. Reducing DHCP timeout to 15 seconds." - # DHCP_TIMEOUT[$i]=15 - # fi - #fi - #### (end commented out) - # 15 seconds should be a reasonable default DHCP timeout. 30 was too much. - echo "/etc/rc.d/rc.inet1: /sbin/dhcpcd -L -t ${DHCP_TIMEOUT[$i]:-15} ${DHCP_OPTIONS} ${1}" | $LOGGER - /sbin/dhcpcd -L -t ${DHCP_TIMEOUT[$i]:-15} ${DHCP_OPTIONS} ${1} - if [ "$?" == "0" ]; then # the dhcp call has succeeded - if [ -n "${IPALIASES[$i]}" ]; then - # Add extra IP addresses, if defined, to interface - num=0 - for ipalias in ${IPALIASES[$i]}; do - ip="${ipalias%/*}" - nm="${ipalias#*/}" - [ -z "$nm" ] || [ "$ip" == "$nm" ] && nm="32" - /sbin/ip address add ${ip}/${nm} dev ${1} label ${1}:${num} - num=$(($num + 1)) - done + if [ -e /proc/sys/net/ipv6 ]; then + if [ "${USE_DHCP[$i]}" = "yes" ] && [ "${USE_DHCP6[$i]}" != "yes" ]; then # only try v4 dhcp + DHCP_OPTIONS+=("-4") + elif [ "${USE_DHCP[$i]}" != "yes" ] && [ "${USE_DHCP6[$i]}" = "yes" ]; then # only try v6 dhcp + DHCP_OPTIONS+=("-6") fi - if [ "${PROMISCUOUS[$i]}" = "yes" ]; then - # Set promiscuous mode on the interface - /sbin/ip link set dev ${1} promisc on + else + DHCP_OPTIONS+=("-4") + fi + [ -n "${DHCP_HOSTNAME[$i]}" ] && DHCP_OPTIONS+=("-h" "${DHCP_HOSTNAME[$i]}") + [ "${DHCP_KEEPRESOLV[$i]}" = "yes" ] && DHCP_OPTIONS+=("-C" "resolv.conf") + [ "${DHCP_KEEPNTP[$i]}" = "yes" ] && DHCP_OPTIONS+=("-C" "ntp.conf") + [ "${DHCP_KEEPGW[$i]}" = "yes" ] && DHCP_OPTIONS+=("-G") + [ "${DHCP_DEBUG[$i]}" = "yes" ] && DHCP_OPTIONS+=("-d") + # The -L option used to be hard coded into the dhcpcd command line in -current. It was added to assist ARM users + # get networking up and running. Previous versions of Slackware did not have -L hard coded - the code here keeps + # the 14.2 behaviour, but can be altered to make the use of -L default as in -current. To change the behaviour, + # alter the test below to be: [ "${DHCP_NOIPV4LL[$i]}" != "no" ]. + # Note: ARM users should make use of the DHCP_NOIPV4LL[x]="yes" parameter in rc.inet1.conf - this is the correct + # way to get the behaviour they seek. + [ "${DHCP_NOIPV4LL[$i]}" = "yes" ] && DHCP_OPTIONS+=("-L") + [ -n "${DHCP_IPADDR[$i]}" ] && DHCP_OPTIONS+=("-r" "${DHCP_IPADDR[$i]}") + echo "${1}: polling for DHCP server" + # 15 seconds should be a reasonable default DHCP timeout. 30 was too much. + debug_log "/sbin/dhcpcd -t ${DHCP_TIMEOUT[$i]:-15} ${DHCP_OPTIONS[*]} ${1}" + if /sbin/dhcpcd -t "${DHCP_TIMEOUT[$i]:-15}" "${DHCP_OPTIONS[@]}" ${1}; then + # Enable accepting of RA packets if explicitly told to: + if [ -e /proc/sys/net/ipv6 ] && [ "${USE_RA[$i]}" = "yes" ]; then + debug_log "${1}: unconditionally accepting IPv6 RA" + echo "1" >/proc/sys/net/ipv6/conf/${1}/accept_ra fi + IF_UP=1 + else + info_log "${1}: failed to obtain DHCP lease" + debug_log "/sbin/ip address flush dev ${1}" + /sbin/ip address flush dev ${1} + debug_log "/sbin/ip link set dev ${1} down" + /sbin/ip link set dev ${1} down + fi + fi + if [ -e /proc/sys/net/ipv6 ] && [ "${USE_DHCP6[$i]}" != "yes" ] && [ "${USE_SLAAC[$i]}" = "yes" ]; then # configure via SLAAC + info_log "${1}: enabling SLAAC" + # Enable accepting of RA packets, unless explicitly configured not to: + if [ "${USE_RA[$i]}" = "no" ]; then + debug_log "${1}: ignoring IPv6 RA" + echo "0" >/proc/sys/net/ipv6/conf/${1}/accept_ra + else + debug_log "${1}: accepting IPv6 RA" + echo "1" >/proc/sys/net/ipv6/conf/${1}/accept_ra + fi + # Enable auto configuration of interfaces: + echo "1" >/proc/sys/net/ipv6/conf/${1}/autoconf + # Bring the interface up: + debug_log "/sbin/ip link set dev ${1} up" + /sbin/ip link set dev ${1} up + echo "${1}: waiting for router announcement" + for ((j = ${SLAAC_TIMEOUT[$i]:=15} * 2; j--;)); do # by default, wait a max of 15 seconds for the interface to configure + /sbin/ip -6 address show dynamic dev ${1} 2>/dev/null | grep -Ewq 'inet6' && { IF_UP=1; break; } + sleep 0.5 + done + if (($IF_UP != 1)); then + echo "${1}: timed out" + info_log "${1}: failed to auto configure after ${SLAAC_TIMEOUT[$i]} seconds" + debug_log "/sbin/ip address flush dev ${1}" + /sbin/ip address flush dev ${1} + debug_log "/sbin/ip link set dev ${1} down" + /sbin/ip link set dev ${1} down fi - else # bring up interface using a static IP address - if [ -n "${IPADDR[$i]}" ]; then # skip unconfigured interfaces - # Set up the network card: - echo "/etc/rc.d/rc.inet1: /sbin/ip address add ${IPADDR[$i]}/${NETMASK[$i]} broadcast + dev ${1}" | $LOGGER - /sbin/ip address add ${IPADDR[$i]}/${NETMASK[$i]} broadcast + dev ${1} - if /sbin/ip link show dev ${1} | grep -wq "state DOWN" ; then - /sbin/ip link set dev ${1} up # Bring up interface + fi + if [ "${USE_DHCP[$i]}" != "yes" ] && [ -n "${IPADDR[$i]}" ]; then # add a fixed v4 IP to the interface + info_log "${1}: setting fixed IPv4 address" + if [ -z "${NETMASK[$i]}" ]; then + info_log "${1}: no NETMASK set for primary IP ${IPADDR[$i]} - assuming 24 (aka, 255.255.255.0)" + NETMASK[$i]="24" + fi + debug_log "/sbin/ip -4 address add ${IPADDR[$i]}/${NETMASK[$i]#/} broadcast + dev ${1}" + if /sbin/ip -4 address add ${IPADDR[$i]}/${NETMASK[$i]#/} broadcast + dev ${1} && \ + /sbin/ip link set dev ${1} up; then + IF_UP=1 + else + info_log "${1}: failed to set IP ${IPADDR[$i]}" + debug_log "/sbin/ip address flush dev ${1}" + /sbin/ip address flush dev ${1} + debug_log "/sbin/ip link set dev ${1} down" + /sbin/ip link set dev ${1} down + fi + fi + if [ -e /proc/sys/net/ipv6 ] && [ "${USE_DHCP6[$i]}" != "yes" ] && [ "${USE_SLAAC[$i]}" != "yes" ] && \ + [ -n "${IP6ADDRS[$i]}" ]; then # add fixed v6 IPs + info_log "${1}: setting fixed IPv6 addresses" + # IPv6's Duplicate Address Detection (DAD) causes a race condition when bringing up interfaces, as + # described here: https://www.agwa.name/blog/post/beware_the_ipv6_dad_race_condition + # Disable DAD while bringing up the interface - but note that this means the loss of detection of a + # duplicate address. It's a trade off, unfortunately. + debug_log "${1}: disabling IPv6 DAD" + echo "0" >/proc/sys/net/ipv6/conf/${1}/accept_dad + for V6IP in ${IP6ADDRS[$i]}; do + IP="${V6IP%/*}" + PREFIX="${V6IP#*/}" + if [ -z "$PREFIX" ] || [ "$IP" == "$PREFIX" ]; then + info_log "${1}: no prefix length set for IP $IP - assuming 64" + PREFIX="64" fi - # Add extra IP addresses, if defined, to interface - if [ -n "${IPALIASES[$i]}" ]; then - num=0 - for ipalias in ${IPALIASES[$i]}; do - ip="${ipalias%/*}" - nm="${ipalias#*/}" - [ -z "$nm" ] || [ "$ip" == "$nm" ] && nm="32" - /sbin/ip address add ${ip}/${nm} dev ${1} label ${1}:${num} - num=$(($num + 1)) - done + debug_log "/sbin/ip -6 address add $IP/$PREFIX dev ${1}" + if /sbin/ip -6 address add $IP/$PREFIX dev ${1} && \ + /sbin/ip link set dev ${1} up; then + # Enable accepting of RA packets if explicitly told to. + if [ "${USE_RA[$i]}" = "yes" ]; then + debug_log "${1}: unconditionally accepting IPv6 RA" + echo "1" >/proc/sys/net/ipv6/conf/${1}/accept_ra + fi + IF_UP=1 + else + info_log "${1}: failed to set IP $IP" + if (($IF_UP != 1)); then # a v4 address was configured, don't flush it + debug_log "/sbin/ip address flush dev ${1}" + /sbin/ip address flush dev ${1} + debug_log "/sbin/ip link set dev ${1} down" + /sbin/ip link set dev ${1} down + fi fi - if [ "${PROMISCUOUS[$i]}" = "yes" ]; then - # Set promiscuous mode on the interface - /sbin/ip link set dev ${1} promisc on + done + # Reset accept_dad back to default now all the IPs are configured: + debug_log "${1}: resetting IPv6 DAD to default" + cat /proc/sys/net/ipv6/conf/default/accept_dad >/proc/sys/net/ipv6/conf/${1}/accept_dad + fi + if (($IF_UP == 1)); then # only do further config if the interface came up + info_log "${1}: setting fixed IPv4 alias addresses" + # Add extra IPv4 addresses to the interface: + if [ -n "${IPALIASES[$i]}" ]; then + NUM=0 + for IPALIAS in ${IPALIASES[$i]}; do + IP="${IPALIAS%/*}" + NM="${IPALIAS#*/}" + if [ -z "$NM" ] || [ "$IP" == "$NM" ]; then + info_log "${1}: no netmask set for alias IP $IP - assuming 24 (aka, 255.255.255.0)" + NM="24" + fi + debug_log "/sbin/ip -4 address add $IP/$NM broadcast + dev ${1} label ${1}:$NUM" + if /sbin/ip -4 address add $IP/$NM broadcast + dev ${1} label ${1}:$NUM; then + NUM=$(($NUM + 1)) + else + info_log "${1}: failed to add alias IP $IP" + fi + done + fi + # Force an MTU (possibly over-riding that set by DHCP or RA): + if [ -n "${MTU[$i]}" ]; then + info_log "${1}: setting custom MTU" + debug_log "/sbin/ip link set dev ${1} mtu ${MTU[$i]}" + if ! /sbin/ip link set dev ${1} mtu ${MTU[$i]}; then + info_log "${1}: failed to set MTU" + fi + fi + # Set promiscuous mode on the interface: + if [ "${PROMISCUOUS[$i]}" = "yes" ]; then + info_log "${1}: setting promiscuous mode" + debug_log "/sbin/ip link set dev ${1} promisc on" + if ! /sbin/ip link set dev ${1} promisc on; then + info_log "${1}: failed to set promiscuous mode" fi - else - debug_log "${1} interface is not configured in /etc/rc.d/rc.inet1.conf" fi fi else - debug_log "${1} is already up, skipping" - fi + debug_log "${1}: skipping configuration - already up" + fi else - debug_log "${1} interface does not exist (yet)" + debug_log "${1}: skipping configuration - does not exist (yet)" fi } @@ -265,27 +509,61 @@ if_down() { i=$(($i+1)) done if [ $i -ge $MAXNICS ]; then - echo "/etc/rc.d/rc.inet1: skipping ${1}, you might need to increase MAXNICS" | $LOGGER + info_log "${1}: skipping - you might need to increase MAXNICS" return fi - if [ -e /sys/class/net/${1%%:*} ]; then - if [ "${USE_DHCP[$i]}" = "yes" ]; then - echo "/etc/rc.d/rc.inet1: /sbin/dhcpcd -k -d ${1}" | $LOGGER - /sbin/dhcpcd -k -d ${1} 2> /dev/null || /sbin/ip link set dev ${1} down - sleep 1 - else - echo "/etc/rc.d/rc.inet1: /sbin/ip link set dev ${1} down" | $LOGGER - /sbin/ip link set dev ${1} down + info_log "${1}: de-configuring interface" + if [ -e /sys/class/net/${1} ]; then + if [ "${USE_DHCP[$i]}" = "yes" ] || [ "${USE_DHCP6[$i]}" = "yes" ]; then # take down dhcpcd + info_log "${1}: stopping dhcpcd" + # When using -k, dhcpcd requires some command line options to match those used to invoke it: + if [ "${USE_DHCP[$i]}" = "yes" ] && [ "${USE_DHCP6[$i]}" != "yes" ]; then # only v4 dhcp + DHCP_OPTIONS="-4" + elif [ "${USE_DHCP[$i]}" != "yes" ] && [ "${USE_DHCP6[$i]}" = "yes" ]; then # only v6 dhcp + DHCP_OPTIONS="-6" + fi + debug_log "/sbin/dhcpcd $DHCP_OPTIONS -k -d ${1}" + /sbin/dhcpcd $DHCP_OPTIONS -k -d ${1} 2>/dev/null || info_log "${1}: failed to stop dhcpcd" fi - if [ -x /etc/rc.d/rc.wireless ]; then - . /etc/rc.d/rc.wireless ${1} stop # Kill wireless daemons if any. + # Disable v6 IP auto configuration and RA before trying to clear the IP from the interface: + if [ -e /proc/sys/net/ipv6 ]; then + debug_log "${1}: disabling IPv6 autoconf and RA" + echo "0" >/proc/sys/net/ipv6/conf/${1}/autoconf + echo "0" >/proc/sys/net/ipv6/conf/${1}/accept_ra + fi + sleep 0.5 # allow time for DHCP/RA to unconfigure the interface + # Flush any remaining IPs: + debug_log "/sbin/ip address flush dev ${1}" + /sbin/ip address flush dev ${1} + # Bring the interface down: + debug_log "/sbin/ip link set dev ${1} down" + /sbin/ip link set dev ${1} down + # Reset autoconf and accept_ra back to defaults: + if [ -e /proc/sys/net/ipv6 ]; then + debug_log "${1}: resetting IPv6 autoconf and RA to defaults" + cat /proc/sys/net/ipv6/conf/default/autoconf >/proc/sys/net/ipv6/conf/${1}/autoconf + cat /proc/sys/net/ipv6/conf/default/accept_ra >/proc/sys/net/ipv6/conf/${1}/accept_ra fi # If the interface is a bridge, then destroy it now: - if [ -n "${BRNICS[$i]}" ]; then - br_close $i + [ -n "${BRNICS[$i]}" ] && br_close $i + # If the interface is a bond, then destroy it now. + [ -n "${BONDNICS[$i]}" ] && bond_destroy $i + # Take down VLAN interface, if configured. + if echo "${1}" | grep -Fq .; then + info_log "${1}: destroying VLAN interface" + debug_log "/sbin/ip link set dev ${1} down" + /sbin/ip link set dev ${1} down + debug_log "/sbin/ip link delete ${1}" + /sbin/ip link delete ${1} + if ! /sbin/ip address show scope global dev ${1%.*} 2>/dev/null | grep -Ewq '(inet|inet6)'; then + debug_log "/sbin/ip link set dev ${1%.*} down" + /sbin/ip link set dev ${1%.*} down + fi + fi + # Kill wireless daemons if any: + if [ -x /etc/rc.d/rc.wireless ]; then + . /etc/rc.d/rc.wireless ${1} stop fi - # Flush the address from the interface: - ip address flush dev ${1} fi } @@ -295,24 +573,39 @@ if_down() { # Function to bring up the gateway if there is not yet a default route: gateway_up() { - if ! /sbin/ip route show | grep -wq default ; then - if [ -n "$GATEWAY" ]; then - echo "/etc/rc.d/rc.inet1: /sbin/ip route add default via ${GATEWAY}" | $LOGGER - /sbin/ip route add default via ${GATEWAY} | $LOGGER + info_log "Configuring gateways" + # Bring up the IPv4 gateway: + if [ -n "$GATEWAY" ]; then + if ! /sbin/ip -4 route show | grep -wq default; then + debug_log "/sbin/ip -4 route add default via ${GATEWAY}" + /sbin/ip -4 route add default via ${GATEWAY} + fi + fi + # Bring up the IPv6 gateway: + if [ -n "$GATEWAY6" ]; then + if ! /sbin/ip -6 route show | grep -wq default; then + debug_log "/sbin/ip -6 route add default via ${GATEWAY6}" + /sbin/ip -6 route add default via ${GATEWAY6} fi fi } # Function to take down an existing default gateway: gateway_down() { - if /sbin/ip route show | grep -wq default ; then - echo "/etc/rc.d/rc.inet1: /sbin/ip route del default" | $LOGGER - /sbin/ip route del default + info_log "De-configuring gateways" + if /sbin/ip -4 route show | grep -wq default ; then + debug_log "/sbin/ip -4 route del default" + /sbin/ip -4 route del default + fi + if /sbin/ip -6 route show | grep -wq default ; then + debug_log "/sbin/ip -6 route del default" + /sbin/ip -6 route del default fi } # Function to start the network: start() { + echo "Starting the network interfaces..." lo_up virtif_create for i in "${IFNAME[@]}" ; do @@ -323,9 +616,10 @@ start() { # Function to stop the network: stop() { + echo "Stopping the network interfaces..." gateway_down - for i in "${IFNAME[@]}" ; do - if_down $i + for (( i = $MAXNICS - 1; i >= 0; i-- )); do + if_down ${IFNAME[$i]} done virtif_destroy lo_down @@ -336,7 +630,7 @@ stop() { ### MAIN ### ############ -case "$1" in +case "${1}" in start|up) # "start" (or "up") brings up all configured interfaces: start ;; @@ -354,16 +648,16 @@ lo_stop|lo_down) # Stop the loopback interface: lo_down ;; *_start|*_up) # Example: "eth1_start" (or "eth1_up") will start the specified interface 'eth1' - INTERFACE=$(echo $1 | /bin/cut -d '_' -f 1) + INTERFACE=$(echo ${1} | /bin/cut -d '_' -f 1) if_up $INTERFACE gateway_up ;; *_stop|*_down) # Example: "eth0_stop" (or "eth0_down") will stop the specified interface 'eth0' - INTERFACE=$(echo $1 | /bin/cut -d '_' -f 1) + INTERFACE=$(echo ${1} | /bin/cut -d '_' -f 1) if_down $INTERFACE ;; *_restart) # Example: "wlan0_restart" will take 'wlan0' down and up again - INTERFACE=$(echo $1 | /bin/cut -d '_' -f 1) + INTERFACE=$(echo ${1} | /bin/cut -d '_' -f 1) if_down $INTERFACE sleep 1 if_up $INTERFACE |