#!/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_rate"
}

# Configure ingress rate limit
config_ingress_rate_limit() {
    local ifname="$1"
    local ingress_rate="$2"
    local in_burst_size="$3"

    if [ -z "$ingress_rate" ] || [ "$ingress_rate" -lt 1000 ] ; then
        return
    fi

    ingress_rate=$((ingress_rate / 1000))

    if [ -n "$in_burst_size" ] && [ "$in_burst_size" -ge 1000 ]; then
        in_burst_size="$((in_burst_size / 1000))"
    fi

    hw_policer_set_ingress_rate "$ifname" "$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" 1

    # 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

    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() {
    # initialize ratelimit params
    /userfs/bin/femgr ratelimit set rx_mode 1 2 0
    /userfs/bin/qdmamgr_wan set general_rx_init enable trtcm 8 125

    for intf in $(jsonfilter -i /etc/board.json -e @.network.lan.ports[*] -e @.network.lan.device -e @.network.wan.device | xargs); 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
}
