Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

T6841: firewall: improve config parsing for ZBF when using VRFs and interfaces attached to VRFs #4180

Merged
merged 4 commits into from
Jan 6, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 47 additions & 9 deletions data/templates/firewall/nftables-zone.j2
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,14 @@
{% endif %}
{% for zone_name, zone_conf in zone.items() %}
{% if 'local_zone' not in zone_conf %}
oifname { {{ zone_conf.interface | join(',') }} } counter jump VZONE_{{ zone_name }}
{% if 'interface' in zone_conf.member %}
oifname { {{ zone_conf.member.interface | join(',') }} } counter jump VZONE_{{ zone_name }}
{% endif %}
{% if 'vrf' in zone_conf.member %}
{% for vrf_name in zone_conf.member.vrf %}
oifname { {{ zone_conf['vrf_interfaces'][vrf_name] }} } counter jump VZONE_{{ zone_name }}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
}
Expand Down Expand Up @@ -40,8 +47,15 @@
iifname lo counter return
{% if zone_conf.from is vyos_defined %}
{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall[fw_name] is vyos_defined %}
iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
iifname { {{ zone[from_zone].interface | join(",") }} } counter return

{% if 'interface' in zone[from_zone].member %}
iifname { {{ zone[from_zone].member.interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
iifname { {{ zone[from_zone].member.interface | join(",") }} } counter return
{% endif %}
{% if 'vrf' in zone[from_zone].member %}
iifname { {{ zone[from_zone].member.vrf | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
iifname { {{ zone[from_zone].member.vrf | join(",") }} } counter return
{% endif %}
{% endfor %}
{% endif %}
{{ zone_conf | nft_default_rule('zone_' + zone_name, family) }}
Expand All @@ -50,23 +64,47 @@
oifname lo counter return
{% if zone_conf.from_local is vyos_defined %}
{% for from_zone, from_conf in zone_conf.from_local.items() if from_conf.firewall[fw_name] is vyos_defined %}
oifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
oifname { {{ zone[from_zone].interface | join(",") }} } counter return
{% if 'interface' in zone[from_zone].member %}
oifname { {{ zone[from_zone].member.interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
oifname { {{ zone[from_zone].member.interface | join(",") }} } counter return
{% endif %}
{% if 'vrf' in zone[from_zone].member %}
{% for vrf_name in zone[from_zone].member.vrf %}
oifname { {{ zone[from_zone]['vrf_interfaces'][vrf_name] }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
oifname { {{ zone[from_zone]['vrf_interfaces'][vrf_name] }} } counter return
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{{ zone_conf | nft_default_rule('zone_' + zone_name, family) }}
}
{% else %}
chain VZONE_{{ zone_name }} {
iifname { {{ zone_conf.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6) }}
{% if 'interface' in zone_conf.member %}
iifname { {{ zone_conf.member.interface | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6) }}
{% endif %}
{% if 'vrf' in zone_conf.member %}
iifname { {{ zone_conf.member.vrf | join(",") }} } counter {{ zone_conf | nft_intra_zone_action(ipv6) }}
{% endif %}
{% if zone_conf.intra_zone_filtering is vyos_defined %}
iifname { {{ zone_conf.interface | join(",") }} } counter return
{% if 'interface' in zone_conf.member %}
iifname { {{ zone_conf.member.interface | join(",") }} } counter return
{% endif %}
{% if 'vrf' in zone_conf.member %}
iifname { {{ zone_conf.member.vrf | join(",") }} } counter return
{% endif %}
{% endif %}
{% if zone_conf.from is vyos_defined %}
{% for from_zone, from_conf in zone_conf.from.items() if from_conf.firewall[fw_name] is vyos_defined %}
{% if zone[from_zone].local_zone is not defined %}
iifname { {{ zone[from_zone].interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
iifname { {{ zone[from_zone].interface | join(",") }} } counter return
{% if 'interface' in zone[from_zone].member %}
iifname { {{ zone[from_zone].member.interface | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
iifname { {{ zone[from_zone].member.interface | join(",") }} } counter return
{% endif %}
{% if 'vrf' in zone[from_zone].member %}
iifname { {{ zone[from_zone].member.vrf | join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
iifname { {{ zone[from_zone].member.vrf | join(",") }} } counter return
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
Expand Down
53 changes: 20 additions & 33 deletions interface-definitions/firewall.xml.in
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,7 @@
</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>
#include <include/generic-interface-multi.xml.i>
<leafNode name="offload">
<properties>
<help>Offloading method</help>
Expand Down Expand Up @@ -155,15 +147,7 @@
<constraintErrorMessage>Name of firewall group can only contain alphanumeric letters, hyphen, underscores and dot</constraintErrorMessage>
</properties>
<children>
<leafNode name="interface">
<properties>
<help>Interface-group member</help>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
</completionHelp>
<multi/>
</properties>
</leafNode>
#include <include/generic-interface-multi.xml.i>
<leafNode name="include">
<properties>
<help>Include another interface-group</help>
Expand Down Expand Up @@ -464,24 +448,27 @@
</node>
</children>
</tagNode>
<leafNode name="interface">
<node name="member">
<properties>
<help>Interface associated with zone</help>
<valueHelp>
<format>txt</format>
<description>Interface associated with zone</description>
</valueHelp>
<valueHelp>
<format>vrf</format>
<description>VRF associated with zone</description>
</valueHelp>
<completionHelp>
<script>${vyos_completion_dir}/list_interfaces</script>
<path>vrf name</path>
</completionHelp>
<multi/>
</properties>
</leafNode>
<children>
#include <include/generic-interface-multi.xml.i>
<leafNode name="vrf">
<properties>
<help>VRF associated with zone</help>
<valueHelp>
<format>vrf</format>
<description>VRF associated with zone</description>
</valueHelp>
<completionHelp>
<path>vrf name</path>
</completionHelp>
<multi/>
</properties>
</leafNode>
</children>
</node>
<node name="intra-zone-filtering">
<properties>
<help>Intra-zone filtering</help>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!-- include start from include/version/firewall-version.xml.i -->
<syntaxVersion component='firewall' version='17'></syntaxVersion>
<syntaxVersion component='firewall' version='18'></syntaxVersion>
<!-- include end -->
4 changes: 3 additions & 1 deletion python/vyos/utils/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ def get_vrf_members(vrf: str) -> list:
answer = json.loads(output)
for data in answer:
if 'ifname' in data:
interfaces.append(data.get('ifname'))
# Skip PIM interfaces which appears in VRF
if 'pim' not in data.get('ifname'):
interfaces.append(data.get('ifname'))
except:
pass
return interfaces
Expand Down
96 changes: 94 additions & 2 deletions smoketest/scripts/cli/test_firewall.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
# Copyright (C) 2021-2023 VyOS maintainers and contributors
# Copyright (C) 2021-2024 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
Expand Down Expand Up @@ -906,7 +906,7 @@ def test_timeout_sysctl(self):
def test_zone_basic(self):
self.cli_set(['firewall', 'ipv4', 'name', 'smoketest', 'default-action', 'drop'])
self.cli_set(['firewall', 'ipv6', 'name', 'smoketestv6', 'default-action', 'drop'])
self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'interface', 'eth0'])
self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'member', 'interface', 'eth0'])
self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'from', 'smoketest-local', 'firewall', 'name', 'smoketest'])
self.cli_set(['firewall', 'zone', 'smoketest-eth0', 'intra-zone-filtering', 'firewall', 'ipv6-name', 'smoketestv6'])
self.cli_set(['firewall', 'zone', 'smoketest-local', 'local-zone'])
Expand Down Expand Up @@ -964,6 +964,98 @@ def test_zone_basic(self):
self.verify_nftables(nftables_search, 'ip vyos_filter')
self.verify_nftables(nftables_search_v6, 'ip6 vyos_filter')

def test_zone_with_vrf(self):
self.cli_set(['firewall', 'ipv4', 'name', 'ZONE1-to-LOCAL', 'default-action', 'accept'])
self.cli_set(['firewall', 'ipv4', 'name', 'ZONE2_to_ZONE1', 'default-action', 'continue'])
self.cli_set(['firewall', 'ipv6', 'name', 'LOCAL_to_ZONE2_v6', 'default-action', 'drop'])
self.cli_set(['firewall', 'zone', 'LOCAL', 'from', 'ZONE1', 'firewall', 'name', 'ZONE1-to-LOCAL'])
self.cli_set(['firewall', 'zone', 'LOCAL', 'local-zone'])
self.cli_set(['firewall', 'zone', 'ZONE1', 'from', 'ZONE2', 'firewall', 'name', 'ZONE2_to_ZONE1'])
self.cli_set(['firewall', 'zone', 'ZONE1', 'member', 'interface', 'eth1'])
self.cli_set(['firewall', 'zone', 'ZONE1', 'member', 'interface', 'eth2'])
self.cli_set(['firewall', 'zone', 'ZONE1', 'member', 'vrf', 'VRF-1'])
self.cli_set(['firewall', 'zone', 'ZONE2', 'from', 'LOCAL', 'firewall', 'ipv6-name', 'LOCAL_to_ZONE2_v6'])
self.cli_set(['firewall', 'zone', 'ZONE2', 'member', 'interface', 'vtun66'])
self.cli_set(['firewall', 'zone', 'ZONE2', 'member', 'vrf', 'VRF-2'])

self.cli_set(['vrf', 'name', 'VRF-1', 'table', '101'])
self.cli_set(['vrf', 'name', 'VRF-2', 'table', '102'])
self.cli_set(['interfaces', 'ethernet', 'eth0', 'vrf', 'VRF-1'])
self.cli_set(['interfaces', 'vti', 'vti1', 'vrf', 'VRF-2'])

self.cli_commit()

nftables_search = [
['chain NAME_ZONE1-to-LOCAL'],
['counter', 'accept', 'comment "NAM-ZONE1-to-LOCAL default-action accept"'],
['chain NAME_ZONE2_to_ZONE1'],
['counter', 'continue', 'comment "NAM-ZONE2_to_ZONE1 default-action continue"'],
['chain VYOS_ZONE_FORWARD'],
['type filter hook forward priority filter + 1'],
['oifname { "eth1", "eth2" }', 'counter packets', 'jump VZONE_ZONE1'],
['oifname "eth0"', 'counter packets', 'jump VZONE_ZONE1'],
['oifname "vtun66"', 'counter packets', 'jump VZONE_ZONE2'],
['oifname "vti1"', 'counter packets', 'jump VZONE_ZONE2'],
['chain VYOS_ZONE_LOCAL'],
['type filter hook input priority filter + 1'],
['counter packets', 'jump VZONE_LOCAL_IN'],
['chain VYOS_ZONE_OUTPUT'],
['type filter hook output priority filter + 1'],
['counter packets', 'jump VZONE_LOCAL_OUT'],
['chain VZONE_LOCAL_IN'],
['iifname { "eth1", "eth2" }', 'counter packets', 'jump NAME_ZONE1-to-LOCAL'],
['iifname "VRF-1"', 'counter packets', 'jump NAME_ZONE1-to-LOCAL'],
['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
['chain VZONE_LOCAL_OUT'],
['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
['chain VZONE_ZONE1'],
['iifname { "eth1", "eth2" }', 'counter packets', 'return'],
['iifname "VRF-1"', 'counter packets', 'return'],
['iifname "vtun66"', 'counter packets', 'jump NAME_ZONE2_to_ZONE1'],
['iifname "vtun66"', 'counter packets', 'return'],
['iifname "VRF-2"', 'counter packets', 'jump NAME_ZONE2_to_ZONE1'],
['iifname "VRF-2"', 'counter packets', 'return'],
['counter packets', 'drop', 'comment "zone_ZONE1 default-action drop"'],
['chain VZONE_ZONE2'],
['iifname "vtun66"', 'counter packets', 'return'],
['iifname "VRF-2"', 'counter packets', 'return'],
['counter packets', 'drop', 'comment "zone_ZONE2 default-action drop"']
]

nftables_search_v6 = [
['chain NAME6_LOCAL_to_ZONE2_v6'],
['counter', 'drop', 'comment "NAM-LOCAL_to_ZONE2_v6 default-action drop"'],
['chain VYOS_ZONE_FORWARD'],
['type filter hook forward priority filter + 1'],
['oifname { "eth1", "eth2" }', 'counter packets', 'jump VZONE_ZONE1'],
['oifname "eth0"', 'counter packets', 'jump VZONE_ZONE1'],
['oifname "vtun66"', 'counter packets', 'jump VZONE_ZONE2'],
['oifname "vti1"', 'counter packets', 'jump VZONE_ZONE2'],
['chain VYOS_ZONE_LOCAL'],
['type filter hook input priority filter + 1'],
['counter packets', 'jump VZONE_LOCAL_IN'],
['chain VYOS_ZONE_OUTPUT'],
['type filter hook output priority filter + 1'],
['counter packets', 'jump VZONE_LOCAL_OUT'],
['chain VZONE_LOCAL_IN'],
['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
['chain VZONE_LOCAL_OUT'],
['oifname "vtun66"', 'counter packets', 'jump NAME6_LOCAL_to_ZONE2_v6'],
['oifname "vti1"', 'counter packets', 'jump NAME6_LOCAL_to_ZONE2_v6'],
['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
['chain VZONE_ZONE1'],
['iifname { "eth1", "eth2" }', 'counter packets', 'return'],
['iifname "VRF-1"', 'counter packets', 'return'],
['counter packets', 'drop', 'comment "zone_ZONE1 default-action drop"'],
['chain VZONE_ZONE2'],
['iifname "vtun66"', 'counter packets', 'return'],
['iifname "VRF-2"', 'counter packets', 'return'],
['counter packets', 'drop', 'comment "zone_ZONE2 default-action drop"']
]

self.verify_nftables(nftables_search, 'ip vyos_filter')
self.verify_nftables(nftables_search_v6, 'ip6 vyos_filter')

def test_flow_offload(self):
self.cli_set(['interfaces', 'ethernet', 'eth0', 'vif', '10'])
self.cli_set(['firewall', 'flowtable', 'smoketest', 'interface', 'eth0.10'])
Expand Down
Loading
Loading