You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
396 lines
12 KiB
Bash
396 lines
12 KiB
Bash
4 years ago
|
#!/bin/sh
|
||
|
# Copyright (c) 2016 Qualcomm Atheros, Inc.
|
||
|
#
|
||
|
# All Rights Reserved.
|
||
|
# Qualcomm Atheros Confidential and Proprietary.
|
||
|
|
||
|
. /usr/share/libubox/jshn.sh
|
||
|
. /lib/functions/repacd-netdet.sh
|
||
|
|
||
|
LP_DIRECTION_UPSTREAM="upstream"
|
||
|
LP_DIRECTION_DOWNSTREAM="downstream"
|
||
|
LP_DIRECTION_UNKNOWN="unknown"
|
||
|
LP_ROLE_CAP="CAP"
|
||
|
LP_ROLE_RE="RE"
|
||
|
LP_VLAN_OFFSET=10
|
||
|
|
||
|
LP_DIRECTION_DB="/etc/ports.dir"
|
||
|
|
||
|
EDMA_ETH0_PORTBMP="/proc/sys/net/edma/default_group1_bmp"
|
||
|
EDMA_ETH1_PORTBMP="/proc/sys/net/edma/default_group2_bmp"
|
||
|
|
||
|
#TODO - these values need to be determined by board
|
||
|
#Port number of the port in the eth0 vlan by default
|
||
|
LP_ETH0_PORT=5
|
||
|
#Port number of the cpu port including the "t" for tagging if appropriate
|
||
|
LP_CPU_PORT="0t"
|
||
|
|
||
|
#TODO - these should probably be configurable from outside ths script
|
||
|
#Timeout for dhcp requests from CA
|
||
|
LP_DHCP_TO_CAP=15
|
||
|
#Timeout for dhcp requests from RE (needs to be longer than from CA)
|
||
|
LP_DHCP_TO_RE=30
|
||
|
|
||
|
__lp_loginfo() {
|
||
|
logger -t repacd.lp -p user.info "$1"
|
||
|
}
|
||
|
|
||
|
__lp_logdebug() {
|
||
|
logger -t repacd.lp -p user.debug "$1"
|
||
|
}
|
||
|
|
||
|
#Returns the default interface for the given port
|
||
|
lp_defaultinterface() {
|
||
|
if [ $port = $LP_ETH0_PORT ]; then
|
||
|
echo "eth0"
|
||
|
else
|
||
|
echo "eth1"
|
||
|
fi
|
||
|
}
|
||
|
#Returns the isolated inteface name for a given port
|
||
|
lp_interfacebyport() {
|
||
|
local port=$1
|
||
|
local baseinterface=$(lp_defaultinterface $port)
|
||
|
local interface="${baseinterface}.$(( $port + $LP_VLAN_OFFSET ))"
|
||
|
echo $interface
|
||
|
}
|
||
|
|
||
|
#Returns the role of the device, either "CAP" or "RE"
|
||
|
lp_devicerole() {
|
||
|
#A CAP should have an entry for network.wan.ifname, an RE should not
|
||
|
uci get network.wan.ifname >/dev/null
|
||
|
if [ $? = 0 ]; then
|
||
|
echo $LP_ROLE_CAP
|
||
|
else
|
||
|
echo $LP_ROLE_RE
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
#Returns the determined direction (upstream, downstram, or unknown) for the
|
||
|
#given port
|
||
|
lp_getportdirection() {
|
||
|
local port=$1
|
||
|
local direction=$LP_DIRECTION_UNKNOWN
|
||
|
if [ -f $LP_DIRECTION_DB ]; then
|
||
|
json_load "$(cat $LP_DIRECTION_DB)"
|
||
|
json_select "port" >/dev/null
|
||
|
json_get_var direction $port
|
||
|
fi
|
||
|
|
||
|
echo $direction
|
||
|
}
|
||
|
|
||
|
#set the current direction (upstream, downstream, or unknown) in a
|
||
|
#persistent db
|
||
|
lp_setportdb() {
|
||
|
local port=$1
|
||
|
local direction=$2
|
||
|
local current
|
||
|
local new
|
||
|
local nports=$(lp_numports)
|
||
|
local dir
|
||
|
|
||
|
if [ -f $LP_DIRECTION_DB ]; then
|
||
|
current=$(cat $LP_DIRECTION_DB)
|
||
|
else
|
||
|
current="{}"
|
||
|
fi
|
||
|
json_init
|
||
|
json_add_array "port"
|
||
|
new=$(json_dump)
|
||
|
for p in $(seq 1 $nports); do
|
||
|
if [ $p = $port ]; then
|
||
|
dir=$direction
|
||
|
else
|
||
|
json_load "$current"
|
||
|
dir=$LP_DIRECTION_UNKNOWN
|
||
|
json_select "port" >/dev/null
|
||
|
json_get_var dir $p
|
||
|
fi
|
||
|
json_load "$new"
|
||
|
json_select "port"
|
||
|
json_add_string $p $dir
|
||
|
new=$(json_dump)
|
||
|
done
|
||
|
json_close_array
|
||
|
new=$(json_dump)
|
||
|
|
||
|
local tmpfile="$(dirname $LP_DIRECTION_DB)/.$(basename $LP_DIRECTION_DB)"
|
||
|
echo "$new" > $tmpfile
|
||
|
mv $tmpfile $LP_DIRECTION_DB
|
||
|
}
|
||
|
|
||
|
#Returns the current number of ports which are marked upstream
|
||
|
lp_numupstream() {
|
||
|
local nup=0
|
||
|
local dir
|
||
|
local nports=$(lp_numports)
|
||
|
|
||
|
if [ -f $LP_DIRECTION_DB ]; then
|
||
|
json_load "$(cat $LP_DIRECTION_DB)"
|
||
|
json_select "port" >/dev/null
|
||
|
for p in $(seq 1 $nports); do
|
||
|
dir=$LP_DIRECTION_UNKNOWN
|
||
|
json_get_var dir $p
|
||
|
if [ $dir = $LP_DIRECTION_UPSTREAM ]; then
|
||
|
nup=$(( nup + 1 ))
|
||
|
fi
|
||
|
done
|
||
|
fi
|
||
|
echo $nup
|
||
|
}
|
||
|
|
||
|
|
||
|
#Returns the number of ethernet ports on switch0
|
||
|
lp_numports() {
|
||
|
local lines=$(swconfig dev switch0 show | grep ports | wc -l)
|
||
|
local words=$(swconfig dev switch0 show | grep ports | wc -w)
|
||
|
|
||
|
echo $(( (( $words - $lines )) - $lines ))
|
||
|
}
|
||
|
|
||
|
#Determines whether the given interface is upstream or downstream
|
||
|
lp_determinedirection() {
|
||
|
|
||
|
local port=$1
|
||
|
#If netdet has already determined that this is a CAP device
|
||
|
#then we will already have an upstream connection, and all
|
||
|
#subsequent connections (including this one) should be
|
||
|
#considered downstream
|
||
|
local netdetmode=$(netdet_get_mode_db)
|
||
|
local upstrmports=$(lp_numupstream)
|
||
|
local portdirection=$(lp_getportdirection $port)
|
||
|
|
||
|
logger -t repacd.lp -p user.debug "netdetmode: $netdetmode"
|
||
|
logger -t repacd.lp -p user.debug "upstrmports: $upstrmports"
|
||
|
if [ $netdetmode = "cap" ] && [ $upstrmports -gt 0 ] && [ $portdirection != $LP_DIRECTION_UPSTREAM ]; then
|
||
|
logger -t repacd.lp -p user.info "Port $port assumed downstream on cap"
|
||
|
echo $LP_DIRECTION_DOWNSTREAM
|
||
|
else
|
||
|
local role=$2
|
||
|
local iface=$(lp_interfacebyport $port)
|
||
|
local timeout
|
||
|
if [ $role = $LP_ROLE_CAP ]; then
|
||
|
timeout=$LP_DHCP_TO_CAP
|
||
|
else
|
||
|
timeout=$LP_DHCP_TO_RE
|
||
|
fi
|
||
|
|
||
|
if udhcpc -i $iface -t $timeout -T1 -n -q -R > /dev/null 2>&1; then
|
||
|
__lp_loginfo "Port $port determined upstream"
|
||
|
echo $LP_DIRECTION_UPSTREAM
|
||
|
else
|
||
|
__lp_loginfo "Port $port determined downstream"
|
||
|
echo $LP_DIRECTION_DOWNSTREAM
|
||
|
fi
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
#Isolate port in its own vlan and create virtual interface
|
||
|
lp_isolateport() {
|
||
|
local port=$1
|
||
|
local isovlan=$(( $port + $LP_VLAN_OFFSET ))
|
||
|
local currvlan=$(swconfig dev switch0 port $port get pvid)
|
||
|
local currports=$(swconfig dev switch0 vlan $currvlan show | grep ports | cut -d: -f2)
|
||
|
local newports=""
|
||
|
|
||
|
__lp_loginfo "Isolating switch port $port into its own vlan"
|
||
|
#remove port from its current vlan
|
||
|
for p in $currports; do
|
||
|
if [ $p != $port ]; then
|
||
|
newports="$newports $p"
|
||
|
fi
|
||
|
done
|
||
|
__lp_logdebug "swconfig dev switch0 vlan $currvlan set ports \"$LP_CPU_PORT $newports\""
|
||
|
swconfig dev switch0 vlan $currvlan set ports "$LP_CPU_PORT $newports"
|
||
|
|
||
|
#add port to isovlan
|
||
|
currports=$(swconfig dev switch0 vlan $isovlan show | grep ports | cut -d: -f2)
|
||
|
__lp_logdebug "swconfig dev switch0 vlan $isovlan set ports \"$LP_CPU_PORT $currports $port\""
|
||
|
swconfig dev switch0 vlan $isovlan set ports "$LP_CPU_PORT $currports $port"
|
||
|
__lp_logdebug "swconfig dev switch0 set apply"
|
||
|
swconfig dev switch0 set apply
|
||
|
|
||
|
if [ $port = $LP_ETH0_PORT ]; then
|
||
|
__lp_logdebug "vconfig add eth0 $isovlan"
|
||
|
vconfig add eth0 $isovlan
|
||
|
else
|
||
|
__lp_logdebug "vconfig add eth1 $isovlan"
|
||
|
vconfig add eth1 $isovlan
|
||
|
fi
|
||
|
lp_setedmamasks $port $(lp_defaultinterface $port)
|
||
|
}
|
||
|
|
||
|
lp_deisolateport() {
|
||
|
local port=$1
|
||
|
local isovlan=$(( $port + $LP_VLAN_OFFSET ))
|
||
|
local currvlan=$(swconfig dev switch0 port $port get pvid)
|
||
|
|
||
|
if [ $isovlan = $currvlan ]; then
|
||
|
#This check might not be necessary, but it prevents us from
|
||
|
#manipulating a port which is not isolated
|
||
|
|
||
|
local isoiface=$(lp_interfacebyport $port)
|
||
|
local unisovlan
|
||
|
|
||
|
#Remove port form the isolated vlan
|
||
|
swconfig dev switch0 vlan $isovlan set ports ""
|
||
|
#Remove virtual interface
|
||
|
vconfig rem $isoiface
|
||
|
#put port back in the appropriate eth0 or eth1 vlan
|
||
|
if [ $port = $LP_ETH0_PORT ]; then
|
||
|
unisovlan=2
|
||
|
else
|
||
|
unisovlan=1
|
||
|
fi
|
||
|
|
||
|
local currports=$(swconfig dev switch0 vlan $unisovlan show | grep ports | cut -d: -f2)
|
||
|
swconfig dev switch0 vlan $unisovlan set ports "$currports $port"
|
||
|
swconfig dev switch0 set apply
|
||
|
fi
|
||
|
}
|
||
|
|
||
|
#set the edma masks so the bitmap for the given iface (eth0 or eth1)
|
||
|
#contains the given port, and the bitmask fot the other iface does not
|
||
|
lp_setedmamasks() {
|
||
|
local port=$1
|
||
|
local dest_iface=$2
|
||
|
local currmask_eth0=$(cat $EDMA_ETH0_PORTBMP)
|
||
|
local currmask_eth1=$(cat $EDMA_ETH1_PORTBMP)
|
||
|
local newmask_eth0
|
||
|
local newmask_eth1
|
||
|
|
||
|
if [ $dest_iface = "eth0" ]; then
|
||
|
newmask_eth0=$(( $currmask_eth0 | (1 << $port) ))
|
||
|
newmask_eth1=$(( $currmask_eth1 & ~(1 << $port) ))
|
||
|
elif [ $dest_iface = "eth1" ]; then
|
||
|
newmask_eth0=$(( $currmask_eth0 & ~(1 << $port) ))
|
||
|
newmask_eth1=$(( $currmask_eth1 | (1 << $port) ))
|
||
|
else
|
||
|
#should not get here, but if we do do not adjust either bitmap
|
||
|
newmask_eth0=$currmask_eth0
|
||
|
newmask_eth1=$currmask_eth1
|
||
|
fi
|
||
|
|
||
|
printf "0x%x" $newmask_eth0 > $EDMA_ETH0_PORTBMP
|
||
|
printf "0x%x" $newmask_eth1 > $EDMA_ETH1_PORTBMP
|
||
|
}
|
||
|
|
||
|
#moves the given port to the eth0 vlan (2) or the eth1 vlan (1)
|
||
|
#and removes it from the other via swconfig
|
||
|
lp_moveportswconfig() {
|
||
|
local port=$1
|
||
|
local dest_iface=$2
|
||
|
local removefromvlan
|
||
|
local addtovlan
|
||
|
local isovlan=$(( $port + $LP_VLAN_OFFSET ))
|
||
|
local isoiface=$(lp_interfacebyport $port)
|
||
|
|
||
|
if [ $dest_iface = "eth0" ]; then
|
||
|
removefromvlan=1
|
||
|
addtovlan=2
|
||
|
elif [ $dest_iface = "eth1" ]; then
|
||
|
removefromvlan=2
|
||
|
addtovlan=1
|
||
|
else
|
||
|
#should not get here, but if we do do not move port
|
||
|
removefromvlan=3
|
||
|
addtovlan=3
|
||
|
fi
|
||
|
|
||
|
local currports=$(swconfig dev switch0 vlan $removefromvlan show | grep ports | cut -d: -f2)
|
||
|
local newports
|
||
|
for p in $currports; do
|
||
|
if [ $p != $port ]; then
|
||
|
newports="$newports $p"
|
||
|
fi
|
||
|
done
|
||
|
__lp_logdebug "swconfig dev switch0 vlan $removefromvlan set ports $newports"
|
||
|
swconfig dev switch0 vlan $removefromvlan set ports $newports
|
||
|
|
||
|
currports=$(swconfig dev switch0 vlan $addtovlan show | grep ports | cut -d: -f2)
|
||
|
__lp_logdebug "swconfig dev switch0 vlan $addtovlan set ports \"$currports $port\""
|
||
|
swconfig dev switch0 vlan $addtovlan set ports "$currports $port"
|
||
|
|
||
|
#eliminate the isolation vlan and virtual interface
|
||
|
__lp_logdebug "swconfig dev switch0 vlan $isovlan set ports \"\""
|
||
|
swconfig dev switch0 vlan $isovlan set ports ""
|
||
|
__lp_logdebug "vconfig rem $isoiface"
|
||
|
vconfig rem $isoiface
|
||
|
|
||
|
__lp_logdebug "swconfig dev switch0 set apply"
|
||
|
swconfig dev switch0 set apply
|
||
|
}
|
||
|
|
||
|
|
||
|
#Move the given port to the eth0 vlan
|
||
|
lp_moveporttoeth0() {
|
||
|
local port=$1
|
||
|
__lp_loginfo "Moving switch port $port into the eth0 vlan"
|
||
|
lp_moveportswconfig $port "eth0"
|
||
|
lp_setedmamasks $port "eth0"
|
||
|
}
|
||
|
|
||
|
#Move the given port to the eth1 vlan
|
||
|
lp_moveporttoeth1() {
|
||
|
local port=$1
|
||
|
__lp_loginfo "Moving switch port $port into the eth1 vlan"
|
||
|
lp_moveportswconfig $port "eth1"
|
||
|
lp_setedmamasks $port "eth1"
|
||
|
}
|
||
|
|
||
|
|
||
|
#Make the hotplug call to signal the direction has been determined for
|
||
|
#the given port
|
||
|
lp_signaldirectionhotplug() {
|
||
|
local port=$1
|
||
|
local direction=$2
|
||
|
(export PORT=$port; export EVENT="direction"; export STATE=$direction; hotplug-call switch)
|
||
|
}
|
||
|
|
||
|
#Called by hotplug whenever a port transtions to link-up status
|
||
|
lp_onlinkup() {
|
||
|
local port=$1
|
||
|
local role=$(lp_devicerole)
|
||
|
local direction
|
||
|
local current_direction=$(lp_getportdirection $port)
|
||
|
|
||
|
logger -t repacd.lp -p user.debug "did we miss a down notification for port $port? current_direction: $current_direction"
|
||
|
if [ $current_direction != $LP_DIRECTION_UNKNOWN ]; then
|
||
|
logger -t repacd.lp -p user.debug "we missed a down notification for port $port so act like we didn't"
|
||
|
lp_onlinkdown $port
|
||
|
fi
|
||
|
direction=$(lp_determinedirection $port $role)
|
||
|
lp_signaldirectionhotplug $port $direction
|
||
|
}
|
||
|
|
||
|
#Called by hotplug whenever a port transtions to link-down status
|
||
|
lp_onlinkdown() {
|
||
|
local port=$1
|
||
|
lp_setportdb $port $LP_DIRECTION_UNKNOWN
|
||
|
#isolate port back into its own iface
|
||
|
lp_isolateport $port
|
||
|
}
|
||
|
|
||
|
#Called by hotplug whenever a port direction has been determined upstream
|
||
|
lp_onupstream() {
|
||
|
local port=$1
|
||
|
lp_setportdb $port $LP_DIRECTION_UPSTREAM
|
||
|
lp_moveporttoeth0 $port
|
||
|
}
|
||
|
|
||
|
#Called by hotplug whenever a port direction has been determined downstream
|
||
|
lp_ondownstream() {
|
||
|
local port=$1
|
||
|
lp_setportdb $port $LP_DIRECTION_DOWNSTREAM
|
||
|
lp_moveporttoeth1 $port
|
||
|
}
|
||
|
|
||
|
repacd_lp_init() {
|
||
|
local nports=$(lp_numports)
|
||
|
for p in $(seq 1 $nports); do
|
||
|
lp_isolateport $p
|
||
|
lp_setportdb $p $LP_DIRECTION_UNKNOWN
|
||
|
done
|
||
|
}
|