diff options
author | Yuxiang Zhu <vfreex@gmail.com> | 2023-08-26 05:28:11 +0000 |
---|---|---|
committer | Yuxiang Zhu <vfreex@gmail.com> | 2023-09-09 08:16:04 +0000 |
commit | f909c17aca4d48598d5eaee0df81bf64967902f0 (patch) | |
tree | 8641df807e45f9257f1603c0f467d5ec226c9618 /src | |
parent | f494325bfde2ba9ff708fa00a7582a5fb6182486 (diff) | |
download | vyos-1x-f909c17aca4d48598d5eaee0df81bf64967902f0.tar.gz vyos-1x-f909c17aca4d48598d5eaee0df81bf64967902f0.zip |
T4502: firewall: Add software flow offload using flowtable
The following commands will enable nftables flowtable offload on interfaces eth0 eth1:
```
set firewall global-options flow-offload software interface <name>
set firewall global-options flow-offload hardware interface <name>
```
Generated nftables rules:
```
table inet vyos_offload {
flowtable VYOS_FLOWTABLE_software {
hook ingress priority filter - 1; devices = { eth0, eth1, eth2, eth3 };
counter
}
chain VYOS_OFFLOAD_software {
type filter hook forward priority filter - 1; policy accept;
ct state { established, related } meta l4proto { tcp, udp } flow add @VYOS_FLOWTABLE_software
}
}
```
Use this option to count packets and bytes for each offloaded flow:
```
set system conntrack flow-accounting
```
To verify a connection is offloaded, run
```
cat /proc/net/nf_conntrack|grep OFFLOAD
```
This PR follows firewalld's implementation: https://github.com/firewalld/firewalld/blob/e748b97787d685d0ca93f58e8d4292e87d3f0da6/src/firewall/core/nftables.py#L590
A good introduction to nftables flowtable: https://thermalcircle.de/doku.php?id=blog:linux:flowtables_1_a_netfilter_nftables_fastpath
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/firewall.py | 37 |
1 files changed, 28 insertions, 9 deletions
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index c3b1ee015..769cc598f 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -26,7 +26,7 @@ from vyos.config import Config from vyos.configdict import node_changed from vyos.configdiff import get_config_diff, Diff from vyos.configdep import set_dependents, call_dependents -# from vyos.configverify import verify_interface_exists +from vyos.configverify import verify_interface_exists from vyos.firewall import fqdn_config_parse from vyos.firewall import geoip_update from vyos.template import render @@ -38,6 +38,7 @@ from vyos.utils.process import process_named_running from vyos.utils.process import rc_cmd from vyos import ConfigError from vyos import airbag + airbag.enable() nat_conf_script = 'nat.py' @@ -100,7 +101,7 @@ def geoip_updated(conf, firewall): elif (path[0] == 'ipv6'): set_name = f'GEOIP_CC6_{path[1]}_{path[2]}_{path[4]}' out['ipv6_name'].append(set_name) - + updated = True if 'delete' in node_diff: @@ -140,6 +141,14 @@ def get_config(config=None): fqdn_config_parse(firewall) + firewall['flowtable_enabled'] = False + flow_offload = dict_search_args(firewall, 'global_options', 'flow_offload') + if flow_offload and 'disable' not in flow_offload: + for offload_type in ('software', 'hardware'): + if dict_search_args(flow_offload, offload_type, 'interface'): + firewall['flowtable_enabled'] = True + break + return firewall def verify_rule(firewall, rule_conf, ipv6): @@ -327,6 +336,14 @@ def verify(firewall): for rule_id, rule_conf in name_conf['rule'].items(): verify_rule(firewall, rule_conf, True) + # Verify flow offload options + flow_offload = dict_search_args(firewall, 'global_options', 'flow_offload') + for offload_type in ('software', 'hardware'): + interfaces = dict_search_args(flow_offload, offload_type, 'interface') or [] + for interface in interfaces: + # nft will raise an error when adding a non-existent interface to a flowtable + verify_interface_exists(interface) + return None def generate(firewall): @@ -336,13 +353,15 @@ def generate(firewall): # Determine if conntrack is needed firewall['ipv4_conntrack_action'] = 'return' firewall['ipv6_conntrack_action'] = 'return' - - for rules, path in dict_search_recursive(firewall, 'rule'): - if any(('state' in rule_conf or 'connection_status' in rule_conf) for rule_conf in rules.values()): - if path[0] == 'ipv4': - firewall['ipv4_conntrack_action'] = 'accept' - elif path[0] == 'ipv6': - firewall['ipv6_conntrack_action'] = 'accept' + if firewall['flowtable_enabled']: # Netfilter's flowtable offload requires conntrack + firewall['ipv4_conntrack_action'] = 'accept' + firewall['ipv6_conntrack_action'] = 'accept' + else: # Check if conntrack is needed by firewall rules + for proto in ('ipv4', 'ipv6'): + for rules, _ in dict_search_recursive(firewall.get(proto, {}), 'rule'): + if any(('state' in rule_conf or 'connection_status' in rule_conf) for rule_conf in rules.values()): + firewall[f'{proto}_conntrack_action'] = 'accept' + break render(nftables_conf, 'firewall/nftables.j2', firewall) return None |