Skip to content

Commit 1fe233b

Browse files
committed
firewall: T8761: Reintroduce VRF-interface names in generated firewall config, aswell as dependents
1 parent 6fa4967 commit 1fe233b

22 files changed

Lines changed: 268 additions & 40 deletions

data/config-mode-dependencies/vyos-1x.json

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,72 @@
99
},
1010
"interfaces_bonding": {
1111
"ethernet": ["interfaces_ethernet"],
12-
"static_arp": ["protocols_static_arp"]
12+
"static_arp": ["protocols_static_arp"],
13+
"firewall": ["firewall"]
1314
},
1415
"interfaces_bridge": {
1516
"vxlan": ["interfaces_vxlan"],
1617
"wlan": ["interfaces_wireless"],
17-
"static_arp": ["protocols_static_arp"]
18+
"static_arp": ["protocols_static_arp"],
19+
"firewall": ["firewall"]
20+
},
21+
"interfaces_dummy": {
22+
"firewall": ["firewall"]
1823
},
1924
"interfaces_ethernet": {
20-
"static_arp": ["protocols_static_arp"]
25+
"static_arp": ["protocols_static_arp"],
26+
"firewall": ["firewall"]
2127
},
2228
"interfaces_geneve": {
23-
"static_arp": ["protocols_static_arp"]
29+
"static_arp": ["protocols_static_arp"],
30+
"firewall": ["firewall"]
2431
},
2532
"interfaces_l2tpv3": {
26-
"static_arp": ["protocols_static_arp"]
33+
"static_arp": ["protocols_static_arp"],
34+
"firewall": ["firewall"]
2735
},
2836
"interfaces_macsec": {
29-
"static_arp": ["protocols_static_arp"]
37+
"static_arp": ["protocols_static_arp"],
38+
"firewall": ["firewall"]
39+
},
40+
"interfaces_openvpn": {
41+
"firewall": ["firewall"]
42+
},
43+
"interfaces_pppoe": {
44+
"firewall": ["firewall"]
3045
},
3146
"interfaces_pseudo_ethernet": {
32-
"static_arp": ["protocols_static_arp"]
47+
"static_arp": ["protocols_static_arp"],
48+
"firewall": ["firewall"]
49+
},
50+
"interfaces_sstpc": {
51+
"firewall": ["firewall"]
52+
},
53+
"interfaces_tunnel": {
54+
"firewall": ["firewall"]
3355
},
3456
"interfaces_virtual_ethernet": {
35-
"static_arp": ["protocols_static_arp"]
57+
"static_arp": ["protocols_static_arp"],
58+
"firewall": ["firewall"]
59+
},
60+
"interfaces_vti": {
61+
"firewall": ["firewall"]
3662
},
3763
"interfaces_vxlan": {
38-
"static_arp": ["protocols_static_arp"]
64+
"static_arp": ["protocols_static_arp"],
65+
"firewall": ["firewall"]
3966
},
4067
"interfaces_wireless": {
41-
"static_arp": ["protocols_static_arp"]
68+
"static_arp": ["protocols_static_arp"],
69+
"firewall": ["firewall"]
4270
},
4371
"interfaces_wwan": {
44-
"static_arp": ["protocols_static_arp"]
72+
"static_arp": ["protocols_static_arp"],
73+
"firewall": ["firewall"]
4574
},
4675
"interfaces_wireguard": {
47-
"vxlan": ["interfaces_vxlan"]
76+
"vxlan": ["interfaces_vxlan"],
77+
"firewall": ["firewall"]
4878
},
4979
"load_balancing_wan": {
5080
"conntrack": ["system_conntrack"]

data/templates/firewall/nftables-zone.j2

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,14 @@
99
{% for zone_name, zone_conf in zone.items() %}
1010
{% if 'local_zone' not in zone_conf %}
1111
{% if 'interface' in zone_conf.member %}
12-
oifname { {{ zone_conf.member.interface | quoted_join(',') }} } counter jump VZONE_{{ zone_name }}
12+
oifname { {{ zone_conf.member.interface | quoted_join(",") }} } counter jump VZONE_{{ zone_name }}
1313
{% endif %}
1414
{% if 'vrf' in zone_conf.member %}
15+
{% for vrf_name in zone_conf.member.vrf %}
16+
{% if zone_conf['vrf_interfaces'][vrf_name] | length > 0 %}
17+
oifname { {{ zone_conf['vrf_interfaces'][vrf_name] | quoted_join(",") }} } counter jump VZONE_{{ zone_name }}
18+
{% endif %}
19+
{% endfor %}
1520
oifname { {{ zone_conf.member.vrf | quoted_join(",") }} } counter jump VZONE_{{ zone_name }}
1621
{% endif %}
1722
{% endif %}
@@ -71,6 +76,12 @@
7176
oifname { {{ zone[from_zone].member.interface | quoted_join(",") }} } counter return
7277
{% endif %}
7378
{% if 'vrf' in zone[from_zone].member %}
79+
{% for vrf_name in zone[from_zone].member.vrf %}
80+
{% if zone[from_zone]['vrf_interfaces'][vrf_name] | length > 0 %}
81+
oifname { {{ zone[from_zone]['vrf_interfaces'][vrf_name] | quoted_join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
82+
oifname { {{ zone[from_zone]['vrf_interfaces'][vrf_name] | quoted_join(",") }} } counter return
83+
{% endif %}
84+
{% endfor %}
7485
oifname { {{ zone[from_zone].member.vrf | quoted_join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
7586
oifname { {{ zone[from_zone].member.vrf | quoted_join(",") }} } counter return
7687
{% endif %}
@@ -84,9 +95,13 @@
8495
{% endif %}
8596
{% if 'vrf' in zone[from_zone].member %}
8697
{% for vrf_name in zone[from_zone].member.vrf %}
87-
oifname { "{{ zone[from_zone]['vrf_interfaces'][vrf_name] }}" } counter jump NAME{{ suffix }}_{{ from_conf[fw_name] }}
88-
oifname { "{{ zone[from_zone]['vrf_interfaces'][vrf_name] }}" } counter return
98+
{% if zone[from_zone]['vrf_interfaces'][vrf_name] | length > 0 %}
99+
oifname { {{ zone[from_zone]['vrf_interfaces'][vrf_name] | quoted_join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf[fw_name] }}
100+
oifname { {{ zone[from_zone]['vrf_interfaces'][vrf_name] | quoted_join(",") }} } counter return
101+
{% endif %}
89102
{% endfor %}
103+
oifname { {{ zone[from_zone].member.vrf | quoted_join(",") }} } counter jump NAME{{ suffix }}_{{ from_conf.firewall[fw_name] }}
104+
oifname { {{ zone[from_zone].member.vrf | quoted_join(",") }} } counter return
90105
{% endif %}
91106
{% endfor %}
92107
{% endif %}

smoketest/scripts/cli/test_firewall.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1143,8 +1143,13 @@ def test_zone_with_vrf(self):
11431143
self.cli_set(['vrf', 'name', 'VRF-1', 'table', '101'])
11441144
self.cli_set(['vrf', 'name', 'VRF-2', 'table', '102'])
11451145
self.cli_set(['interfaces', 'ethernet', 'eth0', 'vrf', 'VRF-1'])
1146-
self.cli_set(['interfaces', 'vti', 'vti1', 'vrf', 'VRF-2'])
1146+
self.cli_set(['interfaces', 'ethernet', 'eth0', 'vif', '10', 'vrf', 'VRF-1'])
1147+
self.cli_set(['interfaces', 'ethernet', 'eth3', 'vif-s', '10', 'vrf', 'VRF-1'])
1148+
self.cli_set(['interfaces', 'ethernet', 'eth3', 'vif-s', '20', 'vif-c', '30', 'vrf', 'VRF-1'])
1149+
self.cli_set(['interfaces', 'vti', 'vti1', 'vrf', 'VRF-1'])
1150+
self.cli_set(['interfaces', 'vti', 'vti2', 'vrf', 'VRF-2'])
11471151

1152+
# commit the config
11481153
self.cli_commit()
11491154

11501155
nftables_search = [
@@ -1155,8 +1160,10 @@ def test_zone_with_vrf(self):
11551160
['chain VYOS_ZONE_FORWARD'],
11561161
['type filter hook forward priority filter + 1'],
11571162
['oifname { "eth1", "eth2" }', 'counter packets', 'jump VZONE_ZONE1'],
1163+
['oifname { "eth0", "eth0.10", "eth3.10", "eth3.20.30", "vti1" }', 'counter packets', 'jump VZONE_ZONE1'],
11581164
['oifname "VRF-1"', 'counter packets', 'jump VZONE_ZONE1'],
11591165
['oifname "vtun66"', 'counter packets', 'jump VZONE_ZONE2'],
1166+
['oifname "vti2"', 'counter packets', 'jump VZONE_ZONE2'],
11601167
['oifname "VRF-2"', 'counter packets', 'jump VZONE_ZONE2'],
11611168
['chain VYOS_ZONE_LOCAL'],
11621169
['type filter hook input priority filter + 1'],
@@ -1190,8 +1197,10 @@ def test_zone_with_vrf(self):
11901197
['chain VYOS_ZONE_FORWARD'],
11911198
['type filter hook forward priority filter + 1'],
11921199
['oifname { "eth1", "eth2" }', 'counter packets', 'jump VZONE_ZONE1'],
1200+
['oifname { "eth0", "eth0.10", "eth3.10", "eth3.20.30", "vti1" }', 'counter packets', 'jump VZONE_ZONE1'],
11931201
['oifname "VRF-1"', 'counter packets', 'jump VZONE_ZONE1'],
11941202
['oifname "vtun66"', 'counter packets', 'jump VZONE_ZONE2'],
1203+
['oifname "vti2"', 'counter packets', 'jump VZONE_ZONE2'],
11951204
['oifname "VRF-2"', 'counter packets', 'jump VZONE_ZONE2'],
11961205
['chain VYOS_ZONE_LOCAL'],
11971206
['type filter hook input priority filter + 1'],
@@ -1203,6 +1212,7 @@ def test_zone_with_vrf(self):
12031212
['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
12041213
['chain VZONE_LOCAL_OUT'],
12051214
['oifname "vtun66"', 'counter packets', 'jump NAME6_LOCAL_to_ZONE2_v6'],
1215+
['oifname "vti2"', 'counter packets', 'jump NAME6_LOCAL_to_ZONE2_v6'],
12061216
['oifname "VRF-2"', 'counter packets', 'jump NAME6_LOCAL_to_ZONE2_v6'],
12071217
['counter packets', 'drop', 'comment "zone_LOCAL default-action drop"'],
12081218
['chain VZONE_ZONE1'],
@@ -1218,6 +1228,29 @@ def test_zone_with_vrf(self):
12181228
self.verify_nftables(nftables_search, 'ip vyos_filter')
12191229
self.verify_nftables(nftables_search_v6, 'ip6 vyos_filter')
12201230

1231+
# change memberships in vrf plus delete and add subifs
1232+
self.cli_set(['interfaces', 'vti', 'vti1', 'vrf', 'VRF-2'])
1233+
self.cli_delete(['interfaces', 'ethernet', 'eth0', 'vif', '10'])
1234+
self.cli_delete(['interfaces', 'ethernet', 'eth3', 'vif-s', '10'])
1235+
self.cli_delete(['interfaces', 'ethernet', 'eth3', 'vif-s', '20', 'vif-c', '30'])
1236+
self.cli_set(['interfaces', 'ethernet', 'eth0', 'vif', '20', 'vrf', 'VRF-1'])
1237+
self.cli_set(['interfaces', 'ethernet', 'eth3', 'vif-s', '20', 'vrf', 'VRF-1'])
1238+
self.cli_set(['interfaces', 'ethernet', 'eth3', 'vif-s', '20', 'vif-c', '40', 'vrf', 'VRF-1'])
1239+
self.cli_commit()
1240+
1241+
# make som verifications to ensure the interface swapped vrf
1242+
nftables_search = [
1243+
['oifname { "eth0", "eth0.20", "eth3.20", "eth3.20.40" }', 'counter packets', 'jump VZONE_ZONE1'],
1244+
['oifname { "vti1", "vti2" }', 'counter packets', 'jump VZONE_ZONE2'],
1245+
]
1246+
1247+
nftables_search_v6 = [
1248+
['oifname { "eth0", "eth0.20", "eth3.20", "eth3.20.40" }', 'counter packets', 'jump VZONE_ZONE1'],
1249+
['oifname { "vti1", "vti2" }', 'counter packets', 'jump VZONE_ZONE2'],
1250+
]
1251+
self.verify_nftables(nftables_search, 'ip vyos_filter')
1252+
self.verify_nftables(nftables_search_v6, 'ip6 vyos_filter')
1253+
12211254
def test_zone_without_member(self):
12221255
self.cli_set(['firewall', 'zone', 'wan', 'default-action', 'drop'])
12231256
error_message = 'Zone "wan" has no interfaces and is not the local zone'

src/conf_mode/firewall.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ def get_config(config=None):
138138
if 'vrf' in local_zone_member:
139139
local_zone_conf['vrf_interfaces'] = {}
140140
for vrf_name in local_zone_member['vrf']:
141-
local_zone_conf['vrf_interfaces'][vrf_name] = ','.join(get_vrf_members(vrf_name))
141+
local_zone_conf['vrf_interfaces'][vrf_name] = get_vrf_members(
142+
vrf_name
143+
)
142144
continue
143145

144146
local_zone_conf['from_local'] = {}

src/conf_mode/interfaces_bonding.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ def get_config(config=None):
171171
if 'static_arp' in bond:
172172
set_dependents('static_arp', conf)
173173

174+
# Check vrf membership, to ensure firewall is updated
175+
if is_node_changed(conf, base + [ifname, 'vrf']):
176+
bond.update({'vrf_changed': {}})
177+
set_dependents('firewall', conf)
178+
174179
bond['vpp_ifaces'] = cli_ifaces_list(conf)
175180

176181
return bond
@@ -298,7 +303,11 @@ def apply(bond):
298303
else:
299304
b.update(bond)
300305

301-
if dict_search('member.interface_remove', bond) or 'static_arp' in bond:
306+
if (
307+
dict_search('member.interface_remove', bond)
308+
or 'static_arp' in bond
309+
or 'vrf_changed' in bond
310+
):
302311
try:
303312
call_dependents()
304313
except ConfigError:

src/conf_mode/interfaces_bridge.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from vyos.config import Config
2020
from vyos.configdict import get_interface_dict
21+
from vyos.configdict import is_node_changed
2122
from vyos.configdict import node_changed
2223
from vyos.configdict import is_member
2324
from vyos.configdict import is_source_interface
@@ -129,6 +130,11 @@ def get_config(config=None):
129130
if 'static_arp' in bridge:
130131
set_dependents('static_arp', conf)
131132

133+
# Check vrf membership, to ensure firewall is updated
134+
if is_node_changed(conf, base + [ifname, 'vrf']):
135+
bridge.update({'vrf_changed': {}})
136+
set_dependents('firewall', conf)
137+
132138
bridge['vpp_ifaces'] = cli_ifaces_list(conf)
133139

134140
return bridge
@@ -233,7 +239,7 @@ def apply(bridge):
233239
if iface.startswith(('vxlan', 'wlan')) and interface_exists(iface)
234240
]
235241

236-
if interfaces_need_update or 'static_arp' in bridge:
242+
if interfaces_need_update or 'static_arp' in bridge or 'vrf_changed' in bridge:
237243
try:
238244
call_dependents()
239245
except ConfigError:

src/conf_mode/interfaces_dummy.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@
1818

1919
from vyos.config import Config
2020
from vyos.configdict import get_interface_dict
21+
from vyos.configdict import is_node_changed
22+
from vyos.configdep import set_dependents
23+
from vyos.configdep import call_dependents
2124
from vyos.configverify import verify_vrf
2225
from vyos.configverify import verify_address
2326
from vyos.configverify import verify_bridge_delete
@@ -37,7 +40,12 @@ def get_config(config=None):
3740
else:
3841
conf = Config()
3942
base = ['interfaces', 'dummy']
40-
_, dummy = get_interface_dict(conf, base)
43+
ifname, dummy = get_interface_dict(conf, base)
44+
45+
# Check vrf membership, to ensure firewall is updated
46+
if is_node_changed(conf, base + [ifname, 'vrf']):
47+
set_dependents('firewall', conf)
48+
4149
return dummy
4250

4351
def verify(dummy):
@@ -63,6 +71,9 @@ def apply(dummy):
6371
else:
6472
d.update(dummy)
6573

74+
# run the dependents
75+
call_dependents()
76+
6677
return None
6778

6879
if __name__ == '__main__':

src/conf_mode/interfaces_ethernet.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,22 @@ def get_config(config=None):
195195
if 'static_arp' in ethernet:
196196
set_dependents('static_arp', conf)
197197

198+
# Check vrf membership, to ensure firewall is updated
199+
# Parent interface
200+
if is_node_changed(conf, base + [ifname, 'vrf']):
201+
set_dependents('firewall', conf)
202+
# vif interface
203+
for vif in conf.list_nodes(base + [ifname, 'vif']):
204+
if is_node_changed(conf, base + [ifname, 'vif', vif, 'vrf']):
205+
set_dependents('firewall', conf)
206+
# q-in-q interface
207+
for vif_s in conf.list_nodes(base + [ifname, 'vif-s']):
208+
if is_node_changed(conf, base + [ifname, 'vif-s', vif_s, 'vrf']):
209+
set_dependents('firewall', conf)
210+
for vif_c in conf.list_nodes(base + [ifname, 'vif-s', vif_s, 'vif-c']):
211+
if is_node_changed(conf, base + [ifname, 'vif-s', vif_s, 'vif-c', vif_c, 'vrf']):
212+
set_dependents('firewall', conf)
213+
198214
return ethernet
199215

200216
def verify_speed_duplex(ethernet: dict, ethtool: Ethtool):
@@ -441,8 +457,9 @@ def apply(ethernet):
441457
e.remove()
442458
else:
443459
e.update(ethernet)
444-
if 'static_arp' in ethernet:
445-
call_dependents()
460+
461+
# run the dependents
462+
call_dependents()
446463

447464
vpp_iface_config = dict_search(f'vpp.settings.interface.{ifname}', ethernet)
448465
if vpp_iface_config is not None and is_systemd_service_running('vpp.service'):

src/conf_mode/interfaces_geneve.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,10 @@ def get_config(config=None):
5757
if 'static_arp' in geneve:
5858
set_dependents('static_arp', conf)
5959

60+
# Check vrf membership, to ensure firewall is updated
61+
if is_node_changed(conf, base + [ifname, 'vrf']):
62+
set_dependents('firewall', conf)
63+
6064
return geneve
6165

6266
def verify(geneve):
@@ -96,8 +100,8 @@ def apply(geneve):
96100
g = GeneveIf(**geneve)
97101
g.update(geneve)
98102

99-
if 'static_arp' in geneve:
100-
call_dependents()
103+
# run the dependents
104+
call_dependents()
101105

102106
return None
103107

src/conf_mode/interfaces_l2tpv3.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from vyos.configdep import set_dependents
2121
from vyos.configdep import call_dependents
2222
from vyos.configdict import get_interface_dict
23+
from vyos.configdict import is_node_changed
2324
from vyos.configdict import leaf_node_changed
2425
from vyos.configverify import verify_address
2526
from vyos.configverify import verify_bridge_delete
@@ -62,6 +63,10 @@ def get_config(config=None):
6263
if 'static_arp' in l2tpv3:
6364
set_dependents('static_arp', conf)
6465

66+
# Check vrf membership, to ensure firewall is updated
67+
if is_node_changed(conf, base + [ifname, 'vrf']):
68+
set_dependents('firewall', conf)
69+
6570
return l2tpv3
6671

6772
def verify(l2tpv3):
@@ -106,8 +111,8 @@ def apply(l2tpv3):
106111
l = L2TPv3If(**l2tpv3)
107112
l.update(l2tpv3)
108113

109-
if 'static_arp' in l2tpv3:
110-
call_dependents()
114+
# run the dependents
115+
call_dependents()
111116

112117
return None
113118

0 commit comments

Comments
 (0)