blob: 2b15d8e298c5cf6d96604abae15216044fbed447 [file] [log] [blame]
#!/bin/sh
. /etc/utils.sh
trap ": >/tmp/run/network.init" EXIT
register_experiment BigInitRwnd
register_experiment NoSTP
register_experiment TVBoxNoGigEthernet
register_experiment TcpWmem1Meg
register_experiment AggressiveTCP
register_experiment BigSocketBuffers
register_experiment MocaFlowControl
irq_affinity() {
local irq="$1" cpu="$2"
if [ -e "/proc/irq/$irq/smp_affinity" ]; then
if ! echo "$cpu" >"/proc/irq/$irq/smp_affinity"; then
echo "Failed to set affinity for IRQ $irq @ CPU $cpu"
fi
else
echo " ...irq #$irq not present, skipping" >&2
fi
}
redistribute_irqs() {
# if a second CPU isn't available, do nothing.
echo "distribute IRQ handling between cores"
if ! taskset 2 true 2>/dev/null; then
echo " ...only one CPU available, skipped."
fi
# Rule of thumb:
# - interrupts are generally by default on first CPU (bitfield=1)
# - let's move realtime sensitive stuff to second CPU (bitfield=2)
# - non-realtime userspace processes can default to both (bitfield=3)
if is-storage-box || is-network-box; then
# Storage box serves MoCA and ethernet simultaneously.
# - put them both on separate CPUs to maximize throughput.
# - consider ethernet (not MoCA) to be realtime sensitive, since it
# carries the multicast feed.
# - consider disk to be non-realtime, since it can prefetch/writeback.
serialcpu=1
eth0cpu=2
mocacpu=1
wificpu=1 # may not actually have wifi
diskcpu=1
else
# TV box handles video interrupts (via miniclient) and
# (ethernet *or* MoCA) traffic (which carries the video stream), and wifi.
# Network traffic includes the video stream, but it's TCP, so it should
# be able to retransmit if packets are lost (unlike multicast on the
# storage box) so it should be okay to put it on the non-realtime CPU.
serialcpu=1
eth0cpu=1
mocacpu=1
wificpu=1
diskcpu=1 # doesn't actually have a disk
fi
if grep -q BCM7425 /proc/cpuinfo; then
irq_affinity 62 $serialcpu
irq_affinity 18 $eth0cpu
irq_affinity 19 $eth0cpu
irq_affinity 20 $mocacpu
irq_affinity 21 $mocacpu
irq_affinity 31 $mocacpu
irq_affinity 34 $wificpu # bcm wifi, if present
irq_affinity 42 $diskcpu
elif grep -q BCM7429 /proc/cpuinfo; then
irq_affinity 52 $serialcpu
irq_affinity 16 $eth0cpu
irq_affinity 17 $eth0cpu
irq_affinity 18 $mocacpu
irq_affinity 19 $mocacpu
irq_affinity 28 $mocacpu
# Wifi is on one of mmc0 or mmc1, but it has varied between early
# device models. Since mmc is pretty fast and seldom used (and we happen
# to want it on the non-realtime cpu anyway, like wifi), let's just
# blindly put them both on the wifi cpu.
irq_affinity 35 $wificpu # mmc1
irq_affinity 36 $wificpu # mmc0
# Note: no disk present, ignore $diskcpu
elif grep -q comcerto /proc/iomem; then
# TODO(apenwarr): we steer *all* PFE network traffic to $eth0cpu.
# Ideally we want only multicast to go there, and other traffic to
# go to the non-realtime CPU. There may be some way to do this by
# changing PFE somehow. As is, incoming WAN traffic destined for wifi
# could end up sucking all available CPU and interfere with multicast.
irq_affinity 59 $serialcpu # serial
irq_affinity 62 $serialcpu # i2c (NOR flash)
irq_affinity 36 $eth0cpu # *all* PFE
irq_affinity 77 $mocacpu
irq_affinity 128 $wificpu # new boards, ath10k
irq_affinity 160 $wificpu # new boards, ath9k
irq_affinity 96 $wificpu 2>/dev/null # old boards, ath10k
irq_affinity 164 $wificpu 2>/dev/null # old boards, ath9k
irq_affinity 48 $diskcpu
elif grep -q LS1024A /proc/cpuinfo; then
# Optimus with Linux 4.1
irq_affinity 24 $serialcpu # serial
irq_affinity 26 $serialcpu # i2c (NOR flash)
irq_affinity 27 $diskcpu
irq_affinity 28 $wificpu # ath9k
irq_affinity 29 $wificpu # ath10k
irq_affinity 94 $mocacpu
irq_affinity 96 $eth0cpu # *all* PFE
fi
}
get_moca_iface() {
# TODO(apenwarr): remove this once all devices use 'moca0' as the name.
if [ -e /sys/class/net/moca0 ]; then
# GFRG200
echo "moca0"
else
# GFMS100/GFHD100/GFHD200
echo "eth1"
fi
}
get_wifi_macaddr_param() {
local WIFI_MAC=$(hnvram -qr MAC_ADDR_WIFI)
if [ -z "$WIFI_MAC" ]; then
local MAC=$(hnvram -qr MAC_ADDR)
if [ -z "${MAC}" ]; then
echo "$0: WARNING: Box has no MAC_ADDR nor MAC_ADDR_WIFI" >&2
else
local WIFI_MAC=$(mac_addr_increment "${MAC}" 3)
fi
fi
if [ -n "$WIFI_MAC" ]; then
echo "wifi_addr=$WIFI_MAC"
fi
}
load_wifi_drivers() {
if [ "$(kernopt wifical)" != "1" ] && ! experiment SkipBluetoothWifi; then
# wifical=1 means Litepoint Wifi/Bluetooth calibration. We cannot load
# the production firmware at all, or it barfs.
# WARNING: Keep ath9k first, ath10k second, other wifi stuff later so that
# the wifi device ordering is constant.
modprobe -a ath9k ath10k_pci mwl8k 2>/dev/null
local mwifi_param=$(get_wifi_macaddr_param)
modprobe mwifiex $mwifi_param 2>/dev/null
modprobe -a mwifiex_sdio mwifiex_usb mwifiex_pcie ath9k_htc 2>/dev/null
# On GFRG250, the Quantenna PCIe module has not initialized by the time the
# kernel enumerates PCIe devices. For development, also include GFRG200 and
# GFRG210.
if contains "GFRG200 GFRG210 GFRG250" "$(cat /etc/platform)"; then
echo 1 > /sys/bus/pci/rescan
fi
if contains "GFHD254" "$(cat /etc/platform)" && ! startswith "$(uname -r)" "3"; then
echo 1 > /sys/bus/pci/devices/0000:01:00.0/remove
sleep 1
echo 1 > /sys/bus/pci/rescan
fi
modprobe qdpc-host 2>/dev/null
# Enable wifi beacon and fatal debug logging.
if [ -e /sys/module/ath9k/parameters/debug ]; then
echo 0x00004400 >/sys/module/ath9k/parameters/debug
fi
# Enable pktgen.
modprobe pktgen 2>/dev/null
fi
}
create_br0() {
echo -n "Creating bridge br0... "
brctl setfd br0 1
if is-ptp || experiment NoSTP; then
brctl stp br0 off
else
brctl stp br0 on
fi
# Storage and network boxes should have higher precedence (lower value)
# when choosing the root of the spanning tree.
# The default in Linux is 0x8000.
if is-network-box || is-windcharger; then
brctl setbridgeprio br0 0x7980
elif is-storage-box; then
brctl setbridgeprio br0 0x7990
fi
for i in lan0 eth0; do
[ -e /sys/class/net/$i/address ] && \
ip link set br0 address \
$(cat /sys/class/net/$i/address) && \
break
done
echo "done"
ip link set br0 up
ip link set br0 up # kernel 3.2.26 bug: fails the first time
}
create_br1() {
echo -n "Creating bridge br1... "
brctl setfd br1 1
brctl stp br1 off
echo "done"
ip link set br1 up
ip link set br1 up # kernel 3.2.26 bug: fails the first time
}
configure_moca_vlan() {
# VLAN tag for MoCA interface
ip link add link $MOCAIFC name $MOCAIFC.0 type vlan id 0
# SO_PRIORITY -> 802.1p mapping
for prio in 0 1 2 3 4 5 6 7; do
vconfig set_egress_map $MOCAIFC.0 $prio $prio >/dev/null 2>&1
done
}
add_interfaces_to_bridge() {
local bridge=$1
shift
echo "Adding interfaces to $bridge... "
# Move any existing network info from added network interfaces to the bridge.
# Only strictly needed for br0, when NFS booting; this prevents losing the
# NFS connection in the middle of the script.
for x in "$@"; do
[ -e "$x" ] || continue
local x="${x#/sys/class/net/}"
echo "Adding interface $x..."
ip link set $x up &&
ip -o -f inet addr show $x |
while read a b c ip d brd junk; do
ip addr add $ip broadcast $brd dev $bridge
done &&
if [ -n "$MOCAIFC" ] && [ $x = $MOCAIFC ]; then
x="${MOCAIFC}.0"
fi &&
brctl addif $bridge $x &&
ip -o -f inet route list dev $x |
while read dst routeinfo; do
ip route add dev $bridge $dst $routeinfo metric 1 &&
ip route del dev $x $dst $routeinfo
done &&
ip -o -f inet addr show $x |
while read a b c ip junk; do
ip addr del $ip dev $x
done
done
}
add_multicast_route() {
echo "Adding RFC2365 multicast route..."
ip route add 239.0.0.0/8 dev br0
kernopt ip |
while IFS=: read ip serverip gatewayip netmask hostname ifc junk; do
# $ip should be already setup by simpleramfs.
# TODO(apenwarr): simpleramfs should set up $gatewayip too.
# But right now its included networking commands are too limited.
if [ -n "$gatewayip" ]; then
echo "IP: adding default gateway '$gatewayip'"
if experiment BigInitRwnd; then
initrwnd='initrwnd 1000'
else
initrwnd=
fi
ip route add default via "$gatewayip" $initrwnd
fi
done
}
if_up_no_bridging() {
local dev="$1"
echo "Adding interface $dev..."
ip link set "$dev" up &&
kernopt ip |
while IFS=: read ip serverip gatewayip netmask hostname ifc junk; do
# $ip should be already setup by simpleramfs.
# TODO(apenwarr): simpleramfs should set up $gatewayip too.
# But right now its included networking commands are too limited.
if [ -n "$gatewayip" ]; then
echo "IP: adding default gateway '$gatewayip'"
ip route add default via "$gatewayip"
fi
done
echo "Bringing up interface $dev..."
ifup "$dev"
enable_rx_coalescing "$dev"
}
bridge_up() {
local br="$1"
echo "Bringing up the bridge $br..."
ip link set dev "$br" up # kernel 3.16 behavior, sometimes br0 does not come up.
ifup "$br"
}
enable_rx_coalescing() {
# Enable receive interrupt coalescing, this is a significant
# performance gain for multicast receive.
ethtool -C $1 rx-usecs 1000
}
enable_hw_offloads() {
# Enable hardware offloads, do this at the end to avoid
# invalid access caused by powered down core
ethtool -K $1 rx on tx on sg on gso on gro on
}
wan0_down() {
if [ -e /sys/class/net/wan0 ]; then
echo "Shutting down the WAN port..."
ifdown wan0
ifdown wan0.2
ip link del wan0.2
fi
}
bridge_down() {
local br="$1"
if [ -n /sys/class/net/$br/bridge ]; then
ifdown $br
echo "Shutting down $br interface"
fi
for x in $(ls /sys/class/net); do
if [ -e /sys/class/net/$x/device ]; then
brctl delif $br $x
fi
done
ifdown $br
[ -e /sys/class/net/$br ] && brctl delbr $br
}
# encode a string as base64
encode()
{
python -c "import base64; print base64.b64encode('$1')"
}
add_firewall_rules_to_vlan_input() {
if [ -e /sys/class/net/sw0.peer ]; then
# open ports for peer to peer configuration control
ip46tables -A vlan-input -i sw0.peer -p tcp --dport 80 -j ACCEPT
ip46tables -A vlan-input -i sw0.peer -p tcp --dport 443 -j ACCEPT
# Open ports used by macsecd for peer communication.
ip46tables -A vlan-input -i sw0.peer -p tcp --dport 50000 -j ACCEPT
ip46tables -A vlan-input -i sw0.peer -p tcp --dport 50001 -j ACCEPT
fi
}
setup_tcp_congestion_control() {
# load all algorithms we may want to use
modprobe -a tcp_acubic tcp_turbulent tcp_transonic
# make all "available" algorithms "allowed" so any process can use it
cat /proc/sys/net/ipv4/tcp_available_congestion_control \
>/proc/sys/net/ipv4/tcp_allowed_congestion_control
# log
echo -n "tcp_allowed_congestion_control="
cat /proc/sys/net/ipv4/tcp_allowed_congestion_control
}
case "$1" in
start)
if is-fiberjack; then
lan_port=$(cat /etc/config/lanport)
echo "Starting LAN."
ifup lo
if [ -n "$lan_port" ]; then
ifup $lan_port
fi
exit 0
fi
if is-moca-present; then
MOCAIFC=$(get_moca_iface)
fi
if ! is-spacecast && ! is-ptp; then
load_wifi_drivers
fi
setup_tcp_congestion_control
echo 1 >/proc/sys/net/ipv4/conf/all/arp_ignore
# Create a default resolv.conf and /etc/hosts in case DHCP doesn't.
# (this is always true if using nfsroot).
# 8.8.8.8 and 8.8.4.4 are well-known IPv4 Google public DNS servers
# that can be used from anywhere, so it makes a good place to start.
# 2001:4860:4860::8888 is one of the two IPv6 Google public DNS servers
# (the other being 2001:4860:4860::8844).
# DHCP will just overwrite this file when it's ready to go.
if [ ! -r /etc/resolv.conf ]; then
# Note: uClibc only reads the first three nameserver entries.
(echo 'nameserver 8.8.8.8';
echo 'nameserver 8.8.4.4';
echo 'nameserver 2001:4860:4860::8888') >/etc/resolv.conf
fi
if [ ! -r /etc/hosts ]; then
echo "127.0.0.1 localhost $(hostname)" >/etc/hosts
fi
# Configure dhclient with the right hostname etc.
setup-dhclient
# Configure loopback
ifup lo
# Quantenna-specific initialization.
if interface_exists quantenna; then
ip link set dev quantenna up
i=0
while true; do
if ! interface_exists wlan"$i"; then
echo "add wlan$i 3" >/sys/class/net/quantenna/vlan
break
fi
i=$((i+1))
done
fi
# GFRG2X0 sets lan0, wan0, and moca0 in pfe kernel module
# from addrs passed on command line from barebox
if is-ptp; then
# set defaults
ptp-config -d craft_ipaddr 192.168.1.1/24
ptp-config -d vlan_inband 4091
ptp-config -d vlan_ooband 50
ptp-config -d vlan_peer 60
# TODO(edjames) default should depend on hi/lo radio model
ptp-config -d local_ipaddr 192.168.2.1/24
ptp-config -d peer_ipaddr 192.168.2.2/24
ptp-config -d password_admin $(encode admin)
ptp-config -d password_guest $(encode guest)
# mac addrs
set_mac_from_hnvram craft0 MAC_ADDR
set_mac_from_hnvram sw0 MAC_ADDR_WAN
# craft0 (static ip for UI)
ptp-config -i craft_ipaddr
if_up_no_bridging craft0
# bring up inband vlan (will dhcp)
ptp-config -i vlan_inband
# no if_up_no_bridging, inband is in br0
# bring up ooband vlan (will dhcp)
ptp-config -i vlan_ooband
if_up_no_bridging sw0.ooband
# bring up peer vlan, set our static ip
ptp-config -i vlan_peer
ptp-config -i local_ipaddr
if_up_no_bridging sw0.peer
add_firewall_rules_to_vlan_input
fi
if is-spacecast; then
if_up_no_bridging lan0
(nohup /sbin/lan0_watchdog 2>&1 > /dev/null) &
else
# br0 bridges Ethernet, MoCA, and WiFi AP interfaces
create_br0
# br1 only bridges captive portal WiFi interfaces
create_br1
if is-moca-present; then
configure_moca_vlan
fi
add_interfaces_to_bridge br0 \
/sys/class/net/[ea]th[0-9] \
/sys/class/net/*.inband \
/sys/class/net/lan[0-9] \
/sys/class/net/moca[0-9] \
/sys/class/net/wlan[0-9]
add_multicast_route
bridge_up br0
bridge_up br1
redistribute_irqs
fi
if is-moca-present; then
echo "starting moca..."
babysit 30 runmoca 2>&1 | logos mocad &
if experiment MocaFlowControl; then
moca-flowctl --enable
fi
fi
if [ -e /sys/class/net/wan0 ]; then
echo "Bringing up the WAN port..."
ip link add link wan0 name wan0.2 type vlan id 2
sysctl net.ipv4.conf.all.forwarding=1
sysctl net.ipv6.conf.all.forwarding=1
sysctl net.ipv6.conf.wan0.accept_ra=2
sysctl net.ipv6.conf.wan0/2.accept_ra=2
ifup wan0
ifup wan0.2
# set the class priority to 802.1p bit mapping. We don't want
# pbit=0,1 ever, so force into 2.
vconfig set_egress_map wan0.2 0 2
vconfig set_egress_map wan0.2 1 2
for prio in 2 3 4 5 6 7; do
vconfig set_egress_map wan0.2 $prio $prio >/dev/null 2>&1
done
# Enable receive interrupt coalescing, this is a significant
# performance gain for multicast receive.
enable_rx_coalescing wan0
fi
if is-tv-box || is-storage-box; then
# Enable hardware offloads, do this at the end to avoid
# invalid access caused by powered down core
enable_hw_offloads eth0
if is-moca-present; then
enable_hw_offloads $MOCAIFC
fi
fi
if is-tv-box && experiment TVBoxNoGigEthernet; then
# advertise only 10 & 100 at half and full duplex.
ethtool -s eth0 advertise 0xf
fi
if is-storage-box && experiment TcpWmem1Meg; then
# Values from GFRG210, applied to all Storage Boxes.
echo "4096 16384 1019904" >/proc/sys/net/ipv4/tcp_wmem
fi
if experiment AggressiveTCP; then
# technically only needed for server
echo 1 >/proc/sys/net/ipv4/tcp_thin_linear_timeouts
echo 1 >/proc/sys/net/ipv4/tcp_thin_dupack
if [ -e "/proc/sys/net/ipv4/tcp_min_rtt_wlen" ]; then
# Only on more recent kernels
echo 10 >/proc/sys/net/ipv4/tcp_min_rtt_wlen
echo 4 >/proc/sys/net/ipv4/tcp_early_retrans
fi
# technically only needed for client
echo 0 >/proc/sys/net/ipv4/tcp_moderate_rcvbuf
fi
if experiment BigSocketBuffers; then
# technically only rbuf increase needed on receiver, and only wbuf
# on sender, but for simplicity just do it everywhere for now.
n=8000000
echo $n $n $n | tee /proc/sys/net/ipv4/tcp_?mem >/dev/null
echo $n | tee /proc/sys/net/core/?mem_* >/dev/null
fi
;;
stop)
if [ ! -e /tmp/NFS ]; then
if is-fiberjack; then
lan_port=$(cat /etc/config/lanport)
echo "Stopping LAN."
ifdown lo
if [ -n "$lan_port" ]; then
ifdown $lan_port
fi
exit 0
fi
if is-spacecast; then
ifdown lan0
echo "Shutting down lan0 interface"
else
wan0_down
bridge_down br0
bridge_down br1
fi
# Kill mocad and mocactl
if [ -e /dev/bmoca0 ]; then
echo -n "mocacfg kill"
pkillwait mocad
fi
fi
exit 0
;;
restart|reload)
"$0" stop
"$0" start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac