map-agent: traffic separation script rework

This commit is contained in:
Stanislaw Gruszka 2022-05-16 06:17:22 +02:00 committed by Jakob Olsson
parent 6ce65b0160
commit 65edb4ab06
2 changed files with 123 additions and 432 deletions

View file

@ -2,6 +2,9 @@
. /lib/functions.sh
AL_BRIDGE=${AL_BRIDGE-"br-lan"}
PRIMARY_VID=${PRIMARY_VID-1}
### Traffic Separation ###
dbg() {
@ -9,456 +12,150 @@ dbg() {
}
ts_sub() {
ts_usage() {
cat <<EOF
Usage: $0 [create|delete|populate|primary|reload]
Usage: $0 [create|reload]
Traffic Separation related functions.
create fh <iface> <vid> - create vlan device and rules for wifi fronthaul
create bh <iface> <vid> <profile> - create vlan device and rules for wifi backhaul
create eth <iface> <vid> <pbits> - create vlan device and rules for logical ethernet interface
delete <iface> - delete vlan device
populate eth <iface> <vid> - add secondary network rules for logical ethernet interface
primary get <iface> - read primary VID for interface from driver (from Association Response frame IE)
reload - reload network with new configuration
create vid - create vlan configuration with vlan_id
reload - reload network with new configuration
EOF
exit 1
}
_get_bridge() {
local bridge=$(ip link show $1 | grep -o "master [^\s]*" | cut -d ' ' -f 2)
echo $bridge
}
ts_create() {
_net_setup() {
local name=$1
local vid=$2
local proto=$3
local dev=$4
local port_dev=$5
set_wireless_bridge() {
config_load wireless
[ -z "$(uci -q get network.${name})" ] || return
_set_network() {
local sec=$1
local iface=$2
local bridge=$3
local ip_addr="192.168.${vid}.1"
local br_dev="${AL_BRIDGE/-/_}"
local tag=":t"
config_get ifname $sec ifname
[ "$iface" != "$ifname" ] && continue
[ "${vid}" = "${PRIMARY_VID}" ] && {
tag=""
config_get mode $sec mode
config_get multi_ap $sec multi_ap "0"
[ "$mode" = "sta" -a "$multi_ap" = "1" ] && continue
# Global options
[ -z "$(uci -q get network.${br_dev}.vlan_filtering)" ] && {
uci -q set network.${br_dev}.vlan_filtering=1;
}
config_get network $sec network
local new_network=${bridge##br-}
if [ "$new_network" != "$network" ] ; then
uci -q set wireless.${sec}.network=${new_network}
uci commit wireless
uci -q delete network.lan.proto
uci -q delete network.lan.ipaddr
uci -q delete network.lan.netmask
uci -q delete network.lan.ip6assign
}
uci -q set network.${name}="interface"
uci -q set network.${name}.device="$dev"
uci -q set network.${name}.is_lan="1"
if [ "$proto" = "static" ] ; then
uci -q set network.${name}.proto="static"
# TODO vid > 255
uci -q set network.${name}.ipaddr="${ip_addr}"
uci -q set network.${name}.netmask="255.255.255.0"
uci -q set network.${name}.ip6assign '60'
else
uci -q set network.${name}.proto="dhcp"
fi
brctl addif $bridge $iface &> /dev/null
}
uci -q add network bridge-vlan
uci -q set network.@bridge-vlan[-1].device="$AL_BRIDGE"
uci -q set network.@bridge-vlan[-1].vlan="$vid"
config_foreach _set_network wifi-iface ${1} ${2}
}
ts_create() {
_create_vlan_dev() {
iface=$1 # real iface
vid=$2 # Vlan ID
bridge=$3 # bridge iface should be connected
vlan_dev=$4
old_bridge="$(_get_bridge $iface)" # bridge iface is connected to
# remove interface from bridge if it is in one
[ -n "$old_bridge" ] && brctl delif $old_bridge $iface &> /dev/null
# (re)create vlan device
ip link show $vlan_dev && vlanctl --if-delete $vlan_dev
vlanctl --mcast --if-create-name $iface $vlan_dev --if $iface --set-if-mode-rg
vlanctl --if $iface --tx --tags 0 --default-miss-drop
vlanctl --if $iface --tx --tags 1 --default-miss-drop
vlanctl --if $iface --tx --tags 2 --default-miss-drop
vlanctl --if $iface --rx --tags 0 --default-miss-drop
vlanctl --if $iface --rx --tags 1 --default-miss-drop
vlanctl --if $iface --rx --tags 2 --default-miss-drop
# bring the vlan device up and add back to bridge if it was in one
brctl addif $bridge $vlan_dev &> /dev/null
}
ts_create_fh() {
iface=$1 # fh iface
vid=$2 # SSID specific (secondary) or primary vid
bridge=$3
[ -n "$iface" ] && [ -n "$vid" ] && [ -n "$bridge" ] || {
cat <<EOF
Adding FH device requires IFACE, VID and bridge
EOF
exit 1
}
# create vlan device
#set_wireless_bridge $iface $bridge
vlan_dev=${iface}_vlan${vid}
ip link set $vlan_dev down
_create_vlan_dev $iface $vid $bridge $vlan_dev
# add rules
# vlanctl --if $iface --rx --tags 0 --filter-ethertype 0x886c --set-rxif $vlan_dev --rule-append # incoming brcm
# EAPOL frames
vlanctl --if $iface --rx --tags 0 --filter-ethertype 34958 --set-rxif $vlan_dev --rule-append
vlanctl --if $iface --rx --tags 1 --filter-ethertype 34958 --pop-tag --set-rxif $vlan_dev --rule-append
vlanctl --if $iface --tx --tags 0 --filter-txif $vlan_dev --filter-ethertype 34958 --rule-append
# 8021q vlan id TAG/UNTAG
vlanctl --if $iface --rx --tags 0 --set-rxif $vlan_dev --push-tag --set-vid $vid 0 --rule-append
vlanctl --if $iface --tx --tags 1 --filter-txif $vlan_dev --filter-vid $vid 0 --pop-tag --dscp2pbits 0 --rule-append
ip link set $iface up
ip link set $vlan_dev up
}
ts_create_bh() {
iface=$1 # bh iface
vid=$2 # primary vid
profile=$3 # agent profile (1 or 2)
bridge=$4 # bridge interface should be connected to
[ -n "$iface" ] && [ -n "$vid" ] && [ -n "$profile" ] || {
cat <<EOF
Adding BH device requires IFACE, VID and PROFILE (1 or 2).
EOF
exit 1
}
#[ -n "$bridge" ] && set_wireless_bridge $iface $bridge
old_vid=$(wl -i $1 map_8021q_settings)
old_vid=${old_vid##* }
old_profile=$(wl -i $1 map_profile | cut -d ' ' -f 3)
[ "$old_vid" = "$vid" -a "$old_profile" = "$profile" ] && return
wl vlan_mode 0 &> /dev/null # make sure this is OFF, else driver won't handle vlan
wl -i $iface down &> /dev/null
wl -i $iface map_profile $profile &> /dev/null # only has effect on profile 2
wl -i $iface map_8021q_settings $vid &> /dev/null # can only be set on bBSS (read-only on bSTA)
wl -i $iface up &> /dev/null
}
ts_create_lei() {
vid=$1 # primary vid
pbits=$2 # default pbits to apply
vlan_bridge=$3 # name of ts subsystem bridge
lan_bridge=$4 # name of node local bridge
[ -n "$vid" ] && [ -n "$pbits" ] && [ -n "$vlan_bridge" ] && [ -n "$lan_bridge" ] || {
cat <<EOF
Adding ETH device requires IFACE, VID, PBITS and name of vlan and lan bridges.
EOF
exit 1
}
ip link show lei &> /dev/null || {
ip link add link lei name lei_lan type vlan id 1 2>/dev/null
}
old_vid=$(ip -d link show lei_lan | sed -n 's/vlan.*id \([0-9][0-9]*\) .*/\1/p')
[ "$old_vid" != "$vid" ] && {
ip link del lei_lan
ip link add link lei name lei_lan type vlan id ${vid}
}
brctl addif ${lan_bridge} lei_lan &>/dev/null
brctl addif ${vlan_bridge} lei_map &>/dev/null
ip link set lei up
ip link set lei_map up
ip link set lei_lan up
}
_create_eth() {
iface=$1 # Multi-AP Logical Ethernet Interface
vid=$2 # primary vid
bridge=$3 # name of ts subsystem bridge
pbits=0
[ -n "$iface" ] && [ -n "$vid" ] && [ -n "$bridge" ] || {
cat <<EOF
Adding ETH device requires IFACE, VID, PBITS and name of vlan and lan bridges.
EOF
exit 1
}
dbg create $@
ip link set $iface down
vlan_dev=${iface}_vlan${vid}
ip link set $vlan_dev down
_create_vlan_dev $iface $vid $bridge $vlan_dev
vlanctl --if $iface --rx --tags 0 --set-rxif $vlan_dev --push-tag --set-vid $vid 0 --set-pbits $pbits 0 --rule-append
vlanctl --if $iface --tx --tags 1 --filter-vid $vid 0 --filter-txif $vlan_dev --pop-tag --rule-append
[ $# -le 3 ] && exit 0
shift 3
while [ -n "$1" ] ; do
vid=$1
vlanctl --if $iface --rx --tags 1 --filter-vid $vid 0 --set-rxif $vlan_dev --rule-append
vlanctl --if $iface --tx --tags 1 --filter-vid $vid 0 --filter-txif $vlan_dev --rule-append
shift
for port in $(uci -q get network.${br_dev}.ports) ; do
echo $port | grep -q eth || continue
uci -q add_list network.@bridge-vlan[-1].ports="${port}${tag}"
done
ip link set $iface up
ip link set $vlan_dev up
uci -q add_list network.${br_dev}.ports="$port_dev"
uci -q add_list network.@bridge-vlan[-1].ports="$port_dev"
uci -q commit network
}
ts_create_eths() {
pvid=$1 # primary vid
bridge=$2 # name of ts subsystem bridge
_dhcp_setup() {
local name=$1
shift 2
# TODO use ieee1905 bridge
for iface in $(uci get network.br_lan.ports) ; do
[ "$iface" = "lei_lan" ] && continue
_create_eth $iface $pvid $bridge $@
ubus call ieee1905 del_interface "{\"ifname\":\"$iface\"}"
done
[ -n "$(uci -q get dhcp.${name})" ] && return
uci -q set dhcp.${name}=dhcp
uci -q set dhcp.${name}.interface="${name}"
uci -q set dhcp.${name}.start="100"
uci -q set dhcp.${name}.limit="150"
uci -q set dhcp.${name}.leasetime="1h"
uci -q set dhcp.${name}.dhcpv4="server"
uci -q set dhcp.${name}.dhcpv6="server"
uci -q set dhcp.${name}.ra="server"
uci -q set dhcp.${name}.ra_slaac="1"
uci -q add_list dhcp.${name}.ra_flags="managed-config"
uci -q add_list dhcp.${name}.ra_flags="other-config"
uci -q commit dhcp
}
ts_create_dhcp() {
local diff=""
_firewall_setup() {
local name=$1
local network=$2
local zone_exist=0
_net_setup() {
local name=$1
local devname=$2
local vid=$3
config_load firewall
[ -z "$(uci -q get network.${name})" ] && {
uci -q set network.${name}="interface"
uci -q set network.${name}.device="$devname"
uci -q set network.${name}.is_lan="1"
uci -q set network.${name}.proto="static"
# TODO vid > 255
local ip_addr="192.168.${vid}.1"
[ "${vid}" = "1" ] && ip_addr="192.168.${vid}.2"
uci -q set network.${name}.ipaddr="${ip_addr}"
uci -q set network.${name}.netmask="255.255.255.0"
_process_zone() {
local section=$1
local new_name=$2
local name
diff="1"
}
config_get name $section name
[ "$diff" = "1" ] && uci -q commit network
[ "$name" == "$new_name" ] && zone_exist=1
}
_br_setup() {
local name=$1
local sinkname=$2
local vid=$3
config_foreach _process_zone zone $name
[ -z "$(uci -q get network.${name}_dev)" ] && {
uci -q set network.${name}_dev="device"
uci -q set network.${name}_dev.name="br-${name}"
uci -q set network.${name}_dev.type="bridge"
uci -q set network.${name}_dev.bridge_empty="1"
uci -q add_list network.${name}_dev.ports="${sinkname}"
[ "$zone_exist" != "0" ] && return
diff="1"
}
uci -q add firewall zone
uci -q set firewall.@zone[-1].name="$name"
uci -q add_list firewall.@zone[-1].network="$network"
uci -q set firewall.@zone[-1].input='ACCEPT'
uci -q set firewall.@zone[-1].output='ACCEPT'
uci -q set firewall.@zone[-1].forward='ACCEPT'
[ -z "$(uci -q get network.${name})" ] && {
uci -q set network.${name}="interface"
uci -q set network.${name}.device="br-${name}"
uci -q set network.${name}.is_lan="1"
uci -q set network.${name}.proto="static"
uci -q set network.${name}.ipaddr="192.168.${vid}.1"
uci -q set network.${name}.netmask="255.255.255.0"
uci -q add firewall forwarding
uci -q set firewall.@forwarding[-1].src="$name"
uci -q set firewall.@forwarding[-1].dest="wan"
diff="1"
}
[ "$diff" = "1" ] && uci -q commit network
}
_dhcp_setup() {
local name=$1
[ -n "$(uci -q get dhcp.${name})" ] && return
uci -q set dhcp.${name}=dhcp
uci -q set dhcp.${name}.interface="${name}"
uci -q set dhcp.${name}.start="100"
uci -q set dhcp.${name}.limit="150"
uci -q set dhcp.${name}.leasetime="1h"
uci -q set dhcp.${name}.dhcpv4="server"
uci -q set dhcp.${name}.dhcpv6="server"
uci -q set dhcp.${name}.ra="server"
uci -q set dhcp.${name}.ra_slaac="1"
uci -q add_list dhcp.${name}.ra_flags="managed-config"
uci -q add_list dhcp.${name}.ra_flags="other-config"
diff="1"
uci -q commit dhcp
}
_firewall_setup() {
local name=$1
local network=$2
local zone_exist=0
config_load firewall
_process_zone() {
local section=$1
local new_name=$2
local name
config_get name $section name
[ "$name" == "$new_name" ] && zone_exist=1
}
config_foreach _process_zone zone $name
[ "$zone_exist" != "0" ] && return
uci -q add firewall zone
uci -q set firewall.@zone[-1].name="$name"
uci -q add_list firewall.@zone[-1].network="$network"
uci -q set firewall.@zone[-1].input='ACCEPT'
uci -q set firewall.@zone[-1].output='ACCEPT'
uci -q set firewall.@zone[-1].forward='ACCEPT'
uci -q add firewall forwarding
uci -q set firewall.@forwarding[-1].src="$name"
uci -q set firewall.@forwarding[-1].dest="wan"
diff="1"
uci -q commit firewall
}
vid=$1 # primary vid
[ -n "$vid" ] || {
cat <<EOF
VID required to configure DHCP.
EOF
exit 1
}
ip link show sink${vid} || {
ip link add sink${vid} type veth peer name sink${vid}_vlan
ip link add link sink${vid} name sink${vid}_peer type vlan id ${vid}
}
ip link set sink${vid} up
ip link set sink${vid}_peer up
ip link set sink${vid}_vlan up
diff=""
_net_setup sink${vid} sink${vid}_peer ${vid}
_dhcp_setup sink${vid}
_firewall_setup lan${vid} sink${vid}
[ "$diff" = "1" ] && {
ubus call network reload
ubus -t 5 wait_for network.interface.sink${vid}
}
brctl addif br-map sink${vid}_vlan &> /dev/null
uci -q commit firewall
}
local type=$1
shift
vid=$1 # primary vid
case "$type" in
fh) ts_create_fh $@;;
bh) ts_create_bh $@;;
lei) ts_create_lei $@;;
eths) ts_create_eths $@;;
dhcp) ts_create_dhcp $@;;
--help|help) ts_usage;;
*) ts_usage; exit 1;;
esac
}
ts_delete() {
iface=$1
path=$(ls -d /sys/class/net/${iface}/upper_*)
[ -z "$path" ] && exit 0
vlan_dev=${path##*upper_}
bridge="$(_get_bridge $vlan_dev)"
[ -n "$bridge" ] && {
vlanctl --if-delete $vlan_dev # note: also removes rules and removes from bridge
brctl addif $bridge $iface &> /dev/null # needed to add again
}
}
ts_populate() {
local type=$1
shift
[ "$type" == "eth" ] || {
[ -n "$vid" ] || {
cat <<EOF
Populating ETH rules requires IFACE and VID.
VID required to configure.
EOF
exit 1
}
iface=$1 # Multi-AP Logical Ethernet Interface
vid=$2 # secondary vid
ip link show sink${vid} 2> /dev/null || {
ip link add sink${vid} type veth peer name sink_peer${vid}
}
path=$(ls -d /sys/class/net/${iface}/upper_*)
[ -z "$path" ] && exit 1
vlan_dev=${path##*upper_}
ip link set sink${vid} up
ip link set sink_peer${vid} up
# add rules
#vlanctl --if $iface --rx --tags 1 --filter-vid $vid 0 --set-rxif $vlan_dev --rule-append # note: retain secondary vids
#vlanctl --if $iface --tx --tags 1 --filter-vid $vid 0 --filter-txif $vlan_dev --rule-append # note: already default
}
proto="dhcp"
[ -x "/usr/sbin/mapcontroller" ] && proto="static" ;
_net_setup "vlan${vid}" ${vid} ${proto} "sink${vid}" "sink_peer${vid}"
ts_primary() {
local func=$1
shift
case "$func" in
get) vid=$(wl -i $1 map_8021q_settings); echo ${vid##* };;
*) ts_usage; exit 1;;
esac
}
ts_unicast() {
local mac=$1
local iface=$2
# TODO: improve?
res=$(ebtables -t broute -L | grep -i "$mac" | grep "$iface")
[ -n "$res" ] && return
ebtables -t broute -D BROUTING -d "$mac" -p 0x893a -j DROP
ebtables -t broute -I BROUTING -i "$iface" -d "$mac" -p 0x893a -j DROP
}
ts_multicast() {
local iface=$1
# TODO: improve?
res=$(ebtables -t broute -L | grep -i "1:80:C2:00:00:13" | grep "$iface")
[ -n "$res" ] && return
ebtables -t broute -D BROUTING -d 01:80:C2:00:00:13 -p 0x893a -j DROP
ebtables -t broute -D BROUTING -i "$iface" -d 01:80:C2:00:00:13 -p 0x893a -j DROP
ebtables -t broute -I BROUTING -i "$iface" -d 01:80:C2:00:00:13 -p 0x893a -j DROP
[ -x "/usr/sbin/mapcontroller" ] && _dhcp_setup vlan${vid}
#_firewall_setup vlan${vid} sink${vid}
}
ts_reload() {
@ -466,32 +163,31 @@ EOF
# workaround for missing backhaul wifi.ap.* ubus obj's:
# iterate in config and setup bh
config_load wireless
# config_load wireless
_setup_bh_iface() {
local sec=$1
local iface=$2
local bridge=$3
# _setup_bh_iface() {
# local sec=$1
# local iface=$2
# local bridge=$3
config_get ifname $sec ifname
# config_get ifname $sec ifname
config_get mode $sec mode
config_get multi_ap $sec multi_ap "0"
[ "$mode" = "ap" -a "$multi_ap" = "1" ] && {
ts_create bh $ifname 1 2 br-map
}
}
# config_get mode $sec mode
# config_get multi_ap $sec multi_ap "0"
# [ "$mode" = "ap" -a "$multi_ap" = "1" ] && {
# ts_create bh $ifname 1 2 br-map
# }
#}
config_foreach _setup_bh_iface wifi-iface
# config_foreach _setup_bh_iface wifi-iface
[ -n "dhcp_reload" ] && /etc/init.d/dnsmasq reload
/etc/init.d/network reload
# another workaround for netif? removed
# sink devices for br-map bridge
for sink in $(ubus list network.interface.sink*) ; do
local sink_vlan=${sink/network.interface./}_vlan
brctl addif br-map $sink_vlan &> /dev/null
done
#for sink in $(ubus list network.interface.sink*) ; do
# local sink_vlan=${sink/network.interface./}_vlan
#done
}
local func=$1
@ -499,11 +195,6 @@ EOF
case "$func" in
create) dbg "create $@"; ts_create $@;;
delete) dbg "delete $@"; ts_delete $@;;
populate) dbg "populate $@"; ts_populate $@;;
primary) dbg "primary $@"; ts_primary $@;;
unicast) dbg "unicast $@"; ts_unicast $@;;
multicast) dbg "multicast $@"; ts_multicast $@;;
reload) dbg "reload $@"; ts_reload $@;;
--help|help) ts_usage;;
*) ts_usage; exit 1;;

View file

@ -6,7 +6,7 @@ config controller 'controller'
option enable_bsta_steer '0'
option use_bcn_metrics '0'
option use_usta_metrics '0'
option primary_vid '1'
option primary_vid '0'
option primary_pcp '0'
option allow_bgdfs '0'
option channel_plan '0'