From 52831a00bec8e3676e2747029c0349f6be9c2593 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Fri, 4 Feb 2022 20:34:06 +0100 Subject: [PATCH] fw4: improve flowtable handling - Delete the flowtable while loading the rulset in case it exists already since flowtable with offload flag canot overwrite ones without and vice versa - Resolve higher level devices such as 802.1q or bridge devices to lower, offload capable ones in case hardware offloading is requested - Revert disabling of "flow_offloading_hw" option Signed-off-by: Jo-Philipp Wich --- root/usr/share/firewall4/main.uc | 77 ++++++++++++++++++- root/usr/share/firewall4/templates/ruleset.uc | 3 + root/usr/share/ucode/fw4.uc | 2 +- 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/root/usr/share/firewall4/main.uc b/root/usr/share/firewall4/main.uc index d7dfdb0..839346b 100644 --- a/root/usr/share/firewall4/main.uc +++ b/root/usr/share/firewall4/main.uc @@ -1,6 +1,8 @@ {% let fw4 = require("fw4"); +let ubus = require("ubus"); +let fs = require("fs"); /* Find existing sets. * @@ -94,14 +96,81 @@ function reload_sets() { } } -function render_ruleset(use_statefile) { +function resolve_lower_devices(devstatus, devname) { + let dir = fs.opendir("/sys/class/net/" + devname); + let devs = []; + + if (dir) { + if (!devstatus || devstatus[devname]?.["hw-tc-offload"]) { + push(devs, devname); + } + else { + let e; + + while ((e = dir.read()) != null) + if (index(e, "lower_") === 0) + push(devs, ...resolve_lower_devices(devstatus, substr(e, 6))); + } + + dir.close(); + } + + return devs; +} + +function resolve_offload_devices() { + if (!fw4.default_option("flow_offloading")) + return []; + + let devstatus = null; let devices = []; - fw4.load(use_statefile); + if (fw4.default_option("flow_offloading_hw")) { + let bus = require("ubus").connect(); + + if (bus) { + devstatus = bus.call("network.device", "status") || {}; + bus.disconnect(); + } + } - map(fw4.zones(), zone => push(devices, ...zone.match_devices)); + for (let zone in fw4.zones()) + for (let device in zone.match_devices) + push(devices, ...resolve_lower_devices(devstatus, device)); + + return uniq(devices); +} + +function check_flowtable() { + let nft = fs.popen("nft --terse --json list flowtables inet"); + let info; + + if (nft) { + try { + info = json(nft.read("all")); + } + catch (e) { + info = {}; + } + + nft.close(); + } + + for (let item in info?.nftables) + if (item?.flowtable?.table == "fw4" && item?.flowtable?.name == "ft") + return true; + + return false; +} + +function render_ruleset(use_statefile) { + fw4.load(use_statefile); - include("templates/ruleset.uc", { fw4, type, exists, length, include, devices: sort(devices) }); + include("templates/ruleset.uc", { + fw4, type, exists, length, include, + devices: resolve_offload_devices(), + flowtable: check_flowtable() + }); } function lookup_network(net) { diff --git a/root/usr/share/firewall4/templates/ruleset.uc b/root/usr/share/firewall4/templates/ruleset.uc index 004cfca..8020bed 100644 --- a/root/usr/share/firewall4/templates/ruleset.uc +++ b/root/usr/share/firewall4/templates/ruleset.uc @@ -1,5 +1,8 @@ table inet fw4 flush table inet fw4 +{% if (flowtable): %} +delete flowtable inet fw4 ft +{% endif %} table inet fw4 { {% if (fw4.default_option("flow_offloading") && length(devices) > 0): %} diff --git a/root/usr/share/ucode/fw4.uc b/root/usr/share/ucode/fw4.uc index 7a2cd75..175883f 100644 --- a/root/usr/share/ucode/fw4.uc +++ b/root/usr/share/ucode/fw4.uc @@ -1695,7 +1695,7 @@ return { custom_chains: [ "bool", null, UNSUPPORTED ], disable_ipv6: [ "bool", null, UNSUPPORTED ], flow_offloading: [ "bool", "0" ], - flow_offloading_hw: [ "bool", "0", UNSUPPORTED ] + flow_offloading_hw: [ "bool", "0" ] }); if (defs.synflood_protect === null) -- 2.30.2