From 920a7d03467295fcfb3c9b3ed9dc37bc3c43c542 Mon Sep 17 00:00:00 2001 From: subramanianc Date: Fri, 10 Mar 2023 10:25:42 +0530 Subject: [PATCH] qos: modularisation of qos code --- .../airoha/lib/qos/common/chains.ebtables.sh | 385 -------- qosmngr/files/airoha/lib/qos/common/chains.sh | 12 - qosmngr/files/airoha/lib/qos/qos.sh | 14 +- qosmngr/files/broadcom/lib/qos/qos.sh | 841 ++---------------- .../qos/common => common/lib/qos}/classify.sh | 22 +- qosmngr/files/common/lib/qos/ebtables.sh | 405 +++++++++ .../lib/qos/iptables.sh} | 0 qosmngr/files/linux/lib/qos/qos.sh | 415 ++------- 8 files changed, 583 insertions(+), 1511 deletions(-) delete mode 100755 qosmngr/files/airoha/lib/qos/common/chains.sh rename qosmngr/files/{airoha/lib/qos/common => common/lib/qos}/classify.sh (88%) create mode 100755 qosmngr/files/common/lib/qos/ebtables.sh rename qosmngr/files/{airoha/lib/qos/common/chains.iptables.sh => common/lib/qos/iptables.sh} (100%) diff --git a/qosmngr/files/airoha/lib/qos/common/chains.ebtables.sh b/qosmngr/files/airoha/lib/qos/common/chains.ebtables.sh index d9a8f6125..7ea0dbf72 100755 --- a/qosmngr/files/airoha/lib/qos/common/chains.ebtables.sh +++ b/qosmngr/files/airoha/lib/qos/common/chains.ebtables.sh @@ -1,97 +1,6 @@ #!/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" @@ -100,22 +9,6 @@ ebt_match_ipv6_dscp() { 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}0 --mark-target ACCEPT" if [ -n "$BR6_RULE" ]; then @@ -123,92 +16,6 @@ broute_rule_set_traffic_class() { 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" @@ -259,195 +66,3 @@ broute_ipv6_rule_options() 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 -} - diff --git a/qosmngr/files/airoha/lib/qos/common/chains.sh b/qosmngr/files/airoha/lib/qos/common/chains.sh deleted file mode 100755 index d26146ee2..000000000 --- a/qosmngr/files/airoha/lib/qos/common/chains.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh -# Set up or flush all chains - -setup_qos() { - create_ebtables_chains - create_iptables_chains -} - -flush_chains() { - flush_ebtables_chains - flush_iptables_chains -} diff --git a/qosmngr/files/airoha/lib/qos/qos.sh b/qosmngr/files/airoha/lib/qos/qos.sh index e2a0a4734..5daa6f1a9 100755 --- a/qosmngr/files/airoha/lib/qos/qos.sh +++ b/qosmngr/files/airoha/lib/qos/qos.sh @@ -4,15 +4,15 @@ . /lib/functions.sh include /lib/ethernet -. /lib/qos/common/chains.sh +. /lib/qos/iptables.sh . /lib/qos/common/chains.ebtables.sh -. /lib/qos/common/chains.iptables.sh -. /lib/qos/common/classify.sh +. /lib/qos/ebtables.sh +. /lib/qos/ip_rule.sh +. /lib/qos/classify.sh . /lib/qos/common/policer.sh . /lib/qos/common/queue.sh . /lib/qos/common/shaper.sh . /lib/qos/airoha.sh -. /lib/qos/ip_rule.sh configure_qos() { # queue configuration is being done after shaper configuration, @@ -24,6 +24,9 @@ configure_qos() { configure_queue configure_policer configure_classify + if [ -f "/tmp/qos/classify.ebtables" ]; then + sh /tmp/qos/classify.ebtables + fi } reload_qos() { @@ -40,6 +43,9 @@ reload_qos() { ;; classify) configure_classify + if [ -f "/tmp/qos/classify.ebtables" ]; then + sh /tmp/qos/classify.ebtables + fi ;; policer) configure_policer diff --git a/qosmngr/files/broadcom/lib/qos/qos.sh b/qosmngr/files/broadcom/lib/qos/qos.sh index ceb72a41a..15d59c679 100755 --- a/qosmngr/files/broadcom/lib/qos/qos.sh +++ b/qosmngr/files/broadcom/lib/qos/qos.sh @@ -4,18 +4,14 @@ include /lib/ethernet # include common code . /lib/qos/ip_rule.sh - -IP_RULE="" -BR_RULE="" -BR6_RULE="" +. /lib/qos/iptables.sh +. /lib/qos/ebtables.sh +. /lib/qos/classify.sh 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 - cfg_name="" cfg_type="" @@ -172,217 +168,6 @@ handle_queue() { Q_COUNT=$((Q_COUNT + 1)) } -#function to handle a policer section -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 [ $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 - - # Call tmctl which is a broadcomm command to configure policer. - tmctl createpolicer --dir $dir --pid $POLICER_COUNT --ptype $meter --cir $cir --cbs $cbs --ebs $ebs --pir $pir --pbs $pbs - - POLICER_COUNT=$((POLICER_COUNT + 1)) -} - -#function to handle a shaper section -handle_shaper() { - sid="$1" #queue section ID - - config_get is_enable "$sid" "enable" - # no need to configure disabled queues - if [ $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 [ $rate -lt 1000 ];then - return - fi - - rate=$(($rate / 1000)) - config_get bs "$sid" "burst_size" - tmctl setportshaper --devtype 0 --if $ifname --shapingrate $rate --burstsize $bs -} - -setup_qos() { - if [ ! -d "/tmp/qos" ]; then - mkdir -p /tmp/qos - fi - if [ ! -f "/tmp/qos/qos" ]; then - touch /tmp/qos/qos - cp /etc/config/qos /tmp/qos/qos - fi - - 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 - - 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_chains() { - echo "ebtables -t broute -F qos" > /tmp/qos/classify.ebtables - - 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 -} - -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() { - # 5.04 onwards the vlan extension in ebtables is used for classification - # on the basis of vlan params which needs proto to be defined as 802_1Q in - # order to add a rule, now, proto can also be defined by specifying proto uci - # option as well as the rule may have a vlan id as well in which case the - # proto will already be present, hence, this check to not add --proto more - # than once - 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() { - #when ethertype is not configured by user then both proto rules of ipv4 - #and ipv6 to be installed so update BR6_RULE string as well otherwise - #update BR_RULE only for installation of ipv6 proto rule only. - if [ ! -z "$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() { - #when ethertype is not configured by user then both proto rules of ipv4 - #and ipv6 to be installed so update BR6_RULE string as well otherwise - #update BR_RULE only for installation of ipv6 proto rule only. - if [ ! -z "$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() { - #when ethertype is not configured by user then both proto rules of ipv4 - #and ipv6 to be installed so update BR6_RULE string as well otherwise - #update BR_RULE only for installation of ipv6 proto rule only. - if [ ! -z "$BR6_RULE" ]; then - BR6_RULE="$BR6_RULE --ip6-proto $1" - else - BR_RULE="$BR_RULE --ip6-proto $1" - fi -} - ebt_match_ipv6_dscp() { #when ethertype is not configured by user then both proto rules of ipv4 #and ipv6 to be installed so update BR6_RULE string as well otherwise @@ -403,112 +188,6 @@ broute_filter_on_dscp() { BR_RULE="$BR_RULE --ip-dscp-extend $tos_hex" } -broute_filter_on_vid() { - - if [ $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() { - #when ethertype is not configured by user then both proto rules of ipv4 - #and ipv6 to be installed so update BR6_RULE string as well otherwise - #update BR_RULE only for installation of ipv6 proto rule only. - BR_RULE="$BR_RULE -j mark --mark-or 0x$1 --mark-target ACCEPT" - if [ ! -z "$BR6_RULE" ]; then - BR6_RULE="$BR6_RULE -j mark --mark-or 0x$1 --mark-target ACCEPT" - fi -} - -broute_append_rule() { - #when ethertype is not configured by user then both proto rules of ipv4 - #and ipv6 to be installed otherwise install ipv6 proto rule only. - 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 [ ! -z "$src_ip" ]; then - $match_src_ip_func "$src_ip" - fi - - if [ ! -z "$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 ! [ -z $src_port ] && ! [ -z $src_port_range ]; then - $match_src_port_func "$src_port:$src_port_range" - elif [ ! -z $src_port ]; then - $match_src_port_func $src_port - fi - - if ! [ -z $dst_port ] && ! [ -z $dst_port_range ]; then - $match_dst_port_func "$dst_port:$dst_port_range" - elif [ ! -z $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 @@ -561,371 +240,66 @@ broute_ipv6_rule_options() fi } -handle_ebtables_rules() { - 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 +broute_rule_set_traffic_class() { + #when ethertype is not configured by user then both proto rules of ipv4 + #and ipv6 to be installed so update BR6_RULE string as well otherwise + #update BR_RULE only for installation of ipv6 proto rule only. + BR_RULE="$BR_RULE -j mark --mark-or 0x$1 --mark-target ACCEPT" + if [ ! -z "$BR6_RULE" ]; then + BR6_RULE="$BR6_RULE -j mark --mark-or 0x$1 --mark-target ACCEPT" fi +} - if [ -n "$src_mac" ]; then - broute_filter_on_src_mac $src_mac - is_l2_rule=1 - fi +#function to handle a policer section +handle_policer() { + local p_sec="$1" # policer section ID + local dir=1 # default direction, upstream - if [ -n "$dst_mac" ]; then - broute_filter_on_dst_mac $dst_mac - is_l2_rule=1 - fi + config_get is_enable "$p_sec" "enable" - 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$dest_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 - ip_version=1 #neither ether_type nor ip address used - #ethertype is not configured by user so install - #both proto ipv4 and ipv6 rule - 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" -a -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 dstination mac - if [ -n "$dst_dhcp_options" -a -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 + #no need to configure disabled policer + if [ $is_enable == '0' ]; then return fi - [ -n "$traffic_class" ] && broute_rule_set_traffic_class $traffic_class + 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 - [ -n "$BR_RULE" ] && broute_append_rule + # Call tmctl which is a broadcomm command to configure policer. + tmctl createpolicer --dir $dir --pid $POLICER_COUNT --ptype $meter --cir $cir --cbs $cbs --ebs $ebs --pir $pir --pbs $pbs + + POLICER_COUNT=$((POLICER_COUNT + 1)) } -init_iptables_rule() { - IP_RULE="" -} +#function to handle a shaper section +handle_shaper() { + sid="$1" #queue section ID -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/0x$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 + config_get is_enable "$sid" "enable" + # no need to configure disabled queues + if [ $is_enable == '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_prerouting" $ip_version - 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 [ $rate -lt 1000 ];then + return + fi + + rate=$(($rate / 1000)) + config_get bs "$sid" "burst_size" + tmctl setportshaper --devtype 0 --if $ifname --shapingrate $rate --burstsize $bs } assign_policer_to_port() { @@ -1015,66 +389,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() { - - local corder_file="/tmp/qos/classify.order" - - while read -r line; do - line_cid=${line#*_} - - # add ip rule only for classify rules which has non empty - # value forwarding policy option - # if forwarding policy option value empty then add iptables/ - # ip6tables/ebtables/rate_limit rules - config_get fwding_policy "$line_cid" "forwarding_policy" - if [ -n "$fwding_policy" ]; then - handle_ip_rule $line_cid $fwding_policy - else - handle_ebtables_rules $line_cid - handle_iptables_rules $line_cid - handle_policer_rules $line_cid - fi - done < "$corder_file" -} - configure_shaper() { # Delete existing shaper for intf in $(db get hw.board.ethernetPortOrder); do @@ -1086,49 +400,6 @@ configure_shaper() { config_foreach handle_shaper shaper } -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 - rm -f /tmp/qos/classify.order - rm -f /tmp/qos/tmp_classify.order - rm -f /tmp/qos/classify.iprule - - #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 - touch /tmp/qos/classify.iprule - - #add flush chain rules - flush_chains - - #flush added ip rule - flush_ip_rule - - # Load UCI file - config_load qos - config_foreach handle_classify_order classify - sort_classify_by_order - handle_classify - - sh /tmp/qos/classify.ebtables - sh /tmp/qos/classify.iptables - sh /tmp/qos/classify.ip6tables - sh /tmp/qos/classify.iprule - - # broadcom recommends that each time traffic class is set, - # the flows should be flushed for the new mapping to take - # effect, it then makes sense to make it a part of the - # qosmngr package itself. - fcctl flush -} - pre_configure_queue() { # Delete queues for intf in $(db get hw.board.ethernetPortOrder); do @@ -1218,6 +489,14 @@ configure_qos() { configure_queue configure_policer configure_classify + if [ -f "/tmp/qos/classify.ebtables" ]; then + sh /tmp/qos/classify.ebtables + fi + # broadcom recommends that each time traffic class is set, + # the flows should be flushed for the new mapping to take + # effect, it then makes sense to make it a part of the + # qosmngr package itself. + fcctl flush } reload_qos() { @@ -1236,6 +515,14 @@ reload_qos() { configure_queue elif [ "$service_name" == "classify" ]; then configure_classify + if [ -f "/tmp/qos/classify.ebtables" ]; then + sh /tmp/qos/classify.ebtables + fi + # broadcom recommends that each time traffic class is set, + # the flows should be flushed for the new mapping to take + # effect, it then makes sense to make it a part of the + # qosmngr package itself. + fcctl flush elif [ "$service_name" == "policer" ]; then configure_policer fi diff --git a/qosmngr/files/airoha/lib/qos/common/classify.sh b/qosmngr/files/common/lib/qos/classify.sh similarity index 88% rename from qosmngr/files/airoha/lib/qos/common/classify.sh rename to qosmngr/files/common/lib/qos/classify.sh index a709e4a8d..f19ea84a3 100755 --- a/qosmngr/files/airoha/lib/qos/common/classify.sh +++ b/qosmngr/files/common/lib/qos/classify.sh @@ -45,7 +45,7 @@ handle_classify() { local corder_file="/tmp/qos/classify.order" while read -r line; do - line_cid=$(echo $line | cut -d '_' -f 2) + line_cid=${line#*_} # add ip rule only for classify rules which has non empty # value forwarding policy option @@ -94,9 +94,25 @@ configure_classify() { sort_classify_by_order handle_classify - sh /tmp/qos/classify.ebtables sh /tmp/qos/classify.iptables sh /tmp/qos/classify.ip6tables sh /tmp/qos/classify.iprule - +} + +setup_qos() { + if [ ! -d "/tmp/qos" ]; then + mkdir -p /tmp/qos + fi + if [ ! -f "/tmp/qos/qos" ]; then + touch /tmp/qos/qos + cp /etc/config/qos /tmp/qos/qos + fi + + create_ebtables_chains + create_iptables_chains +} + +flush_chains() { + flush_ebtables_chains + flush_iptables_chains } diff --git a/qosmngr/files/common/lib/qos/ebtables.sh b/qosmngr/files/common/lib/qos/ebtables.sh new file mode 100755 index 000000000..f99de85e9 --- /dev/null +++ b/qosmngr/files/common/lib/qos/ebtables.sh @@ -0,0 +1,405 @@ +#!/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() { + # 5.04 onwards the vlan extension in ebtables is used for classification + # on the basis of vlan params which needs proto to be defined as 802_1Q in + # order to add a rule, now, proto can also be defined by specifying proto uci + # option as well as the rule may have a vlan id as well in which case the + # proto will already be present, hence, this check to not add --proto more + # than once + 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() { + #when ethertype is not configured by user then both proto rules of ipv4 + #and ipv6 to be installed so update BR6_RULE string as well otherwise + #update BR_RULE only for installation of ipv6 proto rule only. + 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() { + #when ethertype is not configured by user then both proto rules of ipv4 + #and ipv6 to be installed so update BR6_RULE string as well otherwise + #update BR_RULE only for installation of ipv6 proto rule only. + 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() { + #when ethertype is not configured by user then both proto rules of ipv4 + #and ipv6 to be installed so update BR6_RULE string as well otherwise + #update BR_RULE only for installation of ipv6 proto rule only. + if [ -n "$BR6_RULE" ]; then + BR6_RULE="$BR6_RULE --ip6-proto $1" + else + BR_RULE="$BR_RULE --ip6-proto $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_append_rule() { + #when ethertype is not configured by user then both proto rules of ipv4 + #and ipv6 to be installed otherwise install ipv6 proto rule only. + 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 +} + +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 +} + diff --git a/qosmngr/files/airoha/lib/qos/common/chains.iptables.sh b/qosmngr/files/common/lib/qos/iptables.sh similarity index 100% rename from qosmngr/files/airoha/lib/qos/common/chains.iptables.sh rename to qosmngr/files/common/lib/qos/iptables.sh diff --git a/qosmngr/files/linux/lib/qos/qos.sh b/qosmngr/files/linux/lib/qos/qos.sh index 035be3a78..3cda4d097 100755 --- a/qosmngr/files/linux/lib/qos/qos.sh +++ b/qosmngr/files/linux/lib/qos/qos.sh @@ -4,17 +4,16 @@ # include common code . /lib/qos/ip_rule.sh +. /lib/qos/iptables.sh +. /lib/qos/ebtables.sh +. /lib/qos/classify.sh -IP_RULE="" MAJOR="" 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() { @@ -144,6 +143,88 @@ handle_queue() { Q_COUNT=$((Q_COUNT + 1)) } +ebt_match_ipv6_dscp() { + #when ethertype is not configured by user then both proto rules of ipv4 + #and ipv6 to be installed so update BR6_RULE string as well otherwise + #update BR_RULE only for installation of ipv6 proto rule only. + if [ ! -z "$BR6_RULE" ]; then + BR6_RULE="$BR6_RULE --ip6-tclass $1" + else + BR_RULE="$BR_RULE --ip6-tclass $1" + fi +} + +broute_filter_on_dscp() { + # The broadcom option --ip-dscp-extend actually accepts tos + # and not dscp and that too in hex, hence, perform the conversion + # from dscp in uci to tos first and then convert to hex + tos_val=$(($1<<2)) + tos_hex=$(printf "%x" $tos_val) + BR_RULE="$BR_RULE --ip-dscp-extend $tos_hex" +} + +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 [ ! -z $dscp_filter ]; then + broute_filter_on_dscp "$dscp_filter" + fi + + if [ ! -z $protocol ]; then + local proto_num=$(protocol_string_to_num "$protocol") + ebt_match_ip_protocol "$proto_num" + + #port installation for protol tcp/udp/sctp + 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 [ ! -z $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 [ ! -z $protocol ]; then + local proto_num=$(protocol_string_to_num "$protocol") + ebt_match_ipv6_protocol "$proto_num" + + #port installation for protol tcp/udp/sctp + 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 +} + +broute_rule_set_traffic_class() { + #when ethertype is not configured by user then both proto rules of ipv4 + #and ipv6 to be installed so update BR6_RULE string as well otherwise + #update BR_RULE only for installation of ipv6 proto rule only. + BR_RULE="$BR_RULE -j mark --mark-or 0x$1 --mark-target ACCEPT" + if [ ! -z "$BR6_RULE" ]; then + BR6_RULE="$BR6_RULE -j mark --mark-or 0x$1 --mark-target ACCEPT" + fi +} + #function to handle a policer section handle_policer() { local p_sec="$1" # policer section ID @@ -159,243 +240,6 @@ handle_policer() { POLICER_COUNT=$((POLICER_COUNT + 1)) } -setup_qos() { - if [ ! -d "/tmp/qos" ]; then - mkdir -p /tmp/qos - fi - - 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 - - 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_forward - ret=$? - [ $ret -eq 0 ] && iptables -w -t mangle -I FORWARD -j qos_forward - - iptables -w -t mangle -N qos_output - ret=$? - [ $ret -eq 0 ] && iptables -w -t mangle -I OUTPUT -j qos_output - - ip6tables -w -t mangle -N qos_prerouting - ret=$? - [ $ret -eq 0 ] && ip6tables -w -t mangle -I PREROUTING -j qos_prerouting - - ip6tables -t mangle -N qos_forward - ret=$? - [ $ret -eq 0 ] && ip6tables -t mangle -I FORWARD -j qos_forward - - ip6tables -t mangle -N qos_output - ret=$? - [ $ret -eq 0 ] && ip6tables -t mangle -I OUTPUT -j qos_output - -} - -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_prerouting" >> /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_prerouting" >> /tmp/qos/classify.ip6tables -} - -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-mark $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_prerouting" $ip_version - fi - fi -} - handle_policer_rules() { local c_sec=$1 local policer_name @@ -471,94 +315,6 @@ config_ingress_rate_limit() { } -# 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() { - local corder_file="/tmp/qos/classify.order" - while read -r line; do - line_cid=$(echo $line | cut -d '_' -f 2) - # add ip rule only for classify rules which has non empty - # value forwarding policy option - # if forwarding policy option value empty then add iptables/ - # ip6tables/ebtables/rate_limit rules - config_get fwding_policy "$line_cid" "forwarding_policy" - - if [ -n "$fwding_policy" ]; then - handle_ip_rule $line_cid $fwding_policy - else - handle_iptables_rules $line_cid - handle_policer_rules $line_cid - fi - done < "$corder_file" -} - -configure_classify() { - #processing classify section - rm -f /tmp/qos/classify.iptables - rm -f /tmp/qos/classify.ip6tables - rm -f /tmp/qos/classify.order - rm -f /tmp/qos/classify.iprule - - # 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/classify.iprule - - flush_chains - - #flush added ip rule - flush_ip_rule - - # Load UCI file - config_load qos - config_foreach handle_classify_order classify - sort_classify_by_order - handle_classify - - sh /tmp/qos/classify.iptables - sh /tmp/qos/classify.ip6tables - sh /tmp/qos/classify.iprule - -} - pre_configure_queue() { # Delete queues for intf in $(db get hw.board.ethernetPortOrder); do @@ -676,7 +432,6 @@ configure_policer() { echo $POLICER_COUNT > /tmp/qos/max_policer_inst } - configure_qos() { pre_configure_queue configure_queue