summaryrefslogtreecommitdiffstats
path: root/net/tcfilter/README.md
blob: cc8c49cac6fa145276419c665f7b2d76cb6b23f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# tcfilter

A thin UCI front-end for persistent `tc filter ... ingress` rules.

It does **not** model the flower match/action fields. You write that part as
raw `tc` syntax in `option spec`; the package only manages the device, the
`pref` number, enable/disable, persistence across boot, and re-applying the
rules when the network is reconfigured.

Meant for driving hardware tc-flower offload (e.g. the Realtek DSA PIE
offload) where no higher-level config layer exists.

## Config

`/etc/config/tcfilter`:

```
config tcfilter 'global'
	option enabled '1'

config rule
	option label   'Drop-HomePlug-AV (FRITZ!Box)'
	option device  'lan1'
	option enabled '1'
	option pref    '49152'
	option spec    'protocol 0x88e1 flower skip_sw action drop'
```

The shipped default config carries a few such rules with `enabled '0'`
as ready-to-use examples (FRITZ!Box powerline discovery, mDNS) — set
`device` and flip `enabled` to `1`.

`label` is optional and cosmetic — it only tags the log messages and the
LuCI rows.

`spec` is everything that would follow

```
tc filter add dev <device> ingress pref <pref>
```

* `pref` is **required** — it is how the rule is deleted again.
* Use `skip_sw` so a match the hardware cannot offload fails loudly instead
  of silently installing in software.
* One `rule` per `pref` per device.

## Commands

```
/etc/init.d/tcfilter start        # apply all enabled rules
/etc/init.d/tcfilter stop         # remove them
/etc/init.d/tcfilter reload       # stop + start
/etc/init.d/tcfilter show         # tc -s filter show for every configured device
/etc/init.d/tcfilter reapply_dev lan1
```

## Notes / limitations

* ingress / `clsact` only.
* The `clsact` qdisc is added if missing but never removed on stop (other
  users may share it); only the individual filters are deleted.
* Installed `(device, pref)` pairs are tracked in `/var/run/tcfilter.state`
  so a rule removed from the config is still torn down on the next reload.
* Re-apply hooks: `hotplug.d/iface` runs `start` on `ifup`, `hotplug.d/net`
  runs `reapply_dev` on netdev `add`. `start` is idempotent.
* A `procd_add_reload_trigger` reloads the service when the `tcfilter`
  config changes, so LuCI Save & Apply and
  `uci commit tcfilter && reload_config` take effect on their own; a bare
  `uci commit` still needs an explicit `/etc/init.d/tcfilter reload`.
* No dry-run validation — an invalid `spec` is reported via logread only.
* Free-form `spec` is passed to `tc` by word-split (no shell). Anyone who can
  edit the config can install redirect/mirror rules, i.e. tap traffic.

### Hardware packet counters (Realtek rtl930x PIE offload)

Older rtl930x kernels mis-read the per-rule LOG packet counter: with more
than one offloaded flower rule, only the rule whose PIE rule id was
even-aligned reported a working `tc -s` hardware packet count and the
others stayed at 0 (`rtl930x_packet_cntr_read()` assumed the L3-route
counter layout). Dropping / trapping / redirecting was never affected.

Fixed in the kernel driver upstream (openwrt/openwrt#24994); every
offloaded rule now reports its own count. Firmware built before that
patch still shows the old behaviour.