Skip to content

Commit

Permalink
ffda-wireless-rate-limiter: add package
Browse files Browse the repository at this point in the history
This adds a package which can be used to shape traffic on the wireless
interfaces interface-wide or per-client.

Signed-off-by: David Bauer <mail@david-bauer.net>
  • Loading branch information
blocktrron committed Aug 26, 2024
1 parent 0bc5c69 commit 833fccd
Show file tree
Hide file tree
Showing 3 changed files with 251 additions and 0 deletions.
48 changes: 48 additions & 0 deletions ffda-wireless-rate-limiter/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
include $(TOPDIR)/rules.mk

PKG_NAME:=ffda-wireless-rate-limiter
PKG_RELEASE:=1

PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=https://github.com/blocktrron/wireless-rate-limiter.git
PKG_SOURCE_DATE:=2024-08-24
PKG_SOURCE_VERSION:=1fedb08ba7ce347d5c3f7c8ddcac8a5e2f5d14b6

PKG_MAINTAINER:=David Bauer <mail@david-bauer.net>
PKG_LICENSE:=GPL-2.0

include $(TOPDIR)/../package/gluon.mk
include $(INCLUDE_DIR)/cmake.mk

CMAKE_SOURCE_SUBDIR:=src

define Package/ffda-wireless-rate-limiter
TITLE:=Wireless rate-limiter
DEPENDS:=+libubox +libubus +libblobmsg-json +tc +kmod-sched-core +kmod-ifb +gluon-core
endef

define Package/ffda-wireless-rate-limiter/description
Package to impose per-interface and per-client rate limits on a wireless interface
endef

define Package/ffda-wireless-rate-limiter/conffiles
/etc/config/wireless-rate-limiter
endef

define Package/ffda-wireless-rate-limiter/install
$(INSTALL_DIR) $(1)/usr/bin $(1)/etc/init.d $(1)/etc/config $(1)/lib/wireless-rate-limiter $(1)/lib/gluon/upgrade

$(INSTALL_BIN) $(PKG_BUILD_DIR)/wireless-rate-limiter $(1)/usr/bin/wireless-rate-limiter

$(INSTALL_BIN) $(PKG_BUILD_DIR)/openwrt/wireless-rate-limiter/files/wireless-rate-limiter.init $(1)/etc/init.d/wireless-rate-limiter

$(CP) $(PKG_BUILD_DIR)/openwrt/wireless-rate-limiter/files/wireless-rate-limiter.uci $(1)/etc/config/wireless-rate-limiter

$(CP) $(PKG_BUILD_DIR)/openwrt/wireless-rate-limiter/files/htb-shared.sh $(1)/lib/wireless-rate-limiter/htb-shared.sh
$(INSTALL_BIN) $(PKG_BUILD_DIR)/openwrt/wireless-rate-limiter/files/htb-client.sh $(1)/lib/wireless-rate-limiter/htb-client.sh
$(INSTALL_BIN) $(PKG_BUILD_DIR)/openwrt/wireless-rate-limiter/files/htb-netdev.sh $(1)/lib/wireless-rate-limiter/htb-netdev.sh

$(INSTALL_BIN) ./files/wireless-rate-limiter.upgrade.lua $(1)/lib/gluon/upgrade/880-wireless-rate-limiter
endef

$(eval $(call BuildPackageGluon,ffda-wireless-rate-limiter))
83 changes: 83 additions & 0 deletions ffda-wireless-rate-limiter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# ffda-wireless-rate-limiter

This package provides a rate-limiter which can shape traffic per client
and per interface. The limit is user-configurable and defaults can be
applied and updated via the site-config.

## Examples
### Site

Below you can see an example of how to configure the rate-limiter
in the site-configuration.

Each client is shaped to a different rate.

- On 5 GHz, only the uplink will be shaped.
- On 2.4 GHz, both uplink and downlink will be shaped. Additionally,
all traffic on the 2.4 GHz radios will each be shaped to a maximum
of 10 Mbit/s downlink and 5 Mbit/s uplink.

When using OWE, the limits are imposed for the unencrypted and OWE network
indepedently.

```lua
wifi24 = {
channel = 5, -- 2432 MHz

rate_limit = {
client = {
down = 6000, -- 6 Mbit/s
up = 3000, -- 3 Mbit/s
},
iface = {
down = 10000, -- 10 Mbit/s
up = 5000, -- 5 Mbit/s
},
},

mesh = {
mcast_rate = 12000,
},
},
wifi5 = {
channel = 48, -- 5230 MHz
outdoor_chanlist = '96-116 132-140',

rate_limit = {
client = {
up = 6000, -- 6 Mbit/s
},
},

mesh = {
mcast_rate = 12000,
},
},
```

### UCI

The rate-limiter can also be configured via UCI. The following example is
for a configuration which is equivalent to the site-configuration above.

Take note however: If you intend to remove
limits imposed by the site-configuration, you need to set the values to
`0` instead of removing the sections.

```sh
uci set gluon.rate_limit_2g=ffda-rate-limit
uci set gluon.rate_limit_2g.band='2g'
uci set gluon.rate_limit_2g.client_down=6000
uci set gluon.rate_limit_2g.client_up=3000
uci set gluon.rate_limit_2g.iface_down=10000
uci set gluon.rate_limit_2g.iface_up=5000

uci set gluon.rate_limit_5g=ffda-rate-limit
uci set gluon.rate_limit_5g.band='5g'
uci set gluon.rate_limit_5g.client_down=0
uci set gluon.rate_limit_5g.client_up=2000
uci set gluon.rate_limit_5g.iface_down=10000
uci set gluon.rate_limit_5g.iface_up=5000

uci commit gluon
```
120 changes: 120 additions & 0 deletions ffda-wireless-rate-limiter/files/wireless-rate-limiter.upgrade.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/lua

local uci = require('simple-uci').cursor()
local wireless = require('gluon.wireless')

local function get_uci_section_for_band(band)
local section_name = nil
uci:foreach('gluon', 'ffda-rate-limit', function(section)
if section.band == band then
section_name = section['.name']
end
end)

return section_name
end

local function get_user_limit(band, limit_type)
local uci_section = get_uci_section_for_band(band)
if uci_section then
return uci:get('gluon', uci_section, limit_type)
end

return nil
end

local function wireless_limits_get()
local output_limits = {}
wireless.foreach_radio(uci, function(radio, _, site_config)
local radio_band = radio.band
local radio_index = radio['.name']:match('^radio(%d+)$')

local limit_table = {
client = {
up = {
['user'] = get_user_limit(radio_band, 'client_up'),
['site'] = site_config.rate_limit.client.up(0)
},
down = {
['user'] = get_user_limit(radio_band, 'client_down'),
['site'] = site_config.rate_limit.client.down(0)
}
},
iface = {
up = {
['user'] = get_user_limit(radio_band, 'iface_up'),
['site'] = site_config.rate_limit.up(0)
},
down = {
['user'] = get_user_limit(radio_band, 'iface_down'),
['site'] = site_config.rate_limit.down(0)
}
}
}

output_limits[radio_band] = {
index = radio_index,
limits = {
client = {
up = limit_table.client.up.user or limit_table.client.up.site,
down = limit_table.client.down.user or limit_table.client.down.site
},
iface = {
up = limit_table.iface.up.user or limit_table.iface.up.site,
down = limit_table.iface.down.user or limit_table.iface.down.site
}
},
}
end)

return output_limits
end

local function wireless_limits_set(index, limits)
local limit_applied = false
for type_key, type_value in pairs(limits) do
local limit_down = type_value.down
local limit_up = type_value.up

for _, iface_type in ipairs({'client', 'owe'}) do
local section_name = type_key .. '_limit_' .. iface_type .. index

uci:delete('wireless-rate-limiter', section_name)

if limit_down ~= 0 or limit_up ~= 0 then
local section_type = type_key == 'client' and 'limit-client' or 'limit-interface'
uci:section('wireless-rate-limiter', section_type, section_name, {
interface = iface_type .. index,
download = limit_down,
upload = limit_up,
disabled = 0
})

limit_applied = true
end
end
end

return limit_applied
end

-- Delete existing config
uci:delete_all('wireless-rate-limiter', 'limit-client')
uci:delete_all('wireless-rate-limiter', 'limit-interface')

-- Apply config
local limits = wireless_limits_get()
local limits_applied = false
for _, value in pairs(limits) do
if wireless_limits_set(value.index, value.limits) then
limits_applied = true
end
end

-- Decide daemon necessity
uci:set('wireless-rate-limiter', 'core', 'disabled', not limits_applied)

-- Save
uci:commit('wireless-rate-limiter')

return 0

0 comments on commit 833fccd

Please sign in to comment.