nft-qos: support mac address based speed limit
authorTong Zhang <ztong0001@gmail.com>
Fri, 14 Aug 2020 11:21:33 +0000 (07:21 -0400)
committerTong Zhang <ztong0001@gmail.com>
Wed, 19 Aug 2020 13:39:57 +0000 (09:39 -0400)
This patch makes it possible to configure and limit per-client internet
speed based on MAC address and it can work with SQM.
This feature is what OpenWRT currently lacks. This patch is largely based
on static.sh and the configuration file is similar to original nft-qos.

New configuration options and examples are listed below

config default 'default'
    option limit_mac_enable '1'
config client
option drunit 'kbytes'
option urunit 'kbytes'
option hostname 'tv-box'
option macaddr 'AB:CD:EF:01:23:45'
option drate '1000'
option urate '50'
config client
option drunit 'kbytes'
option urunit 'kbytes'
option hostname 'my-pc'
option macaddr 'AB:CD:EF:01:23:46'
option drate '3000'
option urate '2000'

limit_mac_enable - enable rate limit based on MAC address
drunit - download rate unit
urunit - upload rate unit
macaddr - client MAC address
drate - download rate
urate - upload rate

Signed-off-by: Tong Zhang <ztong0001@gmail.com>
net/nft-qos/Makefile
net/nft-qos/files/lib/core.sh
net/nft-qos/files/lib/mac.sh [new file with mode: 0644]
net/nft-qos/files/nft-qos.config
net/nft-qos/files/nft-qos.init

index bafbaabd3637c81bccae0222e2b8ab836c8ee9c8..b6ad0fd327d38bdf690d2d5ff31629e5df6a545b 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=nft-qos
 PKG_VERSION:=1.0.6
-PKG_RELEASE:=1
+PKG_RELEASE:=2
 PKG_LICENSE:=GPL-2.0
 
 PKG_MAINTAINER:=Rosy Song <rosysong@rosinson.com>
index d3c9d641f24785d7363f8e27538b0107aee19df6..8b51122bb1b101793c273515f4f102dd85cb3698 100644 (file)
@@ -34,6 +34,17 @@ qosdef_append_rule_ip_limit() { # <ipaddr> <operator> <unit> <rate>
            "\t\tip $operator $ipaddr limit rate over $rate $unit/second drop\n"
 }
 
+# qosdef_append_rule_{MATCH}_{STATEMENT}
+qosdef_append_rule_mac_limit() { # <macaddr> <operator> <unit> <rate>
+       local macaddr=$1
+       local operator=$2
+       local unit=$3
+       local rate=$4
+
+       qosdef_appendx \
+           "\t\tether $operator $macaddr limit rate over $rate $unit/second drop\n"
+}
+
 # qosdef_append_rule_{MATCH}_{POLICY}
 qosdef_append_rule_ip_policy() { # <operator> <ipaddr> <policy>
        qosdef_appendx "\t\tip $1 $2 $3\n"
diff --git a/net/nft-qos/files/lib/mac.sh b/net/nft-qos/files/lib/mac.sh
new file mode 100644 (file)
index 0000000..ed10704
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/sh
+# based on static.sh
+# Copyright (C) 2020 Tong Zhang<ztong0001@gmail.com>
+#
+
+. /lib/nft-qos/core.sh
+
+qosdef_validate_mac() {
+       uci_load_validate nft-qos default "$1" "$2" \
+               'limit_mac_enable:bool:0'
+}
+
+# append rule for mac qos
+qosdef_append_rule_mac() { # <section> <operator>
+       local macaddr unit rate
+       local operator=$2
+
+       config_get macaddr $1 macaddr
+       if [ "$operator" = "saddr" ]; then
+               config_get unit $1 urunit
+               config_get rate $1 urate
+       else
+               config_get unit $1 drunit
+               config_get rate $1 drate
+       fi
+
+       [ -z "$macaddr" ] && return
+
+       qosdef_append_rule_mac_limit $macaddr $operator $unit $rate
+}
+
+# append chain for mac qos
+qosdef_append_chain_mac() { # <hook> <name> <section>
+       local hook=$1 name=$2
+       local config=$3 operator
+
+       case "$name" in
+               download) operator="daddr";;
+               upload) operator="saddr";;
+       esac
+
+       qosdef_appendx "\tchain $name {\n"
+       qosdef_append_chain_def filter $hook 0 accept
+       config_foreach qosdef_append_rule_mac $config $operator
+       qosdef_appendx "\t}\n"
+}
+
+qosdef_flush_mac() {
+       if [ -n "$NFT_QOS_HAS_BRIDGE" ]; then
+               qosdef_flush_table bridge nft-qos-mac
+       else
+               qosdef_flush_table "$NFT_QOS_INET_FAMILY" nft-qos-mac
+       fi
+}
+
+# limit rate by mac address init
+qosdef_init_mac() {
+       local hook_ul="prerouting" hook_dl="postrouting"
+
+       [ "$2" = 0 ] || {
+               logger -t nft-qos-mac "validation failed"
+               return 1
+       }
+
+       [ $limit_mac_enable -eq 0 ] && return 1
+
+       table_name=$NFT_QOS_INET_FAMILY
+       if [ -z "$NFT_QOS_HAS_BRIDGE" ]; then
+               hook_ul="postrouting"
+               hook_dl="prerouting"
+       else
+               table_name="bridge"
+       fi
+
+       qosdef_appendx "table $table_name nft-qos-mac {\n"
+       qosdef_append_chain_mac $hook_ul upload client
+       qosdef_append_chain_mac $hook_dl download client
+       qosdef_appendx "}\n"
+}
index 82e3b3928d710f9f10656d8805422507d28e76c5..ea1f4a7ba9c8ece82844147f9ec4c6123cc7ffbe 100644 (file)
@@ -51,6 +51,9 @@ config default default
        # list limit_whitelist '192.168.1.0/24'
        # list limit_whitelist 'ABCD:CDEF::1/64'
 
+       # Option for Mac address based traffic control
+       option limit_mac_enable '0'
+
        # Options for Traffic Priority
        option priority_enable '0'
        option priority_netdev 'lan'
@@ -73,6 +76,15 @@ config default default
 #      option ipaddr 'ABCD:FFED::1/64'
 #      option rate '1024'
 #
+# For MAC address based traffic control Samples :
+#
+#config client
+#      option drunit 'kbytes'
+#      option urunit 'kbytes'
+#      option hostname 'tvbox'
+#      option macaddr '00:00:00:00:00:00'
+#      option drate '300'
+#      option urate '30'
 #
 # Traffic Priority Samples :
 #
index 7a56ec7c69149ab632ed715a401cfda47c5773c1..dcd487fa5450876612156e35b0b973df89295c10 100755 (executable)
@@ -7,6 +7,7 @@
 . /lib/nft-qos/monitor.sh
 . /lib/nft-qos/dynamic.sh
 . /lib/nft-qos/static.sh
+. /lib/nft-qos/mac.sh
 . /lib/nft-qos/priority.sh
 
 START=99
@@ -19,6 +20,7 @@ service_triggers() {
        qosdef_validate_dynamic
        qosdef_validate_static
        qosdef_validate_priority
+       qosdef_validate_mac
        procd_close_validate
 }
 
@@ -26,6 +28,7 @@ start_service() {
        config_load nft-qos
 
        qosdef_init_env
+       qosdef_flush_mac
        qosdef_flush_static
        qosdef_flush_dynamic
        qosdef_remove_priority
@@ -34,6 +37,7 @@ start_service() {
        qosdef_init_monitor
        qosdef_validate_dynamic default qosdef_init_dynamic
        qosdef_validate_static default qosdef_init_static
+       qosdef_validate_mac default qosdef_init_mac
        qosdef_validate_priority default qosdef_init_priority
        qosdef_init_done
        qosdef_start
@@ -42,6 +46,7 @@ start_service() {
 stop_service() {
        qosdef_flush_dynamic
        qosdef_flush_static
+       qosdef_flush_mac
        qosdef_remove_priority
        qosdef_clean_cache
 }