Compare commits

...

1 Commits

Author SHA1 Message Date
Padmalochan Mohapatra
edd965f1f5 qos : Classification with tc+iptables for QoS on MTK_PANTHER
Description : For the tc classification, qos_postrouting
scheme has been chosen as the target in iptables.
This change set contains code changes for iptables
programming via qos.sh script modification for upstream
traffic classification on WAN port.
2022-12-29 17:47:48 +05:30
2 changed files with 283 additions and 18 deletions

View File

@@ -2,6 +2,9 @@
. /lib/functions.sh
#set -x
IP_RULE=""
MAJOR=""
POLICER_COUNT=0
Q_COUNT=0
SP_Q_PRIO=7
@@ -136,7 +139,7 @@ handle_queue() {
if [ $order -eq 0 ]; then
# By default flowid is targeted to queue 1.
tc filter add dev $port parent ${root}:0 protocol ip prio 1 u32 match u32 0 0 flowid ${root}:1
tc filter add dev $port parent ${root}:0 protocol ip prio 1 u32 match u32 0 0 flowid ${root}:0
fi
Q_COUNT=$((Q_COUNT + 1))
@@ -175,25 +178,223 @@ setup_qos() {
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
iptables -w -t mangle -N qos_postrouting
ret=$?
[ $ret -eq 0 ] && iptables -w -t mangle -I POSTROUTING -j qos_postrouting
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
ip6tables -w -t mangle -N qos_postrouting
ret=$?
[ $ret -eq 0 ] && ip6tables -w -t mangle -I POSTROUTING -j qos_postrouting
}
flush_chains() {
echo "iptables -w -t mangle -F qos_forward" > /tmp/qos/classify.iptables
echo "iptables -w -t mangle -F qos_output" >> /tmp/qos/classify.iptables
echo "iptables -w -t mangle -F qos_postrouting" >> /tmp/qos/classify.iptables
echo "ip6tables -w -t mangle -F qos_forward" > /tmp/qos/classify.ip6tables
echo "ip6tables -w -t mangle -F qos_output" >> /tmp/qos/classify.ip6tables
echo "ip6tables -w -t mangle -F qos_postrouting" >> /tmp/qos/classify.ip6tables
}
init_iptables_rule() {
IP_RULE=""
}
iptables_filter_intf() {
IP_RULE="$IP_RULE -o $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 CLASSIFY --set-class ${MAJOR}:$1"
}
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() {
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" -a -z "$dest_port_range" ]; then
iptables_filter_port_dest $dest_port
is_l3_rule=1
fi
#filter src. port
if [ -n "$src_port" -a -z "$src_port_range" ]; then
iptables_filter_port_src $src_port
is_l3_rule=1
fi
#filter dest. port range
if [ -n "$dest_port" -a -n "$dest_port_range" ]; then
iptables_filter_port_dest_range $dest_port $dest_port_range
is_l3_rule=1
fi
#filter src. port range
if [ -n "$src_port" -a -n "$src_port_range" ]; then
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 [ $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" -a -n "$dscp_mark" ] && append_rule_to_mangle_table "qos_forward" $ip_version
if [ -n "$IP_RULE" -a -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_postrouting" $ip_version
fi
fi
}
handle_policer_rules() {
@@ -271,27 +472,82 @@ config_ingress_rate_limit() {
}
#function to handle a classify section
handle_classify() {
cid="$1" #classify section ID
# Function to handle a classify order
handle_classify_order() {
local cid="$1" #classify section ID
config_get is_enable "$cid" "enable"
# no need to configure disabled classify rules
if [ "$is_enable" == '0' ]; then
config_get is_enable "$cid" "enable" 1
# No need to configure disabled classify
if [ $is_enable == '0' ]; then
return
fi
handle_policer_rules $cid
# 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() {
local corder_file="/tmp/qos/classify.order"
while read -r line; do
line_cid=$(echo $line | cut -d '_' -f 2)
config_get is_enable "$line_cid" "enable"
# no need to configure disabled classify rules
if [ "$is_enable" == '0' ]; then
continue
fi
handle_iptables_rules $line_cid
handle_policer_rules $line_cid
done < "$corder_file"
}
configure_classify() {
#processing classify section
rm -f /tmp/qos/classify.order
rm -f /tmp/qos/tmp_classify.order
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.order
        touch /tmp/qos/tmp_classify.order
flush_chains
# Load UCI file
config_load qos
config_foreach handle_classify classify
config_foreach handle_classify_order classify
sort_classify_by_order
handle_classify
sh /tmp/qos/classify.iptables
sh /tmp/qos/classify.ip6tables
}
pre_configure_queue() {
@@ -364,7 +620,7 @@ configure_queue() {
bs="$b_size"
fi
}
local wanport="$(db -q get hw.board.ethernetWanPort)"
for interf in $(db -q get hw.board.ethernetPortOrder); do
Q_COUNT=0
rate=0
@@ -383,6 +639,12 @@ configure_queue() {
# TODO using 1500 as allot and avpkt, if shaper config exist for interf get burst_size of shaper for actual value
tc qdisc add dev $interf root handle ${qdisc_idx}: cbq allot $bs avpkt 1500 bandwidth ${rate}kbit
# if qdisc_idx is the index corresponds to WAN port, then
# it would be the MAJOR portion of the destination class ID.
# under the same qdisc. We are programming for WAN port only.
if [ "$interf" == "$wanport" ]; then
MAJOR="$qdisc_idx"
fi
config_foreach handle_queue queue $interf $rate $qdisc_idx $bs
done
@@ -409,6 +671,7 @@ configure_policer() {
configure_qos() {
pre_configure_queue
configure_queue
configure_classify
configure_policer
}
@@ -420,6 +683,8 @@ reload_qos() {
elif [ "$service_name" == "queue" ]; then
pre_configure_queue
configure_queue
elif [ "$service_name" == "classify" ]; then
configure_classify
elif [ "$service_name" == "policer" ]; then
configure_policer
fi