summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYuxiang Zhu <vfreex@gmail.com>2023-08-26 05:28:11 +0000
committerYuxiang Zhu <vfreex@gmail.com>2023-09-09 08:16:04 +0000
commitf909c17aca4d48598d5eaee0df81bf64967902f0 (patch)
tree8641df807e45f9257f1603c0f467d5ec226c9618 /src
parentf494325bfde2ba9ff708fa00a7582a5fb6182486 (diff)
downloadvyos-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-xsrc/conf_mode/firewall.py37
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