Hi! Auto-loading only the required modules definetly helps a lot for low CPU power systems like the Soekris net48xx.
We have seen a difference in sirq (Soft IRQ) load of 80% with conntrack modules versus 12% without any iptables modules when the system is hit with 50Mbps UDP traffic on the ethernet. Or with iperf UDP it's 30Mbps vs 36Mbps (all modues/no conntrack modules), but here the iperf process itself takes a lot of CPU time. So, for small systems which do not use a firewall or which have a firewall configuration without conntrack it would be really good to load the modules on demand... bruno On 11/04/2013 10:27 AM, Takayuki Kaiso wrote: > Thanks for the suggestions for each line, I failed to care for port > forwarding (redirect) case. > > 1. autoload issues > I basically agree to the simple way you said, "only load them when > needed for the first time". > then, "continuous running system, with low cpu power, dynamically change > firewall configuration" > will not be helped, but I hope it should be rare. > > 2. regarding the redundant lines of state->enable_conntrack = true, > yes it looks redundant, but masquerade requires conntrack as its > prerequisite, doesn't it ? > so I think we need to enables the flag in both cases. > > thanks a lot. > Takayuki Kaiso >> Hi, >> >> in general I do consider this idea but I do not agree with the >> implementation in your patch. >> >> In particular I think that the firewall init script is the wrong place >> to unload kmods, actually I think a random service should never unload >> kmods, at most only load them when needed for the first time. >> >> We can certainly change the netfilter kmod packages to not autoload on >> boot anymore, then insmod the required ones from fw3 (similar to how >> iptables did it). >> >> Furthermore the module dependencies should be calculated in the C code >> directly, I do not like parsing the firewall config for a 2nd time in >> shell, just to determine needed modules. >> >> A couple of additional comments are inline below. >> >> On 01.11.2013 06:35, Takayuki Kaiso wrote: >>> Now all the firewall modules are loaded at boot time regardless of >>> the user's firewall configuration. >>> Then, performance overhead is so high for low cpu power boards (Ex. >>> soekris net4826 with 266MHz) >>> by this approach and should be better to load modules on demand >>> base. >>> >>> This patch allow us to unload unnecessary modules especially for >>> conntrack related ones. >>> It can decrease the overhead for the config which does not enable >>> NAT, for instance. >>> >>> Signed-off-by: Takayuki Kaiso <tka...@thinktube.com> >>> >>> --- >>> package/firewall/files/firewall.init | 44 +++++++++ >>> .../patches/010-remove-unnecessary-chain.patch | 101 >>> +++++++++++++++++++++ >>> 2 files changed, 145 insertions(+) >>> >>> diff --git a/package/firewall/files/firewall.init >>> b/package/firewall/files/firewall.init >>> index 64e3a8c..6eda74f 100755 >>> --- a/package/firewall/files/firewall.init >>> +++ b/package/firewall/files/firewall.init >>> @@ -2,24 +2,68 @@ >>> >>> START=19 >>> >>> +CONNTRACK_ZONES= >>> +CONNTRACK_MODS="nf_nat_irc nf_conntrack_irc nf_nat_ftp >>> nf_conntrack_ftp ipt_MASQUERADE iptable_nat nf_nat nf_conntrack_ipv4 >>> nf_defrag_ipv4 >>> +xt_conntrack" >> There are more than just those, e.g. in the conntrack-extra packages, a >> more generic solution is needed here. >> >>> +CONNTRACK_MODS_REVERSE= >>> + >>> +fw_zone_check_conntrack() { >>> + config_get name $1 name >>> + config_get_bool masq $1 masq "0" >>> + config_get_bool conntrack $1 conntrack "0" >>> + [ "$conntrack" = "1" -o "$masq" = "1" ] && append CONNTRACK_ZONES >>> "$name" >> Port forwards imply conntracking on a zone as well, this is not covered >> here. >> >>> +} >>> + >>> +load_conntrack_modules() { >>> + for i in $CONNTRACK_MODS; do >>> + CONNTRACK_MODS_REVERSE="$i $CONNTRACK_MODS_REVERSE" >>> + done >>> + for i in $CONNTRACK_MODS_REVERSE; do >>> + insmod $i 2>/dev/null; >>> + done >>> +} >>> + >>> +unload_conntrack_modules() { >>> + for i in $CONNTRACK_MODS; do >>> + rmmod $i 2>/dev/null; >>> + done >>> +} >>> + >>> +update_firewall_modules() { >>> + config_load firewall >>> + config_foreach fw_zone_check_conntrack zone >>> + if [ -n "$CONNTRACK_ZONES" ]; then >>> + echo "loading conntrack modules" >>> + load_conntrack_modules >>> + else >>> + echo "Unloading conntrack modules" >>> + unload_conntrack_modules >>> + fi >>> +} >>> + >>> boot() { >>> # Be silent on boot, firewall might be started by hotplug already, >>> # so don't complain in syslog. >>> fw3 -q start >>> + update_firewall_modules >> Shouldn't that be done before starting the firewall? >>> } >>> >>> start() { >>> fw3 start >>> + update_firewall_modules >> Dito. >>> } >>> >>> stop() { >>> fw3 flush >>> + update_firewall_modules >> After a flush, the complete firewall is empty, one could argue that the >> principle of least surprise is violated here by *loading* kmods under >> certain circumstances. >>> } >>> >>> restart() { >>> fw3 restart >>> + update_firewall_modules >>> } >>> >>> reload() { >>> fw3 reload >>> + update_firewall_modules >> Reload does not clear the entire ruleset, it simply rebuilds internal >> chains. There is a high probability of live rules still relying on >> conntrack modules. >>> } >>> diff --git >>> a/package/firewall/patches/010-remove-unnecessary-chain.patch >>> b/package/firewall/patches/010-remove-unnecessary-chain.patch >>> new file mode 100644 >>> index 0000000..a2991e9 >>> --- /dev/null >>> +++ b/package/firewall/patches/010-remove-unnecessary-chain.patch >>> @@ -0,0 +1,101 @@ >>> +--- a/defaults.c >>> ++++ b/defaults.c >>> +@@ -138,6 +138,9 @@ fw3_print_default_chains(struct fw3_ipt_ >>> + if (handle->family == FW3_FAMILY_V6 && defs->disable_ipv6) >>> + return; >>> + >>> ++ if ((handle->table == FW3_TABLE_NAT && !state->enable_nat_table)) >>> ++ return; >>> ++ >>> + if (handle->table == FW3_TABLE_FILTER) >>> + { >>> + fw3_ipt_set_policy(handle, "INPUT", policy(defs->policy_input)); >>> +@@ -213,6 +216,9 @@ fw3_print_default_head_rules(struct fw3_ >>> + { 0, NULL }, >>> + }; >>> + >>> ++ if ((handle->table == FW3_TABLE_NAT && !state->enable_nat_table)) >>> ++ return; >>> ++ >>> + for (tr = rules; tr->chain; tr++) >>> + { >>> + if (tr->table != handle->table) >>> +@@ -250,10 +256,13 @@ fw3_print_default_head_rules(struct fw3_ >>> + >>> + for (i = 0; i < ARRAY_SIZE(chains); i += 2) >>> + { >>> +- r = fw3_ipt_rule_new(handle); >>> +- fw3_ipt_rule_extra(r, "-m conntrack --ctstate RELATED,ESTABLISHED"); >>> +- fw3_ipt_rule_target(r, "ACCEPT"); >>> +- fw3_ipt_rule_append(r, chains[i]); >>> ++ if (state->enable_conntrack) >>> ++ { >>> ++ r = fw3_ipt_rule_new(handle); >>> ++ fw3_ipt_rule_extra(r, "-m conntrack --ctstate RELATED,ESTABLISHED"); >>> ++ fw3_ipt_rule_target(r, "ACCEPT"); >>> ++ fw3_ipt_rule_append(r, chains[i]); >>> ++ } >>> + >>> + if (defs->drop_invalid) >>> + { >>> +--- a/options.h >>> ++++ b/options.h >>> +@@ -461,6 +461,8 @@ struct fw3_state >>> + >>> + bool disable_ipsets; >>> + bool statefile; >>> ++ bool enable_nat_table; >>> ++ bool enable_conntrack; >>> + }; >>> + >>> + struct fw3_chain_spec { >>> +--- a/zones.c >>> ++++ b/zones.c >>> +@@ -213,6 +213,13 @@ fw3_load_zones(struct fw3_state *state, >>> + { >>> + setbit(zone->flags[0], FW3_FLAG_SNAT); >>> + zone->conntrack = true; >>> ++ state->enable_nat_table = true; >>> ++ state->enable_conntrack = true; >> This... >> >>> ++ } >>> ++ >>> ++ if (zone->conntrack) >>> ++ { >>> ++ state->enable_conntrack = true; >> ... and this is redundant, only the 2nd enable_conntrack assignment >> seems to be needed. >> >>> + } >>> + >>> + if (zone->custom_chains) >>> +@@ -256,6 +263,9 @@ print_zone_chain(struct fw3_ipt_handle * >>> + if (!fw3_is_family(zone, handle->family)) >>> + return; >>> + >>> ++ if ((handle->table == FW3_TABLE_NAT && !state->enable_nat_table)) >>> ++ return; >>> ++ >>> + info(" * Zone '%s'", zone->name); >>> + >>> + set(zone->flags, handle->family, handle->table); >>> +@@ -332,6 +342,9 @@ print_interface_rule(struct fw3_ipt_hand >>> + "forward", >>> + }; >>> + >>> ++ if ((handle->table == FW3_TABLE_NAT && !state->enable_nat_table)) >>> ++ return; >>> ++ >>> + #define jump_target(t) \ >>> + ((t == FW3_FLAG_REJECT) ? "reject" : fw3_flag_names[t]) >>> + >>> +--- a/main.c >>> ++++ b/main.c >>> +@@ -50,6 +50,11 @@ build_state(bool runtime) >>> + error("Out of memory"); >>> + >>> + memset(state, 0, sizeof(*state)); >>> ++ >>> ++ /* set default status */ >>> ++ state->enable_nat_table = false; >>> ++ state->enable_conntrack = false; >> This is redundant and defaults to false anyway due to the memset before. >> >>> ++ >>> + state->uci = uci_alloc_context(); >>> + >>> + if (!state->uci) >> You also need to enable support for the nat table if at least one >> redirect is referencing the zone. >> >> >> Regards, >> Jow >> >> >> >> _______________________________________________ >> openwrt-devel mailing list >> openwrt-devel@lists.openwrt.org >> https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel > > _______________________________________________ openwrt-devel mailing list openwrt-devel@lists.openwrt.org https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel