#!/bin/sh
# Common classifier library

#counter variable to assign classify order value if not added in config
temp_order=1

# 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 rules
    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
}

# Handle classify section
handle_classify() {

    local corder_file="/tmp/qos/classify.order"
    local interf=""

    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"
    # Handling config for DSCP to pbit conversion:
    # For a given port there can be 64 dscp2pbit mapping and each mapping is
    # represented by one UCI config classify section. So there can be 64 possible
    # config classify.
    #
    # For each port, traverse all config classify section and
    # extract DSCP to P-bit conversion info.
    # generate, dscp2pbit mapping list.
    # Then apply dscp2pbit rule
    for interf in $(jsonfilter -i /etc/board.json -e @.network.lan.ports[*] -e @.network.lan.device -e @.network.wan.device | xargs); do
        handle_ebtables_dscp2pbit "$interf"
        [ -n "$BR_RULE_DSCP2PBIT" ] && broute_apply_dscp2pbit_rule
    done
}

# 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
    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.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

    /etc/init.d/bridging restart # Imitate the existing behaviour.
    create_iptables_chains
}

flush_chains() {
    flush_ebtables_chains
    flush_iptables_chains
}
