Compare commits

...

21 Commits

Author SHA1 Message Date
Rahul
3aa83cf293 qosmngr: update directory structure 2022-11-03 11:48:37 +05:30
Maxim Menshikov
56eda7dc84 qosmngr: rework folder structure to align with other projects 2022-11-03 11:48:37 +05:30
Maxim Menshikov
2b19d9b72f qosmngr: cleanup of Econet library 2022-11-03 11:48:37 +05:30
Maxim Menshikov
7e632d4d5f ebtables setup: cleanup 2022-11-03 11:48:37 +05:30
Maxim Menshikov
62a9643c70 qosmngr/iptables: more correct chain mark 2022-11-03 11:48:37 +05:30
Maxim Menshikov
04da842aee qosmngr/econet: add queues up to required weight list size 2022-11-03 11:48:37 +05:30
Maxim Menshikov
f018420e01 qosmngr/policer: remove references to old code 2022-11-03 11:48:37 +05:30
Maxim Menshikov
ed2363453c qosmngr: comment out non-working functions 2022-11-03 11:48:37 +05:30
Maxim Menshikov
4956507eef qosmngr: perform static analysis with shellcheck on scripts 2022-11-03 11:48:37 +05:30
Maxim Menshikov
92bf5612dd qosmngr: add notes to more functions 2022-11-03 11:48:37 +05:30
Maxim Menshikov
951a5f0c19 qosmngr: enable rules 2022-11-03 11:48:37 +05:30
Maxim Menshikov
02f8b9d695 qosmngr: remove syntax bugs in IP version comparison 2022-11-03 11:48:37 +05:30
Maxim Menshikov
3a1cedd12b qosmngr: fix typo 2022-11-03 11:48:37 +05:30
Maxim Menshikov
19878f619d qosmngr: don't craft broken IP ranges 2022-11-03 11:48:37 +05:30
Maxim Menshikov
249cfdef06 qosmngr: ignore some queues 2022-11-03 11:48:37 +05:30
Maxim Menshikov
782dae80f7 qosmngr: style fixes in queue generate 2022-11-03 11:48:37 +05:30
Maxim Menshikov
dc360e36c0 qosmngr: move qos setup scripts 2022-11-03 11:48:37 +05:30
Maxim Menshikov
f27127df84 qosmngr: better way to install varying files 2022-11-03 11:48:37 +05:30
Maxim Menshikov
6c2213c4d5 qosmngr: introduce target-specific scripts 2022-11-03 11:48:37 +05:30
Maxim Menshikov
b2cc1eaae3 qosmngr: remove qos queue generate script 2022-11-03 11:48:37 +05:30
Maxim Menshikov
f65ce56940 qosmngr: implement Econet support 2022-11-03 11:48:37 +05:30
14 changed files with 1287 additions and 59 deletions

View File

@@ -40,11 +40,24 @@ define Build/Prepare
endef
endif
define Package/qosmngr/install
$(CP) ./files/* $(1)/
define Package/qosmngr/install/common
$(CP) ./files/common/* $(1)/
$(INSTALL_DIR) $(1)/usr
$(INSTALL_DIR) $(1)/usr/sbin
$(INSTALL_BIN) $(PKG_BUILD_DIR)/qosmngr $(1)/usr/sbin
endef
ifeq ($(CONFIG_TARGET_iopsys_brcm63xx_arm),y)
define Package/qosmngr/install
$(CP) ./files/broadcom/* $(1)/
$(call Package/qosmngr/install/common,$(1))
endef
endif
ifeq ($(CONFIG_TARGET_iopsys_econet),y)
define Package/qosmngr/install
$(CP) ./files/airoha/* $(1)/
$(call Package/qosmngr/install/common,$(1))
endef
endif
$(eval $(call BuildPackage,qosmngr))

View File

@@ -0,0 +1,48 @@
#!/bin/sh
. /lib/functions.sh
ethwan="$(db -q get hw.board.ethernetWanPort)"
generate_queue(){
section="$1"
config_get ifname "$section" "ifname"
if [ "$ifname" != "$ethwan" ]; then
return 0
fi
# guaranteed number of queues
no_of_q="0 1 2 3"
i=0
local total_q=$((${no_of_q##* } + 1))
for i in $no_of_q; do
order=$((total_q - i))
uci add qos queue
uci rename qos.@queue[-1]="q_${i}_${ifname}"
uci set qos.@queue[-1].enable="1"
uci set qos.@queue[-1].ifname="$ifname"
uci set qos.@queue[-1].precedence="$order"
uci set qos.@queue[-1].scheduling="SP"
uci set qos.@queue[-1].rate="0"
uci set qos.@queue[-1].burst_size="0"
uci set qos.@queue[-1].weight="1"
done
uci commit qos
}
if [ -s "/etc/config/qos" ]; then
if uci -q get qos.@queue[0] >/dev/null; then
# return if there is any valid content
exit
else
rm -f /etc/config/qos
fi
fi
touch /etc/config/qos
config_load ports
config_foreach generate_queue ethport

View File

@@ -0,0 +1,453 @@
#!/bin/sh
# Install ebtables rules
BR_RULE=""
BR6_RULE=""
init_broute_rule() {
BR_RULE=""
BR6_RULE=""
}
broute_filter_on_src_if() {
BR_RULE="$BR_RULE --in-if $1"
}
broute_filter_on_src_mac() {
BR_RULE="$BR_RULE --src $1"
}
broute_filter_on_dst_mac() {
BR_RULE="$BR_RULE --dst $1"
}
broute_filter_on_pcp() {
case "$BR_RULE" in
*proto*)
BR_RULE="$BR_RULE --vlan-prio $1"
;;
*)
BR_RULE="$BR_RULE --proto 802_1Q --vlan-prio $1"
;;
esac
}
broute_filter_on_ether_type() {
BR_RULE="$BR_RULE --proto $1"
}
broute_filter_on_ether_type6() {
BR6_RULE="$BR6_RULE --proto IPv6"
}
ebt_match_src_ip() {
BR_RULE="$BR_RULE --ip-src $1"
}
ebt_match_dst_ip() {
BR_RULE="$BR_RULE --ip-dst $1"
}
ebt_match_ipv6_src_ip() {
BR_RULE="$BR_RULE --ip6-src $1"
}
ebt_match_ipv6_dst_ip() {
BR_RULE="$BR_RULE --ip6-dst $1"
}
ebt_match_ip_src_port() {
BR_RULE="$BR_RULE --ip-source-port $1"
}
ebt_match_ip_dst_port() {
BR_RULE="$BR_RULE --ip-destination-port $1"
}
ebt_match_ipv6_src_port() {
if [ -n "$BR6_RULE" ]; then
BR6_RULE="$BR6_RULE --ip6-source-port $1"
else
BR_RULE="$BR_RULE --ip6-source-port $1"
fi
}
ebt_match_ipv6_dst_port() {
if [ -n "$BR6_RULE" ]; then
BR6_RULE="$BR6_RULE --ip6-destination-port $1"
else
BR_RULE="$BR_RULE --ip6-destination-port $1"
fi
}
ebt_match_ip_protocol() {
BR_RULE="$BR_RULE --ip-proto $1"
}
ebt_match_ipv6_protocol() {
if [ -n "$BR6_RULE" ]; then
BR6_RULE="$BR6_RULE --ip6-proto $1"
else
BR_RULE="$BR_RULE --ip6-proto $1"
fi
}
ebt_match_ipv6_dscp() {
if [ -n "$BR6_RULE" ]; then
BR6_RULE="$BR6_RULE --ip6-tclass $1"
else
BR_RULE="$BR_RULE --ip6-tclass $1"
fi
}
broute_filter_on_vid() {
if [ -z "$1" ] || [ "$1" -lt 0 ]; then
return
fi
case "$BR_RULE" in
*proto*)
BR_RULE="$BR_RULE --vlan-id $1"
;;
*)
BR_RULE="$BR_RULE --proto 802_1Q --vlan-id $1"
;;
esac
}
broute_rule_set_traffic_class() {
BR_RULE="$BR_RULE -j mark --mark-or 0x$1 --mark-target ACCEPT"
if [ -n "$BR6_RULE" ]; then
BR6_RULE="$BR6_RULE -j mark --mark-or 0x$1 --mark-target ACCEPT"
fi
}
broute_append_rule() {
echo "ebtables -t broute -A qos $BR_RULE" >> /tmp/qos/classify.ebtables
if [ -n "$BR6_RULE" ]; then
echo "ebtables -t broute -A qos $BR6_RULE" >> /tmp/qos/classify.ebtables
fi
}
set_ip_addr()
{
local cid="$1"
local match_src_ip_func="$2"
local match_dst_ip_func="$3"
config_get src_ip "$cid" "src_ip"
config_get dst_ip "$cid" "dest_ip"
if [ -n "$src_ip" ]; then
$match_src_ip_func "$src_ip"
fi
if [ -n "$dst_ip" ]; then
$match_dst_ip_func "$dst_ip"
fi
}
set_ports()
{
local cid="$1"
local match_src_port_func="$2"
local match_dst_port_func="$3"
local src_port=""
local dst_port=""
local src_port_range=""
local dst_port_range=""
config_get src_port "$cid" "src_port"
config_get dst_port "$cid" "dest_port"
config_get src_port_range "$cid" "src_port_range"
config_get dst_port_range "$cid" "dest_port_range"
if [ -n "$src_port" ] && [ -n "$src_port_range" ] ; then
$match_src_port_func "$src_port:$src_port_range"
elif [ -n "$src_port" ] ; then
$match_src_port_func "$src_port"
fi
if [ -n "$dst_port" ] && [ -n "$dst_port_range" ] ; then
$match_dst_port_func "$dst_port:$dst_port_range"
elif [ -n "$dst_port" ] ; then
$match_dst_port_func "$dst_port"
fi
}
protocol_string_to_num()
{
local value="-1"
case "$1" in
*[0-9]*)
value="$1"
;;
TCP|tcp)
value=6
;;
UDP|udp)
value=17
;;
ICMP|icmp)
value=1
;;
ICMPv6|icmpv6)
value=58
;;
IGMP|igmp)
value=2
;;
SCTP|sctp)
value=132
;;
*)
value=-1
;;
esac
echo $value
}
broute_ipv4_rule_options()
{
local cid="$1"
config_get protocol "$cid" "proto"
config_get dscp_filter "$cid" "dscp_filter"
set_ip_addr "$cid" ebt_match_src_ip ebt_match_dst_ip
if [ -n "$dscp_filter" ]; then
echo "DSCP filter is not supporter"
fi
if [ -n "$protocol" ]; then
local proto_num="$(protocol_string_to_num "$protocol")"
ebt_match_ip_protocol "$proto_num"
if [ "$proto_num" == "6" ] || [ "$proto_num" == "17" ] || [ "$proto_num" = "132" ] ; then
set_ports "$cid" ebt_match_ip_src_port ebt_match_ip_dst_port
fi
fi
}
broute_ipv6_rule_options()
{
local cid="$1"
config_get protocol "$cid" "proto"
config_get dscp_filter "$cid" "dscp_filter"
set_ip_addr "$cid" ebt_match_ipv6_src_ip ebt_match_ipv6_dst_ip
if [ -n "$dscp_filter" ]; then
local tos_val
local tos_hex
tos_val=$((dscp_filter<<2))
tos_hex=$(printf "%x" $tos_val)
ebt_match_ipv6_dscp "$tos_hex"
fi
if [ -n "$protocol" ]; then
local proto_num="$(protocol_string_to_num "$protocol")"
ebt_match_ipv6_protocol "$proto_num"
if [ "$proto_num" = "6" ] || [ "$proto_num" = "17" ] || [ "$proto_num" = "132" ] ; then
set_ports "$cid" ebt_match_ipv6_src_port ebt_match_ipv6_dst_port
fi
fi
}
handle_ebtables_rules() {
local sid="$1"
local is_l2_rule=0
local src_dhcp_options=""
local dst_dhcp_options=""
local protocol=""
local ip_version=""
init_broute_rule
config_get src_if "$sid" "ifname"
config_get src_mac "$sid" "src_mac"
config_get dst_mac "$sid" "dst_mac"
config_get dscp_filter "$sid" "dscp_filter"
config_get pcp_check "$sid" "pcp_check"
config_get eth_type "$sid" "ethertype"
config_get vid "$sid" "vid_check"
config_get dhcp_type "$sid" "dhcp_type" # dhcpv4 or v6
config_get src_vcid "$sid" "src_vendor_class_id" # dhcp option 60
config_get dst_vcid "$sid" "dst_vendor_class_id" # dhcp option 60
config_get src_clid "$sid" "src_client_id" # dhcp option 61
config_get dst_clid "$sid" "dst_client_id" # dhcp option 61
config_get src_ucid "$sid" "src_user_class_id" # dhcp option 77
config_get dst_ucid "$sid" "dst_user_class_id" # dhcp option 77
config_get traffic_class "$sid" "traffic_class"
config_get protocol "$sid" "proto"
if [ -n "$src_if" ]; then
for interf in $(db -q get hw.board.ethernetPortOrder); do
if [ "$src_if" == "$interf" ]; then
src_if="$src_if+"
broute_filter_on_src_if "$src_if"
is_l2_rule=1
fi
done
fi
if [ -n "$src_mac" ]; then
broute_filter_on_src_mac "$src_mac"
is_l2_rule=1
fi
if [ -n "$dst_mac" ]; then
broute_filter_on_dst_mac "$dst_mac"
is_l2_rule=1
fi
if [ -n "$pcp_check" ]; then
broute_filter_on_pcp "$pcp_check"
is_l2_rule=1
fi
if [ -n "$eth_type" ]; then
broute_filter_on_ether_type "$eth_type"
is_l2_rule=1
fi
if [ -n "$vid" ]; then
broute_filter_on_vid "$vid"
is_l2_rule=1
fi
case $eth_type in
IPv4|IPV4|0800)
ip_version=4
;;
IPv6|IPV6|86DD)
ip_version=6
;;
*)
if [ -z "$eth_type" ]; then
case "$src_ip$dst_ip" in
*.*)
ip_version=4
broute_filter_on_ether_type "IPv4"
;;
*:*)
ip_version=6
broute_filter_on_ether_type "IPv6"
;;
*)
if [ -n "$protocol" ] || [ -n "$dscp_filter" ]; then
# Neither ether_type nor ip address used,
# ethertype is not configured by user, so install
# both proto IPv4 and IPv6 rule (version 1)
ip_version=1
BR6_RULE="$BR_RULE"
broute_filter_on_ether_type "IPv4"
broute_filter_on_ether_type6 "IPv6"
fi
esac
fi
esac
if [ "$ip_version" == "4" ] || [ "$ip_version" == "1" ]; then
broute_ipv4_rule_options "$sid"
is_l2_rule=1
fi
if [ "$ip_version" == "6" ] || [ "$ip_version" == "1" ]; then
broute_ipv6_rule_options "$sid"
is_l2_rule=1
fi
# first process options that will help figure our source mac address
# dhcp option for "vendor class id"
if [ -n "$src_vcid" ]; then
src_dhcp_options="$src_dhcp_options vcid=$src_vcid"
is_l2_rule=1
fi
# dhcp option for "client id"
if [ -n "$src_clid" ]; then
src_dhcp_options="$src_dhcp_options clid=$src_clid"
is_l2_rule=1
fi
# dhcp option for "user class id"
if [ -n "$src_ucid" ]; then
src_dhcp_options="$src_dhcp_options ucid=$src_ucid"
is_l2_rule=1
fi
# if src mac is already a classification criteria, then it
# does not really make sense to add it as a criteria to
# filter packets again based on source mac
if [ -n "$src_dhcp_options" ] && [ -z "$src_mac" ]; then
comp="$(grep -i "$src_dhcp_options" /tmp/dhcp.client.options)"
if [ -n "$comp" ]; then
s_mac_add="$(echo $comp | head -n1 | awk '{print $1;}')"
if [ -n "$s_mac_add" ]; then
broute_filter_on_src_mac "$s_mac_add"
fi
fi
fi
# Now process options that will help figure our destination mac address
# dhcp option for "vendor class id"
if [ -n "$dst_vcid" ]; then
dst_dhcp_options="$dst_dhcp_options vcid=$dst_vcid"
is_l2_rule=1
fi
# dhcp option for "client id"
if [ -n "$dst_clid" ]; then
dst_dhcp_options="$dst_dhcp_options clid=$dst_clid"
is_l2_rule=1
fi
# dhcp option for "user class id"
if [ -n "$dst_ucid" ]; then
dst_dhcp_options="$dst_dhcp_options ucid=$dst_ucid"
is_l2_rule=1
fi
# if dst mac is already a classification criteria, then it
# does not really make sense to add it as a criteria to
# filter packets again based on destination mac
if [ -n "$dst_dhcp_options" ] && [ -z "$dst_mac" ] ; then
comp="$(grep -i "$dst_dhcp_options" /tmp/dhcp.client.options)"
if [ -n "$comp" ]; then
d_mac_add="$(echo $comp | head -n1 | awk '{print $1;}')"
if [ -n "$d_mac_add" ]; then
broute_filter_on_dst_mac "$d_mac_add"
fi
fi
fi
if [ $is_l2_rule -eq 0 ]; then
return
fi
[ -n "$traffic_class" ] && broute_rule_set_traffic_class "$traffic_class"
[ -n "$BR_RULE" ] && broute_append_rule
}
create_ebtables_chains() {
ebtables -t broute -N qos
ret=$?
if [ $ret -eq 0 ]; then
ebtables -t broute -I BROUTING -j qos
else
ebtables -t broute -D BROUTING -j qos
ebtables -t broute -I BROUTING -j qos
fi
}
flush_ebtables_chains() {
echo "ebtables -t broute -F qos" > /tmp/qos/classify.ebtables
}

View File

@@ -0,0 +1,240 @@
#!/bin/sh
# Install iptables rules
IP_RULE=""
init_iptables_rule() {
IP_RULE=""
}
iptables_filter_intf() {
IP_RULE="$IP_RULE -i $1"
}
iptables_filter_proto() {
IP_RULE="$IP_RULE -p $1"
}
iptables_filter_ip_src() {
IP_RULE="$IP_RULE -s $1"
}
iptables_filter_ip_dest() {
IP_RULE="$IP_RULE -d $1"
}
iptables_filter_port_dest() {
IP_RULE="$IP_RULE --dport $1"
}
iptables_filter_port_src() {
IP_RULE="$IP_RULE --sport $1"
}
iptables_filter_port_dest_range() {
IP_RULE="$IP_RULE --dport $1:$2"
}
iptables_filter_port_src_range() {
IP_RULE="$IP_RULE --sport $1:$2"
}
iptables_filter_dscp_filter() {
IP_RULE="$IP_RULE -m dscp --dscp $1"
}
iptables_filter_ip_len_min() {
IP_RULE="$IP_RULE -m length --length $1"
}
iptables_filter_ip_len_max() {
IP_RULE="$IP_RULE:$1"
}
iptables_set_dscp_mark() {
IP_RULE="$IP_RULE -j DSCP --set-dscp $1"
}
iptables_set_traffic_class() {
IP_RULE="$IP_RULE -j MARK --set-xmark 0x${1}0/0xF0"
}
append_rule_to_mangle_table() {
if [ "$2" == 4 ]; then
echo "iptables -w -t mangle -A $1 $IP_RULE" >> /tmp/qos/classify.iptables
elif [ "$2" == 6 ]; then
echo "ip6tables -w -t mangle -A $1 $IP_RULE" >> /tmp/qos/classify.ip6tables
elif [ "$2" == 1 ]; then
echo "iptables -w -t mangle -A $1 $IP_RULE" >> /tmp/qos/classify.iptables
echo "ip6tables -w -t mangle -A $1 $IP_RULE" >> /tmp/qos/classify.ip6tables
fi
}
handle_iptables_rules() {
local cid="$1"
local ip_version=0
local is_l3_rule=0
init_iptables_rule
config_get proto "$cid" "proto"
config_get traffic_class "$cid" "traffic_class"
config_get dscp_mark "$cid" "dscp_mark"
config_get dscp_filter "$cid" "dscp_filter"
config_get dest_port "$cid" "dest_port"
config_get dest_port_range "$cid" "dest_port_range"
config_get src_port "$cid" "src_port"
config_get src_port_range "$cid" "src_port_range"
config_get dest_ip "$cid" "dest_ip"
config_get src_ip "$cid" "src_ip"
config_get ip_len_min "$cid" "ip_len_min"
config_get ip_len_max "$cid" "ip_len_max"
config_get ifname "$cid" "ifname"
#check version of ip
case $src_ip$dest_ip in
*.*)
ip_version=4
;;
*:*)
ip_version=6
;;
*)
ip_version=1 #ip address not used
esac
#filter interface
if [ -n "$ifname" ]; then
if [ "$ifname" != "lo" ]; then
iptables_filter_intf "$ifname"
fi
fi
# filter proto
if [ -n "$proto" ]; then
iptables_filter_proto "$proto"
is_l3_rule=1
fi
#filter src. ip
if [ -n "$src_ip" ]; then
iptables_filter_ip_src "$src_ip"
is_l3_rule=1
fi
#filter dest. ip
if [ -n "$dest_ip" ]; then
iptables_filter_ip_dest "$dest_ip"
is_l3_rule=1
fi
#filter dest. port
if [ -n "$dest_port" ] && [ -z "$dest_port_range" ]; then
iptables_filter_port_dest "$dest_port"
is_l3_rule=1
fi
#filter src. port
if [ -n "$src_port" ] && [ -z "$src_port_range" ]; then
iptables_filter_port_src "$src_port"
is_l3_rule=1
fi
#filter dest. port range
if [ -n "$dest_port" ] && [ -n "$dest_port_range" ]; then
if [ "$dest_port_range" == "-1" ] ; then
dest_port_range="$dest_port"
fi
iptables_filter_port_dest_range "$dest_port" "$dest_port_range"
is_l3_rule=1
fi
#filter src. port range
if [ -n "$src_port" ] && [ -n "$src_port_range" ]; then
if [ "$src_port_range" == "-1" ] ; then
src_port_range="$src_port"
fi
iptables_filter_port_src_range "$src_port" "$src_port_range"
is_l3_rule=1
fi
#filter dscp
if [ -n "$dscp_filter" ]; then
iptables_filter_dscp_filter "$dscp_filter"
is_l3_rule=1
fi
#filter min. IP packet len.
if [ -n "$ip_len_min" ]; then
iptables_filter_ip_len_min "$ip_len_min"
is_l3_rule=1
fi
#filter max. IP packet len.
if [ -n "$ip_len_max" ]; then
iptables_filter_ip_len_max "$ip_len_max"
is_l3_rule=1
fi
if [ -z "$is_l3_rule" ] || [ "$is_l3_rule" -eq 0 ] ; then
return
fi
#set dscp mark
[ -n "$dscp_mark" ] && iptables_set_dscp_mark "$dscp_mark"
#set packet queue mark
[ -n "$traffic_class" ] && iptables_set_traffic_class "$traffic_class"
#write iptables rule for dscp marking
[ -n "$IP_RULE" ] && [ -n "$dscp_mark" ] && append_rule_to_mangle_table "qos_forward" $ip_version
if [ -n "$IP_RULE" ] && [ -n "$traffic_class" ]; then
if [ "$ifname" == "lo" ]; then
#write iptables rule for putting WAN directed internal packets in different queue
append_rule_to_mangle_table "qos_output" $ip_version
else
#write iptables rule for putting WAN directed LAN packets in different queue
append_rule_to_mangle_table "qos_prerouting" $ip_version
fi
fi
}
create_iptables_chains() {
iptables -w -t mangle -N qos_forward
ret=$?
[ $ret -eq 0 ] && iptables -w -t mangle -I FORWARD -j qos_forward
iptables -w -t mangle -N qos_prerouting
ret=$?
[ $ret -eq 0 ] && iptables -w -t mangle -I PREROUTING -j qos_prerouting
iptables -w -t mangle -N qos_output
ret=$?
[ $ret -eq 0 ] && iptables -w -t mangle -I OUTPUT -j qos_output
ip6tables -t mangle -N qos_forward
ret=$?
[ $ret -eq 0 ] && ip6tables -t mangle -I FORWARD -j qos_forward
ip6tables -t mangle -N qos_prerouting
ret=$?
[ $ret -eq 0 ] && ip6tables -t mangle -I PREROUTING -j qos_prerouting
ip6tables -t mangle -N qos_output
ret=$?
[ $ret -eq 0 ] && ip6tables -t mangle -I OUTPUT -j qos_output
}
flush_iptables_chains() {
echo "iptables -w -t mangle -F qos_forward" > /tmp/qos/classify.iptables
echo "iptables -w -t mangle -F qos_prerouting" >> /tmp/qos/classify.iptables
echo "iptables -w -t mangle -F qos_output" >> /tmp/qos/classify.iptables
echo "ip6tables -w -t mangle -F qos_forward" > /tmp/qos/classify.ip6tables
echo "ip6tables -w -t mangle -F qos_prerouting" >> /tmp/qos/classify.ip6tables
echo "ip6tables -w -t mangle -F qos_output" >> /tmp/qos/classify.ip6tables
}

View File

@@ -0,0 +1,12 @@
#!/bin/sh
# Set up or flush all chains
setup_qos() {
create_ebtables_chains
create_iptables_chains
}
flush_chains() {
flush_ebtables_chains
flush_iptables_chains
}

View File

@@ -0,0 +1,44 @@
#!/bin/sh
# Common classifier library
# Handle classify section
handle_classify() {
cid="$1" #classify section ID
config_get is_enable "$cid" "enable"
# no need to configure disabled classify rules
if [ -z "$is_enable" ] || [ "$is_enable" == "0" ]; then
return
fi
handle_ebtables_rules "$cid"
handle_iptables_rules "$cid"
handle_policer_rules "$cid"
}
# Configure classifier based on UCI subtree 'qos.classify'
configure_classify() {
# Processing classify section
# First remove old files
rm -f /tmp/qos/classify.ebtables
rm -f /tmp/qos/classify.iptables
rm -f /tmp/qos/classify.ip6tables
# Create files that will contain the rules if not present already
mkdir -p /tmp/qos/
touch /tmp/qos/classify.iptables
touch /tmp/qos/classify.ip6tables
touch /tmp/qos/classify.ebtables
# Add flush chain rules
flush_chains
# Load UCI file
config_load qos
config_foreach handle_classify classify
sh /tmp/qos/classify.ebtables
sh /tmp/qos/classify.iptables
sh /tmp/qos/classify.ip6tables
}

View File

@@ -0,0 +1,132 @@
#!/bin/sh
# Common policer library
POLICER_COUNT=0
# Function invoked
handle_policer_rules() {
local c_sec="$1"
local policer_name
local ifname
local pname
local pindex=-1
local ingress_rate=0
local in_burst_size=0
config_get policer_name "$c_sec" "policer"
if [ -z "$policer_name" ];then
# no need to apply policer if policer not present in this
# classification rule
return
fi
config_get ifname "$c_sec" "ifname"
if [ -z "$ifname" ]; then
# cannot associate policer as interface is not mentioned
return
fi
local i=0
local max_policer_inst="$(cat /tmp/qos/max_policer_inst)"
while :
do
if [ "${i}" -eq "$max_policer_inst" ]; then
break
fi
pname="$(uci -q get qos.@policer[$i].name)"
if [ "$policer_name" == "$pname" ]; then
pindex=$i
ingress_rate="$(uci -q get qos.@policer[$i].committed_rate)"
in_burst_rate="$(uci -q get qos.@policer[$i].committed_burst_size)"
break
fi
i=$((i + 1))
done
if [ -z "$pindex" ] || [ "$pindex" -lt 0 ]; then
# policer not found, no need to proceed further
return
fi
config_ingress_rate_limit "$ifname" "$ingress_rate" "$in_burst_size"
}
# Configure ingress rate limit
config_ingress_rate_limit() {
local ifname="$1"
local ingress_rate="$2"
local in_burst_size="$3"
local port=""
if [ -z "$ingress_rate" ] || [ "$ingress_rate" -lt 1000 ] ; then
return
fi
ingress_rate=$((ingress_rate / 1000))
if [ "$in_burst_size" -eq 0 ]; then
in_burst_size="$ingress_rate"
else
in_burst_size="$((in_burst_size / 1000))"
fi
hw_policer_set_ingress_rate "$ifname" "$port" "$ingress_rate" "$in_burst_size"
}
# Function invoked for handling policer section in UCI
handle_policer() {
local p_sec="$1" # policer section ID
local dir=1 # default direction, upstream
config_get is_enable "$p_sec" "enable"
# No need to configure disabled policer
if [ -z "$is_enable" ] || [ "$is_enable" == "0" ] ; then
return
fi
config_get cir "$p_sec" "committed_rate"
config_get cbs "$p_sec" "committed_burst_size" -1
config_get ebs "$p_sec" "excess_burst_size" 0
config_get pir "$p_sec" "peak_rate" 0
config_get pbs "$p_sec" "peak_burst_size" 0
config_get meter "$p_sec" "meter_type" 0
hw_policer_set add "$dir" "$POLICER_COUNT" "$meter" "$cir" "$cbs" "$ebs" "$pir" "$pbs"
POLICER_COUNT=$((POLICER_COUNT + 1))
}
# Configure policer based on UCI subtree 'qos.policer'
configure_policer() {
for intf in $(db get hw.board.ethernetPortOrder); do
if [ -n "${intf}" ] ; then
hw_policer_set_ingress_rate "$intf" 0 0
fi
done
# Delete policer
local i=0
local max_p_inst=0
if [ -f "/tmp/qos/max_policer_inst" ]; then
max_p_inst=$(cat /tmp/qos/max_policer_inst)
fi
while :
do
if [ "$i" -eq "$max_p_inst" ]; then
break
fi
hw_policer_set del 1 $i
i=$((i + 1))
done
# reset the policer counter
echo 0 > /tmp/qos/max_policer_inst
# Load UCI file
config_load qos
config_foreach handle_policer policer
echo $POLICER_COUNT > /tmp/qos/max_policer_inst
}

View File

@@ -0,0 +1,50 @@
#!/bin/sh
# Handle queues and their order
Q_COUNT=0
# Preliminary configuration of a queue
pre_configure_queue() {
# Delete queues
hw_queue_init_all
for intf in $(db get hw.board.ethernetPortOrder); do
hw_intf_init "${intf}"
done
}
# UCI queue section handler
handle_queue() {
local qid="$1" #queue section ID
local intf_name="$2"
config_get is_enable "$qid" "enable"
# no need to configure disabled queues
if [ -z "${is_enable}" ] || [ "${is_enable}" == "0" ]; then
return
fi
config_get ifname "$qid" "ifname"
# if ifname is empty that is good enough to break
if [ -z "$ifname" ];then
return
fi
config_get sc_alg "$qid" "scheduling"
config_get wgt "$qid" "weight" 1
config_get rate "$qid" "rate"
config_get bs "$qid" "burst_size"
config_get qsize "$qid" "queue_size" 1024
config_get precedence "$qid" "precedence"
hw_queue_set "${ifname}" "${Q_COUNT}" "${precedence}" "$qsize" "$wgt" "$sc_alg" "$shapingrate" "$rate" "$bs"
Q_COUNT=$((Q_COUNT + 1))
}
# Configure all queues specified in UCI tree 'qos.queue'
configure_queue() {
# Load UCI file
config_load qos
config_foreach handle_queue queue
}

View File

@@ -0,0 +1,46 @@
#!/bin/sh
# Common shaper library
# UCI 'shaper' section handler.
# It will verify shaper configuration sanity and then invoke
# hardware-specific functions
handle_shaper() {
sid="$1" #queue section ID
config_get is_enable "$sid" "enable"
# no need to configure disabled queues
if [ -z "${is_enable}" ] || [ "${is_enable}" == "0" ] ; then
return
fi
config_get ifname "$sid" "ifname"
# if ifname is empty that is good enough to break
if [ -z "$ifname" ] ; then
return
fi
config_get rate "$sid" "rate"
# Convert the rate from bps to kbps.
if [ -z "${rate}" ] || [ "${rate}" -lt 1000 ] ; then
return
fi
rate=$((rate / 1000))
config_get bs "$sid" "burst_size"
hw_shaper_set "$ifname" add "$rate" "$bs"
}
# Configure shaper based on options saved to UCI tree 'qos.shaper'
configure_shaper() {
# Delete existing shaper
for intf in $(db get hw.board.ethernetPortOrder); do
hw_shaper_set "$intf" del
done
# Load UCI file
config_load qos
# Processing shaper section(s)
config_foreach handle_shaper shaper
}

View File

@@ -0,0 +1,190 @@
#!/bin/sh
# Implementation of QoS setup for Econet platform.
errmsg() {
echo "$@" >&2
return 0
}
get_var() {
local varname="$1"
eval echo \$\{${varname}\}
return 0
}
# Initialized queues
# (Not needed on Econet)
hw_queue_init_all() {
return 0
}
# Initialize all interfaces
# (Not needed on Econet)
hw_intf_init() {
return 0
}
# Initialize the hardware setup library
hw_init_all() {
export TMP_HW_QUEUE_LIST=""
export TMP_HW_QUEUE_MASK="0"
return 0
}
# Remember selected queue options. They will be committed
# during hw_commit_all()
hw_queue_set() {
local ifname="$1"
local q_count="$2"
local order="$3"
local qsize="$4"
local wgt="$5"
local sc_alg="$6"
local rate="$7"
local burstsize="$8"
local index="$((order - 1))"
local ethwan="$(db -q get hw.board.ethernetWanPort)"
#if [ "${ifname}" != "${ethwan}" ] ; then
# return 2
#fi
export TMP_HW_QUEUE_${order}_no="${q_count}"
export TMP_HW_QUEUE_${order}_ifname="${ifname}"
export TMP_HW_QUEUE_${order}_order="${order}"
export TMP_HW_QUEUE_${order}_qsize="${qsize}"
export TMP_HW_QUEUE_${order}_wgt="${wgt}"
export TMP_HW_QUEUE_${order}_sc_alg="${sc_alg}"
export TMP_HW_QUEUE_${order}_rate="${rate}"
export TMP_HW_QUEUE_${order}_burstsize="${burstsize}"
export TMP_HW_QUEUE_LIST="${TMP_HW_QUEUE_LIST} ${order}"
export TMP_HW_QUEUE_MASK="$((TMP_HW_QUEUE_MASK | 1 << index))"
return 0
}
# Set policer options. In fact, they are not supported.
hw_policer_set() {
local action="$1"
local dir="$2"
local policer_no="$3"
shift 3
case "$action" in
add)
meter="$1"
cir="$2"
cbs="$3"
ebs="$4"
pir="$5"
pbs="$6"
;;
del)
;;
esac
errmsg "Policer (action $action, direction $dir) is not implemented"
return $?
}
# Set ingress rate. In fact, it is not supported
hw_policer_set_ingress_rate() {
local ifname="$1"
local ingress_rate="$2"
local in_burst_size="$3"
errmsg "Policer (action set_ingress_rate) is not implemented"
}
# Configure shaper rate that will be committed during hw_commit_all()
hw_shaper_set() {
local ifname="$1"
local action="$2"
local rate="$3"
local burstsize="$4"
case "${action}" in
add)
export TMP_HW_SHAPE_RATE="$rate"
export TMP_HW_SHAPE_BURSTSIZE="$burstsize"
;;
del)
export TMP_HW_SHAPE_RATE=""
export TMP_HW_SHAPE_BURSTSIZE=""
;;
*)
return 1
;;
esac
return 0
}
# Convert shaper in UCI terms to Econet terms
hw_sc_alg2str() {
local sc_alg="$1"
case "${sc_alg}" in
SP)
echo "PQ"
;;
WRR)
echo "WRR"
;;
*)
echo ""
return 1
esac
return 0
}
# Commit all options preserved during
hw_commit_all() {
local sorted_list="$(echo $TMP_HW_QUEUE_LIST | tr ' ' '\n' | sort | xargs)"
local weight_list=""
local glob_alg=""
local shape_rate="$TMP_HW_SHAPE_RATE"
local queue_mask="$TMP_HW_QUEUE_MASK"
local q_count="0"
# Reorder queues
for q in ${sorted_list} ; do
local sc_alg="$(get_var TMP_HW_QUEUE_${q}_sc_alg)"
local wgt="$(get_var TMP_HW_QUEUE_${q}_wgt)"
if [ "$glob_alg" != "" ] && [ "$sc_alg" != "$glob_alg" ] ; then
errmsg "Not matching scheduling algorithm: $sc_alg vs $glob_alg"
return 1
fi
glob_alg="$sc_alg"
case "${sc_alg}" in
WRR)
if [ $(($q_count >= 4)) != 0 ] ; then
errmsg "Too many queues, next queues will be ignored"
else
weight_list="$weight_list $wgt"
fi
q_count=$((q_count + 1))
;;
esac
done
if [ "${glob_alg}" == "WRR" ] ; then
while [ $((q_count < 4)) != 0 ] ; do
weight_list="$weight_list 1"
q_count=$((q_count + 1))
done
fi
if [ "${glob_alg}" != "" ] ; then
/userfs/bin/qosrule discpline $(hw_sc_alg2str ${glob_alg}) ${weight_list} \
${shape_rate:+uplink-bandwidth} $shape_rate \
queuemask $queue_mask
else
/userfs/bin/qosrule discpline off
fi
}

View File

@@ -0,0 +1,51 @@
#!/bin/sh
# The entrypoint for the QoS setup library
. /lib/functions.sh
. /lib/network/port.sh
. /lib/qos/common/chains.sh
. /lib/qos/common/chains.ebtables.sh
. /lib/qos/common/chains.iptables.sh
. /lib/qos/common/classify.sh
. /lib/qos/common/policer.sh
. /lib/qos/common/queue.sh
. /lib/qos/common/shaper.sh
. /lib/qos/econet.sh
configure_qos() {
# queue configuration is being done after shaper configuration,
# If port shapingrate configuration on DISC device is called after queue configuration then
# driver overwrites the queue shaping rate with default value of port shaping rate.
pre_configure_queue
setup_qos
configure_shaper
configure_queue
configure_policer
configure_classify
}
reload_qos() {
local service_name="$1"
hw_init_all
case "${service_name}" in
shaper)
configure_shaper
;;
queue)
pre_configure_queue
configure_queue
;;
classify)
configure_classify
;;
policer)
configure_policer
;;
"")
configure_qos
;;
esac
hw_commit_all
}

View File

@@ -10,9 +10,6 @@ POLICER_COUNT=0
Q_COUNT=0
SP_Q_PRIO=7
#counter variable to assign classify order value if not added in config
temp_order=1
# Function to handle a queue order and
# update total number of queues
handle_q_order() {
@@ -979,43 +976,6 @@ config_ingress_rate_limit() {
ethswctl -c rxratectrl -n $unit -p $port -x $ingress_rate -y $in_burst_size
}
# Function to handle a classify order
handle_classify_order() {
local cid="$1" #classify section ID
config_get is_enable "$cid" "enable" 1
# No need to configure disabled classify
if [ $is_enable == '0' ]; then
return
fi
# Create classify file containing classify order
local corder_file="/tmp/qos/classify.order"
config_get c_order "$cid" "order"
if [ -z "$c_order" ]; then
c_order=$temp_order;
temp_order=$((temp_order + 1))
fi
value=${c_order}_${cid}
echo $value >> $corder_file
}
# Sort classify, lower value in uci means higher precedence, so this
# function sorts the classify order in assending order
sort_classify_by_order() {
local corder_file="/tmp/qos/classify.order"
local tmp_corder_file="/tmp/qos/tmp_classify.order"
sort -n -k1 $corder_file > $tmp_corder_file
cp $tmp_corder_file $corder_file
rm -f $tmp_corder_file
}
#function to handle a classify section
handle_classify() {
cid="$1" #classify section ID
@@ -1026,15 +986,9 @@ handle_classify() {
return
fi
local corder_file="/tmp/qos/classify.order"
while read -r line; do
line_cid=${line: 2}
handle_ebtables_rules $line_cid
handle_iptables_rules $line_cid
handle_policer_rules $line_cid
done < "$corder_file"
handle_ebtables_rules $cid
handle_iptables_rules $cid
handle_policer_rules $cid
}
configure_shaper() {
@@ -1054,25 +1008,19 @@ configure_classify() {
rm -f /tmp/qos/classify.ebtables
rm -f /tmp/qos/classify.iptables
rm -f /tmp/qos/classify.ip6tables
rm -f /tmp/qos/classify.order
rm -f /tmp/qos/tmp_classify.order
#create files that will contain the rules if not present already
mkdir -p /tmp/qos/
touch /tmp/qos/classify.iptables
touch /tmp/qos/classify.ip6tables
touch /tmp/qos/classify.ebtables
touch /tmp/qos/classify.order
touch /tmp/qos/tmp_classify.order
#add flush chain rules
flush_chains
# Load UCI file
config_load qos
config_foreach handle_classify_order classify
sort_classify_by_order
handle_classify classify
config_foreach handle_classify classify
sh /tmp/qos/classify.ebtables
sh /tmp/qos/classify.iptables

View File

@@ -11,7 +11,8 @@ NAME=qosmngr
PROG=/usr/sbin/qosmngr
. /lib/functions.sh
include /lib/qos
. /lib/qos/qos.sh
start_service() {
if [ -f "/etc/config/qos" ]; then