From 591f9d9ddebcd929796f76434d946d35d338472a Mon Sep 17 00:00:00 2001 From: Padmalochan Mohapatra Date: Thu, 29 Dec 2022 12:09:38 +0000 Subject: [PATCH] qos : Classification with tc+iptables for QoS on MTK_PANTHER --- ..._queue_generate => 60-qos_config_generate} | 0 qosmngr/files/linux/lib/qos/qos.sh | 298 ++++++++++++++++-- 2 files changed, 280 insertions(+), 18 deletions(-) rename qosmngr/files/linux/etc/uci-defaults/{60-qos_queue_generate => 60-qos_config_generate} (100%) diff --git a/qosmngr/files/linux/etc/uci-defaults/60-qos_queue_generate b/qosmngr/files/linux/etc/uci-defaults/60-qos_config_generate similarity index 100% rename from qosmngr/files/linux/etc/uci-defaults/60-qos_queue_generate rename to qosmngr/files/linux/etc/uci-defaults/60-qos_config_generate diff --git a/qosmngr/files/linux/lib/qos/qos.sh b/qosmngr/files/linux/lib/qos/qos.sh index 435b7ea31..1f0ef45a7 100755 --- a/qosmngr/files/linux/lib/qos/qos.sh +++ b/qosmngr/files/linux/lib/qos/qos.sh @@ -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,79 @@ 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 + return + fi + handle_iptables_rules $line_cid + handle_policer_rules $line_cid + done < "$corder_file" } configure_classify() { #processing classify section + 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 + + 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 +617,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 +636,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 +668,7 @@ configure_policer() { configure_qos() { pre_configure_queue configure_queue + configure_classify configure_policer } @@ -420,6 +680,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