summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/PULL_REQUEST_TEMPLATE.md11
-rw-r--r--data/config-mode-dependencies/vyos-1x.json5
-rw-r--r--data/templates/aws/override_aws_gwlbtun.conf.j236
-rw-r--r--data/templates/conntrack/nftables-ct.j2159
-rw-r--r--data/templates/dns-dynamic/ddclient.conf.j25
-rw-r--r--data/templates/firewall/nftables-nat.j221
-rw-r--r--data/templates/firewall/nftables-nat66.j217
-rw-r--r--data/templates/firewall/nftables-offload.j216
-rw-r--r--data/templates/firewall/nftables.j249
-rw-r--r--data/templates/high-availability/10-override.conf.j22
-rw-r--r--data/vyos-firewall-init.conf113
-rw-r--r--debian/control1
-rw-r--r--interface-definitions/firewall.xml.in40
-rw-r--r--interface-definitions/high-availability.xml.in4
-rw-r--r--interface-definitions/include/firewall/action-forward.xml.i45
-rw-r--r--interface-definitions/include/firewall/common-rule-inet.xml.i1
-rw-r--r--interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i1
-rw-r--r--interface-definitions/include/firewall/common-rule.xml.i1
-rw-r--r--interface-definitions/include/firewall/flow-offload.xml.i47
-rw-r--r--interface-definitions/include/firewall/global-options.xml.i1
-rw-r--r--interface-definitions/include/firewall/ipv4-hook-forward.xml.i2
-rw-r--r--interface-definitions/include/firewall/ipv6-hook-forward.xml.i2
-rw-r--r--interface-definitions/include/firewall/offload-target.xml.i10
-rw-r--r--interface-definitions/include/firewall/tcp-flags.xml.i18
-rw-r--r--interface-definitions/include/firewall/tcp-mss.xml.i25
-rw-r--r--interface-definitions/include/policy/route-common.xml.i1
-rw-r--r--interface-definitions/interfaces-ethernet.xml.in6
-rw-r--r--interface-definitions/service-aws-glb.xml.in127
-rw-r--r--interface-definitions/system-conntrack.xml.in2
-rw-r--r--python/vyos/ethtool.py3
-rw-r--r--python/vyos/firewall.py71
-rw-r--r--python/vyos/ifconfig/ethernet.py26
-rw-r--r--python/vyos/template.py5
-rw-r--r--python/vyos/utils/network.py2
-rwxr-xr-xsmoketest/scripts/cli/test_firewall.py38
-rwxr-xr-xsmoketest/scripts/cli/test_policy_route.py4
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_dynamic.py4
-rwxr-xr-xsmoketest/scripts/cli/test_system_conntrack.py11
-rwxr-xr-xsmoketest/scripts/cli/test_system_flow-accounting.py2
-rwxr-xr-xsrc/conf_mode/conntrack.py79
-rwxr-xr-xsrc/conf_mode/dns_dynamic.py2
-rwxr-xr-xsrc/conf_mode/firewall.py66
-rwxr-xr-xsrc/conf_mode/flow_accounting_conf.py2
-rwxr-xr-xsrc/conf_mode/high-availability.py2
-rwxr-xr-xsrc/conf_mode/load-balancing-wan.py5
-rwxr-xr-xsrc/conf_mode/nat.py90
-rwxr-xr-xsrc/conf_mode/nat66.py46
-rwxr-xr-xsrc/conf_mode/service_aws_glb.py76
-rwxr-xr-xsrc/conf_mode/system-ip.py28
-rwxr-xr-xsrc/conf_mode/system-ipv6.py25
-rwxr-xr-xsrc/conf_mode/system_frr.py10
-rw-r--r--src/systemd/aws-gwlbtun.service11
52 files changed, 843 insertions, 533 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 47579e1c6..933894447 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -21,6 +21,9 @@ the box, please use [x]
<!-- All submitted PRs must be linked to a Task on Phabricator. -->
* https://vyos.dev/Txxxx
+## Related PR(s)
+<!-- Link here any PRs in other repositories that are required by this PR -->
+
## Component(s) name
<!-- A rather incomplete list of components: ethernet, wireguard, bgp, mpls, ldp, l2tp, dhcp ... -->
@@ -37,6 +40,14 @@ like this
```
-->
+## Smoketest result
+<!-- Provide the output of the smoketest
+```
+$ /usr/libexec/vyos/tests/smoke/cli/test_xxx_feature.py
+test_01_simple_options (__main__.TestFeature.test_01_simple_options) ... ok
+```
+-->
+
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
diff --git a/data/config-mode-dependencies/vyos-1x.json b/data/config-mode-dependencies/vyos-1x.json
index 08732bd4c..a433c2522 100644
--- a/data/config-mode-dependencies/vyos-1x.json
+++ b/data/config-mode-dependencies/vyos-1x.json
@@ -1,6 +1,9 @@
{
- "firewall": {"group_resync": ["conntrack", "nat", "policy-route"]},
+ "firewall": {"conntrack": ["conntrack"], "group_resync": ["conntrack", "nat", "policy-route"]},
"http_api": {"https": ["https"]},
+ "load_balancing_wan": {"conntrack": ["conntrack"]},
+ "nat": {"conntrack": ["conntrack"]},
+ "nat66": {"conntrack": ["conntrack"]},
"pki": {
"ethernet": ["interfaces-ethernet"],
"openvpn": ["interfaces-openvpn"],
diff --git a/data/templates/aws/override_aws_gwlbtun.conf.j2 b/data/templates/aws/override_aws_gwlbtun.conf.j2
new file mode 100644
index 000000000..4c566d852
--- /dev/null
+++ b/data/templates/aws/override_aws_gwlbtun.conf.j2
@@ -0,0 +1,36 @@
+{% set args = [] %}
+{% if script.on_create is vyos_defined %}
+{% set _ = args.append("-c " + script.on_create) %}
+{% endif %}
+{% if script.on_destroy is vyos_defined %}
+{% set _ = args.append("-r " + script.on_destroy) %}
+{% endif %}
+
+{% if status.port is vyos_defined %}
+{% set _ = args.append("-p " + status.port) %}
+{% endif %}
+
+{% if threads.tunnel is vyos_defined %}
+{% set _ = args.append("--tunthreads " + threads.tunnel) %}
+{% endif %}
+{% if threads.tunnel_affinity is vyos_defined %}
+{% set _ = args.append("--tunaffinity " + threads.tunnel_affinity) %}
+{% endif %}
+
+{% if threads.udp is vyos_defined %}
+{% set _ = args.append("--udpthreads " + threads.udp) %}
+{% endif %}
+{% if threads.udp_affinity is vyos_defined %}
+{% set _ = args.append("--udpaffinity " + threads.udp_affinity) %}
+{% endif %}
+
+[Unit]
+StartLimitIntervalSec=0
+After=vyos-router.service
+
+[Service]
+EnvironmentFile=
+ExecStart=/usr/bin/gwlbtun {{ args | join(' ') }}
+CapabilityBoundingSet=CAP_NET_ADMIN
+Restart=always
+RestartSec=10
diff --git a/data/templates/conntrack/nftables-ct.j2 b/data/templates/conntrack/nftables-ct.j2
index 3a5b5a87c..895f61a55 100644
--- a/data/templates/conntrack/nftables-ct.j2
+++ b/data/templates/conntrack/nftables-ct.j2
@@ -2,16 +2,11 @@
{% import 'firewall/nftables-defines.j2' as group_tmpl %}
-{% set nft_ct_ignore_name = 'VYOS_CT_IGNORE' %}
-{% set nft_ct_timeout_name = 'VYOS_CT_TIMEOUT' %}
-
-# we first flush all chains and render the content from scratch - this makes
-# any delta check obsolete
-flush chain raw {{ nft_ct_ignore_name }}
-flush chain raw {{ nft_ct_timeout_name }}
-
-table raw {
- chain {{ nft_ct_ignore_name }} {
+{% if first_install is not vyos_defined %}
+delete table ip vyos_conntrack
+{% endif %}
+table ip vyos_conntrack {
+ chain VYOS_CT_IGNORE {
{% if ignore.ipv4.rule is vyos_defined %}
{% for rule, rule_config in ignore.ipv4.rule.items() %}
# rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
@@ -20,7 +15,7 @@ table raw {
{% endif %}
return
}
- chain {{ nft_ct_timeout_name }} {
+ chain VYOS_CT_TIMEOUT {
{% if timeout.custom.rule is vyos_defined %}
{% for rule, rule_config in timeout.custom.rule.items() %}
# rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
@@ -29,14 +24,81 @@ table raw {
return
}
-{{ group_tmpl.groups(firewall_group, False, True) }}
-}
+ chain PREROUTING {
+ type filter hook prerouting priority -300; policy accept;
+{% if ipv4_firewall_action == 'accept' or ipv4_nat_action == 'accept' %}
+ counter jump VYOS_CT_HELPER
+{% endif %}
+ counter jump VYOS_CT_IGNORE
+ counter jump VYOS_CT_TIMEOUT
+ counter jump FW_CONNTRACK
+ counter jump NAT_CONNTRACK
+ counter jump WLB_CONNTRACK
+ notrack
+ }
+
+ chain OUTPUT {
+ type filter hook output priority -300; policy accept;
+{% if ipv4_firewall_action == 'accept' or ipv4_nat_action == 'accept' %}
+ counter jump VYOS_CT_HELPER
+{% endif %}
+ counter jump VYOS_CT_IGNORE
+ counter jump VYOS_CT_TIMEOUT
+ counter jump FW_CONNTRACK
+ counter jump NAT_CONNTRACK
+{% if wlb_local_action %}
+ counter jump WLB_CONNTRACK
+{% endif %}
+ notrack
+ }
+
+ ct helper rpc_tcp {
+ type "rpc" protocol tcp;
+ }
+
+ ct helper rpc_udp {
+ type "rpc" protocol udp;
+ }
+
+ ct helper tns_tcp {
+ type "tns" protocol tcp;
+ }
+
+ chain VYOS_CT_HELPER {
+{% for module, module_conf in module_map.items() %}
+{% if modules[module] is vyos_defined %}
+{% if 'nftables' in module_conf %}
+{% for rule in module_conf.nftables %}
+ {{ rule }}
+{% endfor %}
+{% endif %}
+{% endif %}
+{% endfor %}
+ return
+ }
+
+ chain FW_CONNTRACK {
+ {{ ipv4_firewall_action }}
+ }
+
+ chain NAT_CONNTRACK {
+ {{ ipv4_nat_action }}
+ }
+
+ chain WLB_CONNTRACK {
+ {{ wlb_action }}
+ }
-flush chain ip6 raw {{ nft_ct_ignore_name }}
-flush chain ip6 raw {{ nft_ct_timeout_name }}
+{% if firewall.group is vyos_defined %}
+{{ group_tmpl.groups(firewall.group, False, True) }}
+{% endif %}
+}
-table ip6 raw {
- chain {{ nft_ct_ignore_name }} {
+{% if first_install is not vyos_defined %}
+delete table ip6 vyos_conntrack
+{% endif %}
+table ip6 vyos_conntrack {
+ chain VYOS_CT_IGNORE {
{% if ignore.ipv6.rule is vyos_defined %}
{% for rule, rule_config in ignore.ipv6.rule.items() %}
# rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
@@ -45,7 +107,7 @@ table ip6 raw {
{% endif %}
return
}
- chain {{ nft_ct_timeout_name }} {
+ chain VYOS_CT_TIMEOUT {
{% if timeout.custom.rule is vyos_defined %}
{% for rule, rule_config in timeout.custom.rule.items() %}
# rule-{{ rule }} {{ '- ' ~ rule_config.description if rule_config.description is vyos_defined }}
@@ -54,5 +116,64 @@ table ip6 raw {
return
}
-{{ group_tmpl.groups(firewall_group, True, True) }}
+ chain PREROUTING {
+ type filter hook prerouting priority -300; policy accept;
+{% if ipv6_firewall_action == 'accept' or ipv6_nat_action == 'accept' %}
+ counter jump VYOS_CT_HELPER
+{% endif %}
+ counter jump VYOS_CT_IGNORE
+ counter jump VYOS_CT_TIMEOUT
+ counter jump FW_CONNTRACK
+ counter jump NAT_CONNTRACK
+ notrack
+ }
+
+ chain OUTPUT {
+ type filter hook output priority -300; policy accept;
+{% if ipv6_firewall_action == 'accept' or ipv6_nat_action == 'accept' %}
+ counter jump VYOS_CT_HELPER
+{% endif %}
+ counter jump VYOS_CT_IGNORE
+ counter jump VYOS_CT_TIMEOUT
+ counter jump FW_CONNTRACK
+ counter jump NAT_CONNTRACK
+ notrack
+ }
+
+ ct helper rpc_tcp {
+ type "rpc" protocol tcp;
+ }
+
+ ct helper rpc_udp {
+ type "rpc" protocol udp;
+ }
+
+ ct helper tns_tcp {
+ type "tns" protocol tcp;
+ }
+
+ chain VYOS_CT_HELPER {
+{% for module, module_conf in module_map.items() %}
+{% if modules[module] is vyos_defined %}
+{% if 'nftables' in module_conf %}
+{% for rule in module_conf.nftables %}
+ {{ rule }}
+{% endfor %}
+{% endif %}
+{% endif %}
+{% endfor %}
+ return
+ }
+
+ chain FW_CONNTRACK {
+ {{ ipv6_firewall_action }}
+ }
+
+ chain NAT_CONNTRACK {
+ {{ ipv6_nat_action }}
+ }
+
+{% if firewall.group is vyos_defined %}
+{{ group_tmpl.groups(firewall.group, True, True) }}
+{% endif %}
}
diff --git a/data/templates/dns-dynamic/ddclient.conf.j2 b/data/templates/dns-dynamic/ddclient.conf.j2
index 3446a9d1b..421daf1df 100644
--- a/data/templates/dns-dynamic/ddclient.conf.j2
+++ b/data/templates/dns-dynamic/ddclient.conf.j2
@@ -59,11 +59,8 @@ use=no {# ddclient default ('ip') results in confusing warning messag
{% endif %}
{% for host in config.host_name if config.host_name is vyos_defined %}
{% set ip_suffixes = ['v4', 'v6'] if config.ip_version == 'both'
- else (['v6'] if config.ip_version == 'ipv6' else ['']) %}
+ else [config.ip_version[2:]] %} {# 'ipvX' -> 'vX' #}
# Web service dynamic DNS configuration for {{ name }}: [{{ config.protocol }}, {{ host }}]
-{# For ipv4 only setup or legacy ipv6 setup, don't append 'new-style' compliant suffix
- ('usev4', 'ifv4', 'webv4' etc.) to the properties and instead live through the
- deprecation warnings for better compatibility with most ddclient protocols. #}
{{ render_config(host, address, service_cfg.web_options, ip_suffixes,
protocol=config.protocol, server=config.server, zone=config.zone,
login=config.username, password=config.password) }}
diff --git a/data/templates/firewall/nftables-nat.j2 b/data/templates/firewall/nftables-nat.j2
index dcf28da88..4254f6a0e 100644
--- a/data/templates/firewall/nftables-nat.j2
+++ b/data/templates/firewall/nftables-nat.j2
@@ -2,27 +2,6 @@
{% import 'firewall/nftables-defines.j2' as group_tmpl %}
-{% if helper_functions is vyos_defined('remove') %}
-{# NAT if going to be disabled - remove rules and targets from nftables #}
-{% set base_command = 'delete rule ip raw' %}
-{{ base_command }} PREROUTING handle {{ pre_ct_ignore }}
-{{ base_command }} OUTPUT handle {{ out_ct_ignore }}
-{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }}
-{{ base_command }} OUTPUT handle {{ out_ct_conntrack }}
-
-delete chain ip raw NAT_CONNTRACK
-
-{% elif helper_functions is vyos_defined('add') %}
-{# NAT if enabled - add targets to nftables #}
-add chain ip raw NAT_CONNTRACK
-add rule ip raw NAT_CONNTRACK counter accept
-{% set base_command = 'add rule ip raw' %}
-{{ base_command }} PREROUTING position {{ pre_ct_ignore }} counter jump VYOS_CT_HELPER
-{{ base_command }} OUTPUT position {{ out_ct_ignore }} counter jump VYOS_CT_HELPER
-{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
-{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
-{% endif %}
-
{% if first_install is not vyos_defined %}
delete table ip vyos_nat
{% endif %}
diff --git a/data/templates/firewall/nftables-nat66.j2 b/data/templates/firewall/nftables-nat66.j2
index 27b3eec88..67eb2c109 100644
--- a/data/templates/firewall/nftables-nat66.j2
+++ b/data/templates/firewall/nftables-nat66.j2
@@ -1,22 +1,5 @@
#!/usr/sbin/nft -f
-{% if helper_functions is vyos_defined('remove') %}
-{# NAT if going to be disabled - remove rules and targets from nftables #}
-{% set base_command = 'delete rule ip6 raw' %}
-{{ base_command }} PREROUTING handle {{ pre_ct_conntrack }}
-{{ base_command }} OUTPUT handle {{ out_ct_conntrack }}
-
-delete chain ip6 raw NAT_CONNTRACK
-
-{% elif helper_functions is vyos_defined('add') %}
-{# NAT if enabled - add targets to nftables #}
-add chain ip6 raw NAT_CONNTRACK
-add rule ip6 raw NAT_CONNTRACK counter accept
-{% set base_command = 'add rule ip6 raw' %}
-{{ base_command }} PREROUTING position {{ pre_ct_conntrack }} counter jump NAT_CONNTRACK
-{{ base_command }} OUTPUT position {{ out_ct_conntrack }} counter jump NAT_CONNTRACK
-{% endif %}
-
{% if first_install is not vyos_defined %}
delete table ip6 vyos_nat
{% endif %}
diff --git a/data/templates/firewall/nftables-offload.j2 b/data/templates/firewall/nftables-offload.j2
index 6afcd79f7..a893e05b2 100644
--- a/data/templates/firewall/nftables-offload.j2
+++ b/data/templates/firewall/nftables-offload.j2
@@ -1,11 +1,9 @@
-{% macro render_flowtable(name, devices, priority='filter', hardware_offload=false, with_counter=true) %}
-flowtable {{ name }} {
- hook ingress priority {{ priority }}; devices = { {{ devices | join(', ') }} };
-{% if hardware_offload %}
- flags offload;
+{% macro flowtable(name, config) %}
+ flowtable VYOS_FLOWTABLE_{{ name }} {
+ hook ingress priority 0; devices = { {{ config.interface | join(', ') }} };
+{% if config.offload is vyos_defined('hardware') %}
+ flags offload;
{% endif %}
-{% if with_counter %}
- counter
-{% endif %}
-}
+ counter
+ }
{% endmacro %}
diff --git a/data/templates/firewall/nftables.j2 b/data/templates/firewall/nftables.j2
index 723c9c3a2..75800ee3d 100644
--- a/data/templates/firewall/nftables.j2
+++ b/data/templates/firewall/nftables.j2
@@ -2,19 +2,12 @@
{% import 'firewall/nftables-defines.j2' as group_tmpl %}
{% import 'firewall/nftables-bridge.j2' as bridge_tmpl %}
-{% import 'firewall/nftables-offload.j2' as offload %}
-
-flush chain raw FW_CONNTRACK
-flush chain ip6 raw FW_CONNTRACK
+{% import 'firewall/nftables-offload.j2' as offload_tmpl %}
flush chain raw vyos_global_rpfilter
flush chain ip6 raw vyos_global_rpfilter
table raw {
- chain FW_CONNTRACK {
- {{ ipv4_conntrack_action }}
- }
-
chain vyos_global_rpfilter {
{% if global_options.source_validation is vyos_defined('loose') %}
fib saddr oif 0 counter drop
@@ -26,10 +19,6 @@ table raw {
}
table ip6 raw {
- chain FW_CONNTRACK {
- {{ ipv6_conntrack_action }}
- }
-
chain vyos_global_rpfilter {
{% if global_options.ipv6_source_validation is vyos_defined('loose') %}
fib saddr oif 0 counter drop
@@ -45,6 +34,12 @@ delete table ip vyos_filter
{% endif %}
table ip vyos_filter {
{% if ipv4 is vyos_defined %}
+{% if flowtable is vyos_defined %}
+{% for name, flowtable_conf in flowtable.items() %}
+{{ offload_tmpl.flowtable(name, flowtable_conf) }}
+{% endfor %}
+{% endif %}
+
{% set ns = namespace(sets=[]) %}
{% if ipv4.forward is vyos_defined %}
{% for prior, conf in ipv4.forward.items() %}
@@ -164,6 +159,12 @@ delete table ip6 vyos_filter
{% endif %}
table ip6 vyos_filter {
{% if ipv6 is vyos_defined %}
+{% if flowtable is vyos_defined %}
+{% for name, flowtable_conf in flowtable.items() %}
+{{ offload_tmpl.flowtable(name, flowtable_conf) }}
+{% endfor %}
+{% endif %}
+
{% set ns = namespace(sets=[]) %}
{% if ipv6.forward is vyos_defined %}
{% for prior, conf in ipv6.forward.items() %}
@@ -266,31 +267,7 @@ table ip6 vyos_filter {
{% if first_install is not vyos_defined %}
delete table bridge vyos_filter
{% endif %}
-{% if bridge is vyos_defined %}
table bridge vyos_filter {
{{ bridge_tmpl.bridge(bridge) }}
{{ group_tmpl.groups(group, False, False) }}
}
-{% endif %}
-{{ group_tmpl.groups(group, True) }}
-
-table inet vyos_offload
-delete table inet vyos_offload
-table inet vyos_offload {
-{% if flowtable_enabled %}
-{% if global_options.flow_offload.hardware.interface is vyos_defined %}
- {{- offload.render_flowtable('VYOS_FLOWTABLE_hardware', global_options.flow_offload.hardware.interface | list, priority='filter - 2', hardware_offload=true) }}
- chain VYOS_OFFLOAD_hardware {
- type filter hook forward priority filter - 2; policy accept;
- ct state { established, related } meta l4proto { tcp, udp } flow add @VYOS_FLOWTABLE_hardware
- }
-{% endif %}
-{% if global_options.flow_offload.software.interface is vyos_defined %}
- {{- offload.render_flowtable('VYOS_FLOWTABLE_software', global_options.flow_offload.software.interface | list, priority='filter - 1') }}
- 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
- }
-{% endif %}
-{% endif %}
-}
diff --git a/data/templates/high-availability/10-override.conf.j2 b/data/templates/high-availability/10-override.conf.j2
index d1cb25581..c153f09b4 100644
--- a/data/templates/high-availability/10-override.conf.j2
+++ b/data/templates/high-availability/10-override.conf.j2
@@ -1,5 +1,5 @@
### Autogenerated by ${vyos_conf_scripts_dir}/high-availability.py ###
-{% set snmp = '' if vrrp.disable_snmp is vyos_defined else '--snmp' %}
+{% set snmp = '--snmp' if vrrp.snmp is vyos_defined else '' %}
[Unit]
After=vyos-router.service
# Only start if there is our configuration file - remove Debian default
diff --git a/data/vyos-firewall-init.conf b/data/vyos-firewall-init.conf
index 7e258e6f1..cd7d5011f 100644
--- a/data/vyos-firewall-init.conf
+++ b/data/vyos-firewall-init.conf
@@ -9,6 +9,7 @@ table ip nat {
}
table inet mangle {
+ # Used by system flow-accounting
chain FORWARD {
type filter hook forward priority -150; policy accept;
}
@@ -28,61 +29,9 @@ table raw {
counter jump vyos_global_rpfilter
}
- chain PREROUTING {
+ # Used by system flow-accounting
+ chain VYOS_PREROUTING_HOOK {
type filter hook prerouting priority -300; policy accept;
- counter jump VYOS_CT_IGNORE
- counter jump VYOS_CT_TIMEOUT
- counter jump VYOS_CT_PREROUTING_HOOK
- counter jump FW_CONNTRACK
- notrack
- }
-
- chain OUTPUT {
- type filter hook output priority -300; policy accept;
- counter jump VYOS_CT_IGNORE
- counter jump VYOS_CT_TIMEOUT
- counter jump VYOS_CT_OUTPUT_HOOK
- counter jump FW_CONNTRACK
- notrack
- }
-
- ct helper rpc_tcp {
- type "rpc" protocol tcp;
- }
-
- ct helper rpc_udp {
- type "rpc" protocol udp;
- }
-
- ct helper tns_tcp {
- type "tns" protocol tcp;
- }
-
- chain VYOS_CT_HELPER {
- ct helper set "rpc_tcp" tcp dport {111} return
- ct helper set "rpc_udp" udp dport {111} return
- ct helper set "tns_tcp" tcp dport {1521,1525,1536} return
- return
- }
-
- chain VYOS_CT_IGNORE {
- return
- }
-
- chain VYOS_CT_TIMEOUT {
- return
- }
-
- chain VYOS_CT_PREROUTING_HOOK {
- return
- }
-
- chain VYOS_CT_OUTPUT_HOOK {
- return
- }
-
- chain FW_CONNTRACK {
- return
}
}
@@ -100,60 +49,8 @@ table ip6 raw {
counter jump vyos_global_rpfilter
}
- chain PREROUTING {
+ # Used by system flow-accounting
+ chain VYOS_PREROUTING_HOOK {
type filter hook prerouting priority -300; policy accept;
- counter jump VYOS_CT_IGNORE
- counter jump VYOS_CT_TIMEOUT
- counter jump VYOS_CT_PREROUTING_HOOK
- counter jump FW_CONNTRACK
- notrack
- }
-
- chain OUTPUT {
- type filter hook output priority -300; policy accept;
- counter jump VYOS_CT_IGNORE
- counter jump VYOS_CT_TIMEOUT
- counter jump VYOS_CT_OUTPUT_HOOK
- counter jump FW_CONNTRACK
- notrack
- }
-
- ct helper rpc_tcp {
- type "rpc" protocol tcp;
- }
-
- ct helper rpc_udp {
- type "rpc" protocol udp;
- }
-
- ct helper tns_tcp {
- type "tns" protocol tcp;
- }
-
- chain VYOS_CT_HELPER {
- ct helper set "rpc_tcp" tcp dport {111} return
- ct helper set "rpc_udp" udp dport {111} return
- ct helper set "tns_tcp" tcp dport {1521,1525,1536} return
- return
- }
-
- chain VYOS_CT_IGNORE {
- return
- }
-
- chain VYOS_CT_TIMEOUT {
- return
- }
-
- chain VYOS_CT_PREROUTING_HOOK {
- return
- }
-
- chain VYOS_CT_OUTPUT_HOOK {
- return
- }
-
- chain FW_CONNTRACK {
- return
}
}
diff --git a/debian/control b/debian/control
index ee45a5fe3..735733956 100644
--- a/debian/control
+++ b/debian/control
@@ -36,6 +36,7 @@ Depends:
accel-ppp,
auditd,
avahi-daemon,
+ aws-gwlbtun,
beep,
bmon,
bsdmainutils,
diff --git a/interface-definitions/firewall.xml.in b/interface-definitions/firewall.xml.in
index 8e462f3eb..81e6b89ea 100644
--- a/interface-definitions/firewall.xml.in
+++ b/interface-definitions/firewall.xml.in
@@ -7,6 +7,46 @@
</properties>
<children>
#include <include/firewall/global-options.xml.i>
+ <tagNode name="flowtable">
+ <properties>
+ <help>Flowtable</help>
+ <constraint>
+ <regex>[a-zA-Z0-9][\w\-\.]*</regex>
+ </constraint>
+ </properties>
+ <children>
+ #include <include/generic-description.xml.i>
+ <leafNode name="interface">
+ <properties>
+ <help>Interfaces to use this flowtable</help>
+ <completionHelp>
+ <script>${vyos_completion_dir}/list_interfaces</script>
+ </completionHelp>
+ <multi/>
+ </properties>
+ </leafNode>
+ <leafNode name="offload">
+ <properties>
+ <help>Offloading method</help>
+ <completionHelp>
+ <list>hardware software</list>
+ </completionHelp>
+ <valueHelp>
+ <format>hardware</format>
+ <description>Hardware offload</description>
+ </valueHelp>
+ <valueHelp>
+ <format>software</format>
+ <description>Software offload</description>
+ </valueHelp>
+ <constraint>
+ <regex>(hardware|software)</regex>
+ </constraint>
+ </properties>
+ <defaultValue>software</defaultValue>
+ </leafNode>
+ </children>
+ </tagNode>
<node name="group">
<properties>
<help>Firewall group</help>
diff --git a/interface-definitions/high-availability.xml.in b/interface-definitions/high-availability.xml.in
index 47a772d04..aa23888a4 100644
--- a/interface-definitions/high-availability.xml.in
+++ b/interface-definitions/high-availability.xml.in
@@ -12,10 +12,10 @@
<help>Virtual Router Redundancy Protocol settings</help>
</properties>
<children>
- <leafNode name="disable-snmp">
+ <leafNode name="snmp">
<properties>
<valueless/>
- <help>Disable SNMP</help>
+ <help>Enable SNMP</help>
</properties>
</leafNode>
<node name="global-parameters">
diff --git a/interface-definitions/include/firewall/action-forward.xml.i b/interface-definitions/include/firewall/action-forward.xml.i
new file mode 100644
index 000000000..f61e51887
--- /dev/null
+++ b/interface-definitions/include/firewall/action-forward.xml.i
@@ -0,0 +1,45 @@
+<!-- include start from firewall/action-forward.xml.i -->
+<leafNode name="action">
+ <properties>
+ <help>Rule action</help>
+ <completionHelp>
+ <list>accept continue jump reject return drop queue offload</list>
+ </completionHelp>
+ <valueHelp>
+ <format>accept</format>
+ <description>Accept matching entries</description>
+ </valueHelp>
+ <valueHelp>
+ <format>continue</format>
+ <description>Continue parsing next rule</description>
+ </valueHelp>
+ <valueHelp>
+ <format>jump</format>
+ <description>Jump to another chain</description>
+ </valueHelp>
+ <valueHelp>
+ <format>reject</format>
+ <description>Reject matching entries</description>
+ </valueHelp>
+ <valueHelp>
+ <format>return</format>
+ <description>Return from the current chain and continue at the next rule of the last chain</description>
+ </valueHelp>
+ <valueHelp>
+ <format>drop</format>
+ <description>Drop matching entries</description>
+ </valueHelp>
+ <valueHelp>
+ <format>queue</format>
+ <description>Enqueue packet to userspace</description>
+ </valueHelp>
+ <valueHelp>
+ <format>offload</format>
+ <description>Offload packet via flowtable</description>
+ </valueHelp>
+ <constraint>
+ <regex>(accept|continue|jump|reject|return|drop|queue|offload)</regex>
+ </constraint>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/firewall/common-rule-inet.xml.i b/interface-definitions/include/firewall/common-rule-inet.xml.i
index 7a2eb86d4..e51dd0056 100644
--- a/interface-definitions/include/firewall/common-rule-inet.xml.i
+++ b/interface-definitions/include/firewall/common-rule-inet.xml.i
@@ -303,6 +303,7 @@
</children>
</node>
#include <include/firewall/tcp-flags.xml.i>
+#include <include/firewall/tcp-mss.xml.i>
<node name="time">
<properties>
<help>Time to match rule</help>
diff --git a/interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i b/interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i
index a1071a09a..e040c9b13 100644
--- a/interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i
+++ b/interface-definitions/include/firewall/common-rule-ipv4-raw.xml.i
@@ -260,6 +260,7 @@
</children>
</node>
#include <include/firewall/tcp-flags.xml.i>
+#include <include/firewall/tcp-mss.xml.i>
<node name="time">
<properties>
<help>Time to match rule</help>
diff --git a/interface-definitions/include/firewall/common-rule.xml.i b/interface-definitions/include/firewall/common-rule.xml.i
index 7417a3c58..c62bf2c5f 100644
--- a/interface-definitions/include/firewall/common-rule.xml.i
+++ b/interface-definitions/include/firewall/common-rule.xml.i
@@ -315,6 +315,7 @@
</children>
</node>
#include <include/firewall/tcp-flags.xml.i>
+#include <include/firewall/tcp-mss.xml.i>
<node name="time">
<properties>
<help>Time to match rule</help>
diff --git a/interface-definitions/include/firewall/flow-offload.xml.i b/interface-definitions/include/firewall/flow-offload.xml.i
deleted file mode 100644
index 706836362..000000000
--- a/interface-definitions/include/firewall/flow-offload.xml.i
+++ /dev/null
@@ -1,47 +0,0 @@
-<!-- include start from firewall/flow-offload.xml.i -->
-<node name="flow-offload">
- <properties>
- <help>Configurable flow offload options</help>
- </properties>
- <children>
- <leafNode name="disable">
- <properties>
- <help>Disable flow offload</help>
- <valueless/>
- </properties>
- </leafNode>
- <node name="software">
- <properties>
- <help>Software offload</help>
- </properties>
- <children>
- <leafNode name="interface">
- <properties>
- <help>Interfaces to enable</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <multi/>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="hardware">
- <properties>
- <help>Hardware offload</help>
- </properties>
- <children>
- <leafNode name="interface">
- <properties>
- <help>Interfaces to enable</help>
- <completionHelp>
- <script>${vyos_completion_dir}/list_interfaces</script>
- </completionHelp>
- <multi/>
- </properties>
- </leafNode>
- </children>
- </node>
- </children>
-</node>
-<!-- include end -->
diff --git a/interface-definitions/include/firewall/global-options.xml.i b/interface-definitions/include/firewall/global-options.xml.i
index 03c07e657..e655cd6ac 100644
--- a/interface-definitions/include/firewall/global-options.xml.i
+++ b/interface-definitions/include/firewall/global-options.xml.i
@@ -271,7 +271,6 @@
</properties>
<defaultValue>disable</defaultValue>
</leafNode>
- #include <include/firewall/flow-offload.xml.i>
</children>
</node>
<!-- include end -->
diff --git a/interface-definitions/include/firewall/ipv4-hook-forward.xml.i b/interface-definitions/include/firewall/ipv4-hook-forward.xml.i
index 08ee96419..70c0adb77 100644
--- a/interface-definitions/include/firewall/ipv4-hook-forward.xml.i
+++ b/interface-definitions/include/firewall/ipv4-hook-forward.xml.i
@@ -24,8 +24,10 @@
<constraintErrorMessage>Firewall rule number must be between 1 and 999999</constraintErrorMessage>
</properties>
<children>
+ #include <include/firewall/action-forward.xml.i>
#include <include/firewall/common-rule-ipv4.xml.i>
#include <include/firewall/inbound-interface.xml.i>
+ #include <include/firewall/offload-target.xml.i>
#include <include/firewall/outbound-interface.xml.i>
</children>
</tagNode>
diff --git a/interface-definitions/include/firewall/ipv6-hook-forward.xml.i b/interface-definitions/include/firewall/ipv6-hook-forward.xml.i
index 20ab8dbe8..d83827161 100644
--- a/interface-definitions/include/firewall/ipv6-hook-forward.xml.i
+++ b/interface-definitions/include/firewall/ipv6-hook-forward.xml.i
@@ -24,8 +24,10 @@
<constraintErrorMessage>Firewall rule number must be between 1 and 999999</constraintErrorMessage>
</properties>
<children>
+ #include <include/firewall/action-forward.xml.i>
#include <include/firewall/common-rule-ipv6.xml.i>
#include <include/firewall/inbound-interface.xml.i>
+ #include <include/firewall/offload-target.xml.i>
#include <include/firewall/outbound-interface.xml.i>
</children>
</tagNode>
diff --git a/interface-definitions/include/firewall/offload-target.xml.i b/interface-definitions/include/firewall/offload-target.xml.i
new file mode 100644
index 000000000..940ed8091
--- /dev/null
+++ b/interface-definitions/include/firewall/offload-target.xml.i
@@ -0,0 +1,10 @@
+<!-- include start from firewall/offload-target.xml.i -->
+<leafNode name="offload-target">
+ <properties>
+ <help>Set flowtable offload target. Action offload must be defined to use this setting</help>
+ <completionHelp>
+ <path>firewall flowtable</path>
+ </completionHelp>
+ </properties>
+</leafNode>
+<!-- include end -->
diff --git a/interface-definitions/include/firewall/tcp-flags.xml.i b/interface-definitions/include/firewall/tcp-flags.xml.i
index e2ce7b9fd..36546c2e4 100644
--- a/interface-definitions/include/firewall/tcp-flags.xml.i
+++ b/interface-definitions/include/firewall/tcp-flags.xml.i
@@ -1,7 +1,7 @@
<!-- include start from firewall/tcp-flags.xml.i -->
<node name="tcp">
<properties>
- <help>TCP flags to match</help>
+ <help>TCP options to match</help>
</properties>
<children>
<node name="flags">
@@ -114,22 +114,6 @@
</node>
</children>
</node>
- <leafNode name="mss">
- <properties>
- <help>Maximum segment size (MSS)</help>
- <valueHelp>
- <format>u32:1-16384</format>
- <description>Maximum segment size</description>
- </valueHelp>
- <valueHelp>
- <format>&lt;min&gt;-&lt;max&gt;</format>
- <description>TCP MSS range (use '-' as delimiter)</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--allow-range --range 1-16384"/>
- </constraint>
- </properties>
- </leafNode>
</children>
</node>
<!-- include end -->
diff --git a/interface-definitions/include/firewall/tcp-mss.xml.i b/interface-definitions/include/firewall/tcp-mss.xml.i
new file mode 100644
index 000000000..dc49b4272
--- /dev/null
+++ b/interface-definitions/include/firewall/tcp-mss.xml.i
@@ -0,0 +1,25 @@
+<!-- include start from firewall/tcp-mss.xml.i -->
+<node name="tcp">
+ <properties>
+ <help>TCP options to match</help>
+ </properties>
+ <children>
+ <leafNode name="mss">
+ <properties>
+ <help>Maximum segment size (MSS)</help>
+ <valueHelp>
+ <format>u32:1-16384</format>
+ <description>Maximum segment size</description>
+ </valueHelp>
+ <valueHelp>
+ <format>&lt;min&gt;-&lt;max&gt;</format>
+ <description>TCP MSS range (use '-' as delimiter)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--allow-range --range 1-16384"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+</node>
+<!-- include end -->
diff --git a/interface-definitions/include/policy/route-common.xml.i b/interface-definitions/include/policy/route-common.xml.i
index 216ec9bea..6551d23ab 100644
--- a/interface-definitions/include/policy/route-common.xml.i
+++ b/interface-definitions/include/policy/route-common.xml.i
@@ -314,6 +314,7 @@
</children>
</node>
#include <include/firewall/tcp-flags.xml.i>
+#include <include/firewall/tcp-mss.xml.i>
<node name="time">
<properties>
<help>Time to match rule</help>
diff --git a/interface-definitions/interfaces-ethernet.xml.in b/interface-definitions/interfaces-ethernet.xml.in
index 3669336fd..5aaa7095c 100644
--- a/interface-definitions/interfaces-ethernet.xml.in
+++ b/interface-definitions/interfaces-ethernet.xml.in
@@ -80,6 +80,12 @@
<valueless/>
</properties>
</leafNode>
+ <leafNode name="hw-tc-offload">
+ <properties>
+ <help>Enable Hardware Flow Offload</help>
+ <valueless/>
+ </properties>
+ </leafNode>
<leafNode name="lro">
<properties>
<help>Enable Large Receive Offload</help>
diff --git a/interface-definitions/service-aws-glb.xml.in b/interface-definitions/service-aws-glb.xml.in
new file mode 100644
index 000000000..c749fd04e
--- /dev/null
+++ b/interface-definitions/service-aws-glb.xml.in
@@ -0,0 +1,127 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="service">
+ <children>
+ <node name="aws">
+ <properties>
+ <help>Amazon Web Service</help>
+ <priority>1280</priority>
+ </properties>
+ <children>
+ <node name="glb" owner="${vyos_conf_scripts_dir}/service_aws_glb.py">
+ <properties>
+ <help>Gateway load-balancer tunnel handler</help>
+ </properties>
+ <children>
+ <node name="script">
+ <properties>
+ <help>Script executed on create or destroy tunnel</help>
+ </properties>
+ <children>
+ <leafNode name="on-create">
+ <properties>
+ <help>Script to run when interface is created</help>
+ <constraint>
+ <validator name="script"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="on-destroy">
+ <properties>
+ <help>Script to run when interface is destroyed</help>
+ <constraint>
+ <validator name="script"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ <node name="status">
+ <properties>
+ <help>Status</help>
+ </properties>
+ <children>
+ <leafNode name="format">
+ <properties>
+ <help>Statistic format</help>
+ <completionHelp>
+ <list>simple full</list>
+ </completionHelp>
+ <valueHelp>
+ <format>simple</format>
+ <description>Simple format</description>
+ </valueHelp>
+ <valueHelp>
+ <format>full</format>
+ <description>Full format</description>
+ </valueHelp>
+ <constraint>
+ <regex>(simple|full)</regex>
+ </constraint>
+ </properties>
+ </leafNode>
+ #include <include/port-number.xml.i>
+ </children>
+ </node>
+ <node name="threads">
+ <properties>
+ <help>Threads settings</help>
+ </properties>
+ <children>
+ <leafNode name="tunnel">
+ <properties>
+ <help>Number of threads for each tunnel processor</help>
+ <valueHelp>
+ <format>u32:1-256</format>
+ <description>Number of threads</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-256"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="tunnel-affinity">
+ <properties>
+ <help>List of cores worker threads</help>
+ <valueHelp>
+ <format>&lt;idN&gt;-&lt;idM&gt;</format>
+ <description>CPU core id range (use '-' as delimiter)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--allow-range --range 0-255"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="udp">
+ <properties>
+ <help>Number of threads for UDP receiver</help>
+ <valueHelp>
+ <format>u32:1-256</format>
+ <description>Number of threads</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--range 1-256"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ <leafNode name="udp-affinity">
+ <properties>
+ <help>List of cores worker threads</help>
+ <valueHelp>
+ <format>&lt;idN&gt;-&lt;idM&gt;</format>
+ <description>CPU core id range (use '-' as delimiter)</description>
+ </valueHelp>
+ <constraint>
+ <validator name="numeric" argument="--allow-range --range 0-255"/>
+ </constraint>
+ </properties>
+ </leafNode>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/interface-definitions/system-conntrack.xml.in b/interface-definitions/system-conntrack.xml.in
index 78d19090c..4452f1a74 100644
--- a/interface-definitions/system-conntrack.xml.in
+++ b/interface-definitions/system-conntrack.xml.in
@@ -127,6 +127,7 @@
#include <include/nat-port.xml.i>
</children>
</node>
+ #include <include/firewall/tcp-flags.xml.i>
</children>
</tagNode>
</children>
@@ -212,6 +213,7 @@
#include <include/nat-port.xml.i>
</children>
</node>
+ #include <include/firewall/tcp-flags.xml.i>
</children>
</tagNode>
</children>
diff --git a/python/vyos/ethtool.py b/python/vyos/ethtool.py
index ca3bcfc3d..f19632719 100644
--- a/python/vyos/ethtool.py
+++ b/python/vyos/ethtool.py
@@ -172,6 +172,9 @@ class Ethtool:
def get_generic_segmentation_offload(self):
return self._get_generic('generic-segmentation-offload')
+ def get_hw_tc_offload(self):
+ return self._get_generic('hw-tc-offload')
+
def get_large_receive_offload(self):
return self._get_generic('large-receive-offload')
diff --git a/python/vyos/firewall.py b/python/vyos/firewall.py
index 3305eb269..3ca7a25b9 100644
--- a/python/vyos/firewall.py
+++ b/python/vyos/firewall.py
@@ -249,29 +249,6 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):
output.append(f'{proto} {prefix}port {operator} @P_{group_name}')
- if 'log' in rule_conf and rule_conf['log'] == 'enable':
- action = rule_conf['action'] if 'action' in rule_conf else 'accept'
- #output.append(f'log prefix "[{fw_name[:19]}-{rule_id}-{action[:1].upper()}]"')
- output.append(f'log prefix "[{family}-{hook}-{fw_name}-{rule_id}-{action[:1].upper()}]"')
- ##{family}-{hook}-{fw_name}-{rule_id}
- if 'log_options' in rule_conf:
-
- if 'level' in rule_conf['log_options']:
- log_level = rule_conf['log_options']['level']
- output.append(f'log level {log_level}')
-
- if 'group' in rule_conf['log_options']:
- log_group = rule_conf['log_options']['group']
- output.append(f'log group {log_group}')
-
- if 'queue_threshold' in rule_conf['log_options']:
- queue_threshold = rule_conf['log_options']['queue_threshold']
- output.append(f'queue-threshold {queue_threshold}')
-
- if 'snapshot_length' in rule_conf['log_options']:
- log_snaplen = rule_conf['log_options']['snapshot_length']
- output.append(f'snaplen {log_snaplen}')
-
if 'hop_limit' in rule_conf:
operators = {'eq': '==', 'gt': '>', 'lt': '<'}
for op, operator in operators.items():
@@ -393,6 +370,28 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):
if 'priority' in rule_conf['vlan']:
output.append(f'vlan pcp {rule_conf["vlan"]["priority"]}')
+ if 'log' in rule_conf and rule_conf['log'] == 'enable':
+ action = rule_conf['action'] if 'action' in rule_conf else 'accept'
+ #output.append(f'log prefix "[{fw_name[:19]}-{rule_id}-{action[:1].upper()}]"')
+ output.append(f'log prefix "[{family}-{hook}-{fw_name}-{rule_id}-{action[:1].upper()}]"')
+ ##{family}-{hook}-{fw_name}-{rule_id}
+ if 'log_options' in rule_conf:
+
+ if 'level' in rule_conf['log_options']:
+ log_level = rule_conf['log_options']['level']
+ output.append(f'log level {log_level}')
+
+ if 'group' in rule_conf['log_options']:
+ log_group = rule_conf['log_options']['group']
+ output.append(f'log group {log_group}')
+
+ if 'queue_threshold' in rule_conf['log_options']:
+ queue_threshold = rule_conf['log_options']['queue_threshold']
+ output.append(f'queue-threshold {queue_threshold}')
+
+ if 'snapshot_length' in rule_conf['log_options']:
+ log_snaplen = rule_conf['log_options']['snapshot_length']
+ output.append(f'snaplen {log_snaplen}')
output.append('counter')
@@ -402,20 +401,24 @@ def parse_rule(rule_conf, hook, fw_name, rule_id, ip_name):
if 'action' in rule_conf:
# Change action=return to action=action
# #output.append(nft_action(rule_conf['action']))
- output.append(f'{rule_conf["action"]}')
- if 'jump' in rule_conf['action']:
- target = rule_conf['jump_target']
- output.append(f'NAME{def_suffix}_{target}')
+ if rule_conf['action'] == 'offload':
+ offload_target = rule_conf['offload_target']
+ output.append(f'flow add @VYOS_FLOWTABLE_{offload_target}')
+ else:
+ output.append(f'{rule_conf["action"]}')
- if 'queue' in rule_conf['action']:
- if 'queue' in rule_conf:
- target = rule_conf['queue']
- output.append(f'num {target}')
+ if 'jump' in rule_conf['action']:
+ target = rule_conf['jump_target']
+ output.append(f'NAME{def_suffix}_{target}')
- if 'queue_options' in rule_conf:
- queue_opts = ','.join(rule_conf['queue_options'])
- output.append(f'{queue_opts}')
+ if 'queue' in rule_conf['action']:
+ if 'queue' in rule_conf:
+ target = rule_conf['queue']
+ output.append(f'num {target}')
+ if 'queue_options' in rule_conf:
+ queue_opts = ','.join(rule_conf['queue_options'])
+ output.append(f'{queue_opts}')
else:
output.append('return')
diff --git a/python/vyos/ifconfig/ethernet.py b/python/vyos/ifconfig/ethernet.py
index 24ce3a803..285542057 100644
--- a/python/vyos/ifconfig/ethernet.py
+++ b/python/vyos/ifconfig/ethernet.py
@@ -57,6 +57,10 @@ class EthernetIf(Interface):
'validate': lambda v: assert_list(v, ['on', 'off']),
'possible': lambda i, v: EthernetIf.feature(i, 'gso', v),
},
+ 'hw-tc-offload': {
+ 'validate': lambda v: assert_list(v, ['on', 'off']),
+ 'possible': lambda i, v: EthernetIf.feature(i, 'hw-tc-offload', v),
+ },
'lro': {
'validate': lambda v: assert_list(v, ['on', 'off']),
'possible': lambda i, v: EthernetIf.feature(i, 'lro', v),
@@ -222,6 +226,25 @@ class EthernetIf(Interface):
print('Adapter does not support changing generic-segmentation-offload settings!')
return False
+ def set_hw_tc_offload(self, state):
+ """
+ Enable hardware TC flow offload. State can be either True or False.
+ Example:
+ >>> from vyos.ifconfig import EthernetIf
+ >>> i = EthernetIf('eth0')
+ >>> i.set_hw_tc_offload(True)
+ """
+ if not isinstance(state, bool):
+ raise ValueError('Value out of range')
+
+ enabled, fixed = self.ethtool.get_hw_tc_offload()
+ if enabled != state:
+ if not fixed:
+ return self.set_interface('hw-tc-offload', 'on' if state else 'off')
+ else:
+ print('Adapter does not support changing hw-tc-offload settings!')
+ return False
+
def set_lro(self, state):
"""
Enable Large Receive offload. State can be either True or False.
@@ -358,6 +381,9 @@ class EthernetIf(Interface):
# GSO (generic segmentation offload)
self.set_gso(dict_search('offload.gso', config) != None)
+ # GSO (generic segmentation offload)
+ self.set_hw_tc_offload(dict_search('offload.hw-tc-offload', config) != None)
+
# LRO (large receive offload)
self.set_lro(dict_search('offload.lro', config) != None)
diff --git a/python/vyos/template.py b/python/vyos/template.py
index add4d3ce5..3be486cc4 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -678,6 +678,11 @@ def conntrack_ignore_rule(rule_conf, rule_id, ipv6=False):
proto = rule_conf['protocol']
output.append(f'meta l4proto {proto}')
+ tcp_flags = dict_search_args(rule_conf, 'tcp', 'flags')
+ if tcp_flags:
+ from vyos.firewall import parse_tcp_flags
+ output.append(parse_tcp_flags(tcp_flags))
+
for side in ['source', 'destination']:
if side in rule_conf:
side_conf = rule_conf[side]
diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py
index 4c579c760..9354bd495 100644
--- a/python/vyos/utils/network.py
+++ b/python/vyos/utils/network.py
@@ -139,7 +139,7 @@ def is_ipv6_tentative(iface: str, ipv6_address: str) -> bool:
import json
from vyos.utils.process import rc_cmd
- rc, out = rc_cmd(f'ip -6 --json address show dev {iface} scope global')
+ rc, out = rc_cmd(f'ip -6 --json address show dev {iface}')
if rc:
return False
diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py
index 391ef03ff..72e04847a 100755
--- a/smoketest/scripts/cli/test_firewall.py
+++ b/smoketest/scripts/cli/test_firewall.py
@@ -523,8 +523,8 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
self.verify_nftables(nftables_search, 'ip vyos_filter')
# Check conntrack
- self.verify_nftables_chain([['accept']], 'raw', 'FW_CONNTRACK')
- self.verify_nftables_chain([['return']], 'ip6 raw', 'FW_CONNTRACK')
+ self.verify_nftables_chain([['accept']], 'ip vyos_conntrack', 'FW_CONNTRACK')
+ self.verify_nftables_chain([['return']], 'ip6 vyos_conntrack', 'FW_CONNTRACK')
def test_bridge_basic_rules(self):
name = 'smoketest'
@@ -603,17 +603,39 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase):
with open(path, 'r') as f:
self.assertNotEqual(f.read().strip(), conf['default'], msg=path)
- def test_flow_offload_software(self):
- self.cli_set(['firewall', 'global-options', 'flow-offload', 'software', 'interface', 'eth0'])
+ def test_flow_offload(self):
+ self.cli_set(['firewall', 'flowtable', 'smoketest', 'interface', 'eth0'])
+ self.cli_set(['firewall', 'flowtable', 'smoketest', 'offload', 'hardware'])
+
+ # QEMU virtual NIC does not support hw-tc-offload
+ with self.assertRaises(ConfigSessionError):
+ self.cli_commit()
+
+ self.cli_set(['firewall', 'flowtable', 'smoketest', 'offload', 'software'])
+
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'action', 'offload'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'offload-target', 'smoketest'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'protocol', 'tcp_udp'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'state', 'established', 'enable'])
+ self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'state', 'related', 'enable'])
+
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '1', 'action', 'offload'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '1', 'offload-target', 'smoketest'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '1', 'protocol', 'tcp_udp'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '1', 'state', 'established', 'enable'])
+ self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'rule', '1', 'state', 'related', 'enable'])
+
self.cli_commit()
+
nftables_search = [
- ['flowtable VYOS_FLOWTABLE_software'],
- ['hook ingress priority filter - 1'],
+ ['flowtable VYOS_FLOWTABLE_smoketest'],
+ ['hook ingress priority filter'],
['devices = { eth0 }'],
- ['flow add @VYOS_FLOWTABLE_software'],
+ ['ct state { established, related }', 'meta l4proto { tcp, udp }', 'flow add @VYOS_FLOWTABLE_smoketest'],
]
- self.verify_nftables(nftables_search, 'inet vyos_offload')
+ self.verify_nftables(nftables_search, 'ip vyos_filter')
+ self.verify_nftables(nftables_search, 'ip6 vyos_filter')
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/smoketest/scripts/cli/test_policy_route.py b/smoketest/scripts/cli/test_policy_route.py
index 118b1d3a2..c7ddf873e 100755
--- a/smoketest/scripts/cli/test_policy_route.py
+++ b/smoketest/scripts/cli/test_policy_route.py
@@ -250,7 +250,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['meta l4proto udp', 'drop'],
['tcp flags syn / syn,ack', 'meta mark set ' + mark_hex],
['ct state new', 'tcp dport 22', 'ip saddr 198.51.100.0/24', 'ip ttl > 2', 'meta mark set ' + mark_hex],
- ['meta l4proto icmp', 'log prefix "[ipv4-route-smoketest-4-A]"', 'icmp type echo-request', 'ip length { 128, 1024-2048 }', 'meta pkttype other', 'meta mark set ' + mark_hex],
+ ['log prefix "[ipv4-route-smoketest-4-A]"', 'icmp type echo-request', 'ip length { 128, 1024-2048 }', 'meta pkttype other', 'meta mark set ' + mark_hex],
['ip dscp { 0x29, 0x39-0x3b }', 'meta mark set ' + mark_hex]
]
@@ -262,7 +262,7 @@ class TestPolicyRoute(VyOSUnitTestSHIM.TestCase):
['meta l4proto udp', 'drop'],
['tcp flags syn / syn,ack', 'meta mark set ' + mark_hex],
['ct state new', 'tcp dport 22', 'ip6 saddr 2001:db8::/64', 'ip6 hoplimit > 2', 'meta mark set ' + mark_hex],
- ['meta l4proto ipv6-icmp', 'log prefix "[ipv6-route6-smoketest6-4-A]"', 'icmpv6 type echo-request', 'ip6 length != { 128, 1024-2048 }', 'meta pkttype multicast', 'meta mark set ' + mark_hex],
+ ['log prefix "[ipv6-route6-smoketest6-4-A]"', 'icmpv6 type echo-request', 'ip6 length != { 128, 1024-2048 }', 'meta pkttype multicast', 'meta mark set ' + mark_hex],
['ip6 dscp != { 0x0e-0x13, 0x3d }', 'meta mark set ' + mark_hex]
]
diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py
index ee8a07b37..357c3dfb1 100755
--- a/smoketest/scripts/cli/test_service_dns_dynamic.py
+++ b/smoketest/scripts/cli/test_service_dns_dynamic.py
@@ -79,8 +79,8 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
# default value 300 seconds
self.assertIn(f'daemon=300', ddclient_conf)
- self.assertIn(f'use=if', ddclient_conf)
- self.assertIn(f'if={interface}', ddclient_conf)
+ self.assertIn(f'usev4=ifv4', ddclient_conf)
+ self.assertIn(f'ifv4={interface}', ddclient_conf)
self.assertIn(f'password={password}', ddclient_conf)
for opt in details.keys():
diff --git a/smoketest/scripts/cli/test_system_conntrack.py b/smoketest/scripts/cli/test_system_conntrack.py
index ea304783d..c9f184558 100755
--- a/smoketest/scripts/cli/test_system_conntrack.py
+++ b/smoketest/scripts/cli/test_system_conntrack.py
@@ -200,7 +200,7 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
self.assertTrue(os.path.isdir(f'/sys/module/{driver}'))
if 'nftables' in module_options:
for rule in module_options['nftables']:
- self.assertTrue(find_nftables_rule('raw', 'VYOS_CT_HELPER', [rule]) != None)
+ self.assertTrue(find_nftables_rule('ip vyos_conntrack', 'VYOS_CT_HELPER', [rule]) != None)
# unload modules
for module in modules:
@@ -216,7 +216,7 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
self.assertFalse(os.path.isdir(f'/sys/module/{driver}'))
if 'nftables' in module_options:
for rule in module_options['nftables']:
- self.assertTrue(find_nftables_rule('raw', 'VYOS_CT_HELPER', [rule]) == None)
+ self.assertTrue(find_nftables_rule('ip vyos_conntrack', 'VYOS_CT_HELPER', [rule]) == None)
def test_conntrack_hash_size(self):
hash_size = '65536'
@@ -256,6 +256,7 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'destination', 'address', '192.0.2.2'])
self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'destination', 'port', '22'])
self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'protocol', 'tcp'])
+ self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '1', 'tcp', 'flags', 'syn'])
self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '2', 'source', 'address', '192.0.2.1'])
self.cli_set(base_path + ['ignore', 'ipv4', 'rule', '2', 'destination', 'group', 'address-group', address_group])
@@ -274,7 +275,7 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
nftables_search = [
- ['ip saddr 192.0.2.1', 'ip daddr 192.0.2.2', 'tcp dport 22', 'notrack'],
+ ['ip saddr 192.0.2.1', 'ip daddr 192.0.2.2', 'tcp dport 22', 'tcp flags & syn == syn', 'notrack'],
['ip saddr 192.0.2.1', 'ip daddr @A_conntracktest', 'notrack']
]
@@ -284,8 +285,8 @@ class TestSystemConntrack(VyOSUnitTestSHIM.TestCase):
['ip6 saddr fe80::1', 'ip6 daddr != fe80::3', 'notrack']
]
- self.verify_nftables(nftables_search, 'raw')
- self.verify_nftables(nftables6_search, 'ip6 raw')
+ self.verify_nftables(nftables_search, 'ip vyos_conntrack')
+ self.verify_nftables(nftables6_search, 'ip6 vyos_conntrack')
self.cli_delete(['firewall'])
diff --git a/smoketest/scripts/cli/test_system_flow-accounting.py b/smoketest/scripts/cli/test_system_flow-accounting.py
index d55ea616e..6c761579b 100755
--- a/smoketest/scripts/cli/test_system_flow-accounting.py
+++ b/smoketest/scripts/cli/test_system_flow-accounting.py
@@ -67,7 +67,7 @@ class TestSystemFlowAccounting(VyOSUnitTestSHIM.TestCase):
self.cli_commit()
# verify configuration
- nftables_output = cmd('sudo nft list chain raw VYOS_CT_PREROUTING_HOOK').splitlines()
+ nftables_output = cmd('sudo nft list chain raw VYOS_PREROUTING_HOOK').splitlines()
for interface in Section.interfaces('ethernet'):
rule_found = False
ifname_search = f'iifname "{interface}"'
diff --git a/src/conf_mode/conntrack.py b/src/conf_mode/conntrack.py
index a0de914bc..21a20ea8d 100755
--- a/src/conf_mode/conntrack.py
+++ b/src/conf_mode/conntrack.py
@@ -20,11 +20,10 @@ import re
from sys import exit
from vyos.config import Config
-from vyos.firewall import find_nftables_rule
-from vyos.firewall import remove_nftables_rule
from vyos.utils.process import process_named_running
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
+from vyos.utils.dict import dict_search_recursive
from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
from vyos.utils.process import run
@@ -47,8 +46,8 @@ module_map = {
'ko' : ['nf_nat_h323', 'nf_conntrack_h323'],
},
'nfs' : {
- 'nftables' : ['ct helper set "rpc_tcp" tcp dport "{111}" return',
- 'ct helper set "rpc_udp" udp dport "{111}" return']
+ 'nftables' : ['ct helper set "rpc_tcp" tcp dport {111} return',
+ 'ct helper set "rpc_udp" udp dport {111} return']
},
'pptp' : {
'ko' : ['nf_nat_pptp', 'nf_conntrack_pptp'],
@@ -57,7 +56,7 @@ module_map = {
'ko' : ['nf_nat_sip', 'nf_conntrack_sip'],
},
'sqlnet' : {
- 'nftables' : ['ct helper set "tns_tcp" tcp dport "{1521,1525,1536}" return']
+ 'nftables' : ['ct helper set "tns_tcp" tcp dport {1521,1525,1536} return']
},
'tftp' : {
'ko' : ['nf_nat_tftp', 'nf_conntrack_tftp'],
@@ -87,10 +86,25 @@ def get_config(config=None):
get_first_key=True,
with_recursive_defaults=True)
- conntrack['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'),
+ conntrack['firewall'] = conf.get_config_dict(['firewall'], key_mangling=('-', '_'),
get_first_key=True,
no_tag_node_value_mangle=True)
+ conntrack['flowtable_enabled'] = False
+ flow_offload = dict_search_args(conntrack['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'):
+ conntrack['flowtable_enabled'] = True
+ break
+
+ conntrack['ipv4_nat_action'] = 'accept' if conf.exists(['nat']) else 'return'
+ conntrack['ipv6_nat_action'] = 'accept' if conf.exists(['nat66']) else 'return'
+ conntrack['wlb_action'] = 'accept' if conf.exists(['load-balancing', 'wan']) else 'return'
+ conntrack['wlb_local_action'] = conf.exists(['load-balancing', 'wan', 'enable-local-traffic'])
+
+ conntrack['module_map'] = module_map
+
return conntrack
def verify(conntrack):
@@ -104,6 +118,17 @@ def verify(conntrack):
if 'protocol' not in rule_config or rule_config['protocol'] not in ['tcp', 'udp']:
raise ConfigError(f'Port requires tcp or udp as protocol in rule {rule}')
+ tcp_flags = dict_search_args(rule_config, 'tcp', 'flags')
+ if tcp_flags:
+ if dict_search_args(rule_config, 'protocol') != 'tcp':
+ raise ConfigError('Protocol must be tcp when specifying tcp flags')
+
+ not_flags = dict_search_args(rule_config, 'tcp', 'flags', 'not')
+ if not_flags:
+ duplicates = [flag for flag in tcp_flags if flag in not_flags]
+ if duplicates:
+ raise ConfigError(f'Cannot match a tcp flag as set and not set')
+
for side in ['destination', 'source']:
if side in rule_config:
side_conf = rule_config[side]
@@ -127,7 +152,7 @@ def verify(conntrack):
if inet == 'ipv6':
group = f'ipv6_{group}'
- group_obj = dict_search_args(conntrack['firewall_group'], group, group_name)
+ group_obj = dict_search_args(conntrack['firewall'], 'group', group, group_name)
if group_obj is None:
raise ConfigError(f'Invalid {error_group} "{group_name}" on ignore rule')
@@ -138,22 +163,29 @@ def verify(conntrack):
return None
def generate(conntrack):
+ if not os.path.exists(nftables_ct_file):
+ conntrack['first_install'] = True
+
+ # Determine if conntrack is needed
+ conntrack['ipv4_firewall_action'] = 'return'
+ conntrack['ipv6_firewall_action'] = 'return'
+
+ if conntrack['flowtable_enabled']:
+ conntrack['ipv4_firewall_action'] = 'accept'
+ conntrack['ipv6_firewall_action'] = 'accept'
+ else:
+ for rules, path in dict_search_recursive(conntrack['firewall'], 'rule'):
+ if any(('state' in rule_conf or 'connection_status' in rule_conf) for rule_conf in rules.values()):
+ if path[0] == 'ipv4':
+ conntrack['ipv4_firewall_action'] = 'accept'
+ elif path[0] == 'ipv6':
+ conntrack['ipv6_firewall_action'] = 'accept'
+
render(conntrack_config, 'conntrack/vyos_nf_conntrack.conf.j2', conntrack)
render(sysctl_file, 'conntrack/sysctl.conf.j2', conntrack)
render(nftables_ct_file, 'conntrack/nftables-ct.j2', conntrack)
return None
-def find_nftables_ct_rule(table, chain, rule):
- helper_search = re.search('ct helper set "(\w+)"', rule)
- if helper_search:
- rule = helper_search[1]
- return find_nftables_rule(table, chain, [rule])
-
-def find_remove_rule(table, chain, rule):
- handle = find_nftables_ct_rule(table, chain, rule)
- if handle:
- remove_nftables_rule(table, chain, handle)
-
def apply(conntrack):
# Depending on the enable/disable state of the ALG (Application Layer Gateway)
# modules we need to either insmod or rmmod the helpers.
@@ -164,21 +196,10 @@ def apply(conntrack):
# Only remove the module if it's loaded
if os.path.exists(f'/sys/module/{mod}'):
cmd(f'rmmod {mod}')
- if 'nftables' in module_config:
- for rule in module_config['nftables']:
- find_remove_rule('raw', 'VYOS_CT_HELPER', rule)
- find_remove_rule('ip6 raw', 'VYOS_CT_HELPER', rule)
else:
if 'ko' in module_config:
for mod in module_config['ko']:
cmd(f'modprobe {mod}')
- if 'nftables' in module_config:
- for rule in module_config['nftables']:
- if not find_nftables_ct_rule('raw', 'VYOS_CT_HELPER', rule):
- cmd(f'nft insert rule raw VYOS_CT_HELPER {rule}')
-
- if not find_nftables_ct_rule('ip6 raw', 'VYOS_CT_HELPER', rule):
- cmd(f'nft insert rule ip6 raw VYOS_CT_HELPER {rule}')
# Load new nftables ruleset
install_result, output = rc_cmd(f'nft -f {nftables_ct_file}')
diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py
index ab80defe8..4b1aed742 100755
--- a/src/conf_mode/dns_dynamic.py
+++ b/src/conf_mode/dns_dynamic.py
@@ -104,7 +104,7 @@ def generate(dyndns):
if not dyndns or 'address' not in dyndns:
return None
- render(config_file, 'dns-dynamic/ddclient.conf.j2', dyndns)
+ render(config_file, 'dns-dynamic/ddclient.conf.j2', dyndns, permission=0o600)
render(systemd_override, 'dns-dynamic/override.conf.j2', dyndns)
return None
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index 769cc598f..3d799318e 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -27,6 +27,7 @@ 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.ethtool import Ethtool
from vyos.firewall import fqdn_config_parse
from vyos.firewall import geoip_update
from vyos.template import render
@@ -141,13 +142,7 @@ 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
+ set_dependents('conntrack', conf)
return firewall
@@ -169,6 +164,15 @@ def verify_rule(firewall, rule_conf, ipv6):
if target not in dict_search_args(firewall, 'ipv6', 'name'):
raise ConfigError(f'Invalid jump-target. Firewall ipv6 name {target} does not exist on the system')
+ if rule_conf['action'] == 'offload':
+ if 'offload_target' not in rule_conf:
+ raise ConfigError('Action set to offload, but no offload-target specified')
+
+ offload_target = rule_conf['offload_target']
+
+ if not dict_search_args(firewall, 'flowtable', offload_target):
+ raise ConfigError(f'Invalid offload-target. Flowtable "{offload_target}" does not exist on the system')
+
if 'queue_options' in rule_conf:
if 'queue' not in rule_conf['action']:
raise ConfigError('queue-options defined, but action queue needed and it is not defined')
@@ -288,7 +292,31 @@ def verify_nested_group(group_name, group, groups, seen):
if 'include' in groups[g]:
verify_nested_group(g, groups[g], groups, seen)
+def verify_hardware_offload(ifname):
+ ethtool = Ethtool(ifname)
+ enabled, fixed = ethtool.get_hw_tc_offload()
+
+ if not enabled and fixed:
+ raise ConfigError(f'Interface "{ifname}" does not support hardware offload')
+
+ if not enabled:
+ raise ConfigError(f'Interface "{ifname}" requires "offload hw-tc-offload"')
+
def verify(firewall):
+ if 'flowtable' in firewall:
+ for flowtable, flowtable_conf in firewall['flowtable'].items():
+ if 'interface' not in flowtable_conf:
+ raise ConfigError(f'Flowtable "{flowtable}" requires at least one interface')
+
+ for ifname in flowtable_conf['interface']:
+ verify_interface_exists(ifname)
+
+ if dict_search_args(flowtable_conf, 'offload') == 'hardware':
+ interfaces = flowtable_conf['interface']
+
+ for ifname in interfaces:
+ verify_hardware_offload(ifname)
+
if 'group' in firewall:
for group_type in nested_group_types:
if group_type in firewall['group']:
@@ -336,33 +364,12 @@ 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):
if not os.path.exists(nftables_conf):
firewall['first_install'] = True
- # Determine if conntrack is needed
- firewall['ipv4_conntrack_action'] = 'return'
- firewall['ipv6_conntrack_action'] = 'return'
- 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
@@ -392,8 +399,7 @@ def apply(firewall):
apply_sysfs(firewall)
- if firewall['group_resync']:
- call_dependents()
+ call_dependents()
# T970 Enable a resolver (systemd daemon) that checks
# domain-group/fqdn addresses and update entries for domains by timeout
diff --git a/src/conf_mode/flow_accounting_conf.py b/src/conf_mode/flow_accounting_conf.py
index 71acd69fa..81ee39df1 100755
--- a/src/conf_mode/flow_accounting_conf.py
+++ b/src/conf_mode/flow_accounting_conf.py
@@ -37,7 +37,7 @@ uacctd_conf_path = '/run/pmacct/uacctd.conf'
systemd_service = 'uacctd.service'
systemd_override = f'/run/systemd/system/{systemd_service}.d/override.conf'
nftables_nflog_table = 'raw'
-nftables_nflog_chain = 'VYOS_CT_PREROUTING_HOOK'
+nftables_nflog_chain = 'VYOS_PREROUTING_HOOK'
egress_nftables_nflog_table = 'inet mangle'
egress_nftables_nflog_chain = 'FORWARD'
diff --git a/src/conf_mode/high-availability.py b/src/conf_mode/high-availability.py
index 70f43ab52..b3b27b14e 100755
--- a/src/conf_mode/high-availability.py
+++ b/src/conf_mode/high-availability.py
@@ -59,7 +59,7 @@ def get_config(config=None):
if conf.exists(conntrack_path):
ha['conntrack_sync_group'] = conf.return_value(conntrack_path)
- if leaf_node_changed(conf, base + ['vrrp', 'disable-snmp']):
+ if leaf_node_changed(conf, base + ['vrrp', 'snmp']):
ha.update({'restart_required': {}})
return ha
diff --git a/src/conf_mode/load-balancing-wan.py b/src/conf_mode/load-balancing-wan.py
index ad9c80d72..5da0b906b 100755
--- a/src/conf_mode/load-balancing-wan.py
+++ b/src/conf_mode/load-balancing-wan.py
@@ -21,6 +21,7 @@ from shutil import rmtree
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdep import set_dependents, call_dependents
from vyos.utils.process import cmd
from vyos.template import render
from vyos import ConfigError
@@ -49,6 +50,8 @@ def get_config(config=None):
if lb.from_defaults(['rule', rule, 'limit']):
del lb['rule'][rule]['limit']
+ set_dependents('conntrack', conf)
+
return lb
@@ -132,6 +135,8 @@ def apply(lb):
cmd('sudo sysctl -w net.netfilter.nf_conntrack_acct=1')
cmd(f'systemctl restart {systemd_service}')
+ call_dependents()
+
return None
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index e37a7011c..52a7a71fd 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -18,13 +18,12 @@ import jmespath
import json
import os
-from distutils.version import LooseVersion
-from platform import release as kernel_version
from sys import exit
from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdep import set_dependents, call_dependents
from vyos.template import render
from vyos.template import is_ip_network
from vyos.utils.kernel import check_kmod
@@ -38,10 +37,7 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-if LooseVersion(kernel_version()) > LooseVersion('5.1'):
- k_mod = ['nft_nat', 'nft_chain_nat']
-else:
- k_mod = ['nft_nat', 'nft_chain_nat_ipv4']
+k_mod = ['nft_nat', 'nft_chain_nat']
nftables_nat_config = '/run/nftables_nat.conf'
nftables_static_nat_conf = '/run/nftables_static-nat-rules.nft'
@@ -53,18 +49,27 @@ valid_groups = [
'port_group'
]
-def get_handler(json, chain, target):
- """ Get nftable rule handler number of given chain/target combination.
- Handler is required when adding NAT/Conntrack helper targets """
- for x in json:
- if x['chain'] != chain:
- continue
- if x['target'] != target:
- continue
- return x['handle']
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
- return None
+ base = ['nat']
+ nat = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
+ set_dependents('conntrack', conf)
+
+ if not conf.exists(base):
+ nat['deleted'] = ''
+ return nat
+
+ nat['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True,
+ no_tag_node_value_mangle=True)
+
+ return nat
def verify_rule(config, err_msg, groups_dict):
""" Common verify steps used for both source and destination NAT """
@@ -136,62 +141,11 @@ def verify_rule(config, err_msg, groups_dict):
if count != 100:
Warning(f'Sum of weight for nat load balance rule is not 100. You may get unexpected behaviour')
-def get_config(config=None):
- if config:
- conf = config
- else:
- conf = Config()
-
- base = ['nat']
- nat = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True,
- with_recursive_defaults=True)
-
- # read in current nftable (once) for further processing
- tmp = cmd('nft -j list table raw')
- nftable_json = json.loads(tmp)
-
- # condense the full JSON table into a list with only relevand informations
- pattern = 'nftables[?rule].rule[?expr[].jump].{chain: chain, handle: handle, target: expr[].jump.target | [0]}'
- condensed_json = jmespath.search(pattern, nftable_json)
-
- if not conf.exists(base):
- if get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER'):
- nat['helper_functions'] = 'remove'
-
- # Retrieve current table handler positions
- nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER')
- nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK')
- nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_HELPER')
- nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'NAT_CONNTRACK')
- nat['deleted'] = ''
- return nat
-
- nat['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
-
- # check if NAT connection tracking helpers need to be set up - this has to
- # be done only once
- if not get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK'):
- nat['helper_functions'] = 'add'
-
- # Retrieve current table handler positions
- nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_IGNORE')
- nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_PREROUTING_HOOK')
- nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_IGNORE')
- nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_OUTPUT_HOOK')
-
- return nat
-
def verify(nat):
if not nat or 'deleted' in nat:
# no need to verify the CLI as NAT is going to be deactivated
return None
- if 'helper_functions' in nat:
- if not (nat['pre_ct_ignore'] or nat['pre_ct_conntrack'] or nat['out_ct_ignore'] or nat['out_ct_conntrack']):
- raise Exception('could not determine nftable ruleset handlers')
-
if dict_search('source.rule', nat):
for rule, config in dict_search('source.rule', nat).items():
err_msg = f'Source NAT configuration error in rule {rule}:'
@@ -267,6 +221,8 @@ def apply(nat):
os.unlink(nftables_nat_config)
os.unlink(nftables_static_nat_conf)
+ call_dependents()
+
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py
index 4c12618bc..46d796bc8 100755
--- a/src/conf_mode/nat66.py
+++ b/src/conf_mode/nat66.py
@@ -23,6 +23,7 @@ from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdep import set_dependents, call_dependents
from vyos.template import render
from vyos.utils.process import cmd
from vyos.utils.kernel import check_kmod
@@ -37,18 +38,6 @@ k_mod = ['nft_nat', 'nft_chain_nat']
nftables_nat66_config = '/run/nftables_nat66.nft'
ndppd_config = '/run/ndppd/ndppd.conf'
-def get_handler(json, chain, target):
- """ Get nftable rule handler number of given chain/target combination.
- Handler is required when adding NAT66/Conntrack helper targets """
- for x in json:
- if x['chain'] != chain:
- continue
- if x['target'] != target:
- continue
- return x['handle']
-
- return None
-
def get_config(config=None):
if config:
conf = config
@@ -58,35 +47,10 @@ def get_config(config=None):
base = ['nat66']
nat = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # read in current nftable (once) for further processing
- tmp = cmd('nft -j list table ip6 raw')
- nftable_json = json.loads(tmp)
-
- # condense the full JSON table into a list with only relevand informations
- pattern = 'nftables[?rule].rule[?expr[].jump].{chain: chain, handle: handle, target: expr[].jump.target | [0]}'
- condensed_json = jmespath.search(pattern, nftable_json)
+ set_dependents('conntrack', conf)
if not conf.exists(base):
- nat['helper_functions'] = 'remove'
- nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER')
- nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK')
- nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_HELPER')
- nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'NAT_CONNTRACK')
nat['deleted'] = ''
- return nat
-
- # check if NAT66 connection tracking helpers need to be set up - this has to
- # be done only once
- if not get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK'):
- nat['helper_functions'] = 'add'
-
- # Retrieve current table handler positions
- nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_IGNORE')
- nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_PREROUTING_HOOK')
- nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_IGNORE')
- nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_OUTPUT_HOOK')
- else:
- nat['helper_functions'] = 'has'
return nat
@@ -95,10 +59,6 @@ def verify(nat):
# no need to verify the CLI as NAT66 is going to be deactivated
return None
- if 'helper_functions' in nat and nat['helper_functions'] != 'has':
- if not (nat['pre_ct_conntrack'] or nat['out_ct_conntrack']):
- raise Exception('could not determine nftable ruleset handlers')
-
if dict_search('source.rule', nat):
for rule, config in dict_search('source.rule', nat).items():
err_msg = f'Source NAT66 configuration error in rule {rule}:'
@@ -155,6 +115,8 @@ def apply(nat):
else:
cmd('systemctl restart ndppd')
+ call_dependents()
+
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/service_aws_glb.py b/src/conf_mode/service_aws_glb.py
new file mode 100755
index 000000000..d1ed5a07b
--- /dev/null
+++ b/src/conf_mode/service_aws_glb.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+from sys import exit
+
+from vyos.config import Config
+from vyos.template import render
+from vyos.utils.process import call
+from vyos import ConfigError
+from vyos import airbag
+airbag.enable()
+
+systemd_service = 'aws-gwlbtun.service'
+systemd_override = '/run/systemd/system/aws-gwlbtun.service.d/10-override.conf'
+
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+ base = ['service', 'aws', 'glb']
+ if not conf.exists(base):
+ return None
+
+ glb = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ no_tag_node_value_mangle=True)
+
+ return glb
+
+
+def verify(glb):
+ # bail out early - looks like removal from running config
+ if not glb:
+ return None
+
+
+def generate(glb):
+ if not glb:
+ return None
+
+ render(systemd_override, 'aws/override_aws_gwlbtun.conf.j2', glb)
+
+
+def apply(glb):
+ call('systemctl daemon-reload')
+ if not glb:
+ call(f'systemctl stop {systemd_service}')
+ else:
+ call(f'systemctl restart {systemd_service}')
+ return None
+
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)
diff --git a/src/conf_mode/system-ip.py b/src/conf_mode/system-ip.py
index 5e4e5ec28..7612e2c0d 100755
--- a/src/conf_mode/system-ip.py
+++ b/src/conf_mode/system-ip.py
@@ -20,10 +20,12 @@ from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configverify import verify_route_map
from vyos.template import render_to_string
-from vyos.utils.process import call
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
+from vyos.utils.process import call
+from vyos.utils.process import is_systemd_service_active
from vyos.utils.system import sysctl_write
+
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -115,16 +117,20 @@ def apply(opt):
value = '48' if (tmp is None) else tmp
sysctl_write('net.ipv4.tcp_mtu_probe_floor', value)
- zebra_daemon = 'zebra'
- # Save original configuration prior to starting any commit actions
- frr_cfg = frr.FRRConfig()
-
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section(r'ip protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
- if 'frr_zebra_config' in opt:
- frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
+ # During startup of vyos-router that brings up FRR, the service is not yet
+ # running when this script is called first. Skip this part and wait for initial
+ # commit of the configuration to trigger this statement
+ if is_systemd_service_active('frr.service'):
+ zebra_daemon = 'zebra'
+ # Save original configuration prior to starting any commit actions
+ frr_cfg = frr.FRRConfig()
+
+ # The route-map used for the FIB (zebra) is part of the zebra daemon
+ frr_cfg.load_configuration(zebra_daemon)
+ frr_cfg.modify_section(r'ip protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
+ if 'frr_zebra_config' in opt:
+ frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config'])
+ frr_cfg.commit_configuration(zebra_daemon)
if __name__ == '__main__':
try:
diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py
index e40ed38e2..90a1a8087 100755
--- a/src/conf_mode/system-ipv6.py
+++ b/src/conf_mode/system-ipv6.py
@@ -22,8 +22,9 @@ from vyos.configdict import dict_merge
from vyos.configverify import verify_route_map
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
-from vyos.utils.system import sysctl_write
from vyos.utils.file import write_file
+from vyos.utils.process import is_systemd_service_active
+from vyos.utils.system import sysctl_write
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -93,16 +94,20 @@ def apply(opt):
if name == 'accept_dad':
write_file(os.path.join(root, name), value)
- zebra_daemon = 'zebra'
- # Save original configuration prior to starting any commit actions
- frr_cfg = frr.FRRConfig()
+ # During startup of vyos-router that brings up FRR, the service is not yet
+ # running when this script is called first. Skip this part and wait for initial
+ # commit of the configuration to trigger this statement
+ if is_systemd_service_active('frr.service'):
+ zebra_daemon = 'zebra'
+ # Save original configuration prior to starting any commit actions
+ frr_cfg = frr.FRRConfig()
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section(r'ipv6 protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
- if 'frr_zebra_config' in opt:
- frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
+ # The route-map used for the FIB (zebra) is part of the zebra daemon
+ frr_cfg.load_configuration(zebra_daemon)
+ frr_cfg.modify_section(r'ipv6 protocol \w+ route-map [-a-zA-Z0-9.]+', stop_pattern='(\s|!)')
+ if 'frr_zebra_config' in opt:
+ frr_cfg.add_before(frr.default_add_before, opt['frr_zebra_config'])
+ frr_cfg.commit_configuration(zebra_daemon)
if __name__ == '__main__':
try:
diff --git a/src/conf_mode/system_frr.py b/src/conf_mode/system_frr.py
index d8224b3c3..6727b63c2 100755
--- a/src/conf_mode/system_frr.py
+++ b/src/conf_mode/system_frr.py
@@ -18,7 +18,7 @@ from pathlib import Path
from sys import exit
from vyos import ConfigError
-from vyos import airbag
+from vyos.base import Warning
from vyos.config import Config
from vyos.logger import syslog
from vyos.template import render_to_string
@@ -26,6 +26,8 @@ from vyos.utils.boot import boot_configuration_complete
from vyos.utils.file import read_file
from vyos.utils.file import write_file
from vyos.utils.process import call
+
+from vyos import airbag
airbag.enable()
# path to daemons config and config status files
@@ -62,10 +64,8 @@ def apply(frr_config):
if boot_configuration_complete() and frr_config.get('config_file_changed'):
# Since FRR restart is not safe thing, better to give
# control over this to users
- print('''
- You need to reboot a router (preferred) or restart FRR
- to apply changes in modules settings
- ''')
+ Warning('You need to reboot the router (preferred) or restart '\
+ 'FRR to apply changes in modules settings')
# restart FRR automatically
# During initial boot this should be safe in most cases
diff --git a/src/systemd/aws-gwlbtun.service b/src/systemd/aws-gwlbtun.service
new file mode 100644
index 000000000..97d772dec
--- /dev/null
+++ b/src/systemd/aws-gwlbtun.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Description=AWS Gateway Load Balancer Tunnel Handler
+Documentation=https://github.com/aws-samples/aws-gateway-load-balancer-tunnel-handler
+After=network.target
+
+[Service]
+ExecStart=
+Restart=on-failure
+
+[Install]
+WantedBy=multi-user.target