diff options
-rw-r--r-- | interface-definitions/include/interface/vif-s.xml.i | 22 | ||||
-rw-r--r-- | interface-definitions/include/interface/vlan-protocol.xml.i | 23 | ||||
-rw-r--r-- | interface-definitions/interfaces_bridge.xml.in | 4 | ||||
-rw-r--r-- | python/vyos/ifconfig/bridge.py | 34 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_firewall.py | 31 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_interfaces_bridge.py | 18 | ||||
-rwxr-xr-x | src/conf_mode/system_conntrack.py | 16 | ||||
-rwxr-xr-x | src/migration-scripts/policy/3-to-4 | 8 |
8 files changed, 110 insertions, 46 deletions
diff --git a/interface-definitions/include/interface/vif-s.xml.i b/interface-definitions/include/interface/vif-s.xml.i index fdd62b63d..02e7ab057 100644 --- a/interface-definitions/include/interface/vif-s.xml.i +++ b/interface-definitions/include/interface/vif-s.xml.i @@ -18,27 +18,7 @@ #include <include/interface/dhcpv6-options.xml.i> #include <include/interface/disable-link-detect.xml.i> #include <include/interface/disable.xml.i> - <leafNode name="protocol"> - <properties> - <help>Protocol used for service VLAN (default: 802.1ad)</help> - <completionHelp> - <list>802.1ad 802.1q</list> - </completionHelp> - <valueHelp> - <format>802.1ad</format> - <description>Provider Bridging (IEEE 802.1ad, Q-inQ), ethertype 0x88a8</description> - </valueHelp> - <valueHelp> - <format>802.1q</format> - <description>VLAN-tagged frame (IEEE 802.1q), ethertype 0x8100</description> - </valueHelp> - <constraint> - <regex>(802.1q|802.1ad)</regex> - </constraint> - <constraintErrorMessage>Ethertype must be 802.1ad or 802.1q</constraintErrorMessage> - </properties> - <defaultValue>802.1ad</defaultValue> - </leafNode> + #include <include/interface/vlan-protocol.xml.i> #include <include/interface/ipv4-options.xml.i> #include <include/interface/ipv6-options.xml.i> #include <include/interface/mac.xml.i> diff --git a/interface-definitions/include/interface/vlan-protocol.xml.i b/interface-definitions/include/interface/vlan-protocol.xml.i new file mode 100644 index 000000000..2fe8d65d7 --- /dev/null +++ b/interface-definitions/include/interface/vlan-protocol.xml.i @@ -0,0 +1,23 @@ +<!-- include start from interface/vif.xml.i --> +<leafNode name="protocol"> + <properties> + <help>Protocol used for service VLAN (default: 802.1ad)</help> + <completionHelp> + <list>802.1ad 802.1q</list> + </completionHelp> + <valueHelp> + <format>802.1ad</format> + <description>Provider Bridging (IEEE 802.1ad, Q-inQ), ethertype 0x88a8</description> + </valueHelp> + <valueHelp> + <format>802.1q</format> + <description>VLAN-tagged frame (IEEE 802.1q), ethertype 0x8100</description> + </valueHelp> + <constraint> + <regex>(802.1q|802.1ad)</regex> + </constraint> + <constraintErrorMessage>Ethertype must be 802.1ad or 802.1q</constraintErrorMessage> + </properties> + <defaultValue>802.1ad</defaultValue> +</leafNode> +<!-- include end --> diff --git a/interface-definitions/interfaces_bridge.xml.in b/interface-definitions/interfaces_bridge.xml.in index d4d277cfc..7fb5f121a 100644 --- a/interface-definitions/interfaces_bridge.xml.in +++ b/interface-definitions/interfaces_bridge.xml.in @@ -98,6 +98,10 @@ <valueless/> </properties> </leafNode> + #include <include/interface/vlan-protocol.xml.i> + <leafNode name="protocol"> + <defaultValue>802.1q</defaultValue> + </leafNode> <leafNode name="max-age"> <properties> <help>Interval at which neighbor bridges are removed</help> diff --git a/python/vyos/ifconfig/bridge.py b/python/vyos/ifconfig/bridge.py index b29e71394..7936e3da5 100644 --- a/python/vyos/ifconfig/bridge.py +++ b/python/vyos/ifconfig/bridge.py @@ -1,4 +1,4 @@ -# Copyright 2019-2021 VyOS maintainers and contributors <maintainers@vyos.io> +# Copyright 2019-2024 VyOS maintainers and contributors <maintainers@vyos.io> # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -14,12 +14,11 @@ # License along with this library. If not, see <http://www.gnu.org/licenses/>. from netifaces import interfaces -import json from vyos.ifconfig.interface import Interface from vyos.utils.assertion import assert_boolean +from vyos.utils.assertion import assert_list from vyos.utils.assertion import assert_positive -from vyos.utils.process import cmd from vyos.utils.dict import dict_search from vyos.configdict import get_vlan_ids from vyos.configdict import list_diff @@ -86,6 +85,10 @@ class BridgeIf(Interface): 'validate': assert_boolean, 'location': '/sys/class/net/{ifname}/bridge/vlan_filtering', }, + 'vlan_protocol': { + 'validate': lambda v: assert_list(v, ['0x88a8', '0x8100']), + 'location': '/sys/class/net/{ifname}/bridge/vlan_protocol', + }, 'multicast_querier': { 'validate': assert_boolean, 'location': '/sys/class/net/{ifname}/bridge/multicast_querier', @@ -248,6 +251,26 @@ class BridgeIf(Interface): """ return self.set_interface('del_port', interface) + def set_vlan_protocol(self, protocol): + """ + Set protocol used for VLAN filtering. + The valid values are 0x8100(802.1q) or 0x88A8(802.1ad). + + Example: + >>> from vyos.ifconfig import Interface + >>> BridgeIf('br0').del_port('eth1') + """ + + if protocol not in ['802.1q', '802.1ad']: + raise ValueError() + + map = { + '802.1ad': '0x88a8', + '802.1q' : '0x8100' + } + + return self.set_interface('vlan_protocol', map[protocol]) + def update(self, config): """ General helper function which works on a dictionary retrived by get_config_dict(). It's main intention is to consolidate the scattered @@ -294,10 +317,13 @@ class BridgeIf(Interface): if member in interfaces(): self.del_port(member) - # enable/disable Vlan Filter + # enable/disable VLAN Filter tmp = '1' if 'enable_vlan' in config else '0' self.set_vlan_filter(tmp) + tmp = config.get('protocol') + self.set_vlan_protocol(tmp) + # add VLAN interfaces to local 'parent' bridge to allow forwarding if 'enable_vlan' in config: for vlan in config.get('vif_remove', {}): diff --git a/smoketest/scripts/cli/test_firewall.py b/smoketest/scripts/cli/test_firewall.py index 9e8473fa4..fe6977252 100755 --- a/smoketest/scripts/cli/test_firewall.py +++ b/smoketest/scripts/cli/test_firewall.py @@ -598,14 +598,30 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): self.verify_nftables(nftables_search, 'ip6 vyos_filter') - def test_ipv4_state_and_status_rules(self): - name = 'smoketest-state' - interface = 'eth0' - + def test_ipv4_global_state(self): self.cli_set(['firewall', 'global-options', 'state-policy', 'established', 'action', 'accept']) self.cli_set(['firewall', 'global-options', 'state-policy', 'related', 'action', 'accept']) self.cli_set(['firewall', 'global-options', 'state-policy', 'invalid', 'action', 'drop']) + self.cli_commit() + + nftables_search = [ + ['jump VYOS_STATE_POLICY'], + ['chain VYOS_STATE_POLICY'], + ['ct state established', 'accept'], + ['ct state invalid', 'drop'], + ['ct state related', 'accept'] + ] + + self.verify_nftables(nftables_search, 'ip vyos_filter') + + # Check conntrack is enabled from state-policy + self.verify_nftables_chain([['accept']], 'ip vyos_conntrack', 'FW_CONNTRACK') + self.verify_nftables_chain([['accept']], 'ip6 vyos_conntrack', 'FW_CONNTRACK') + + def test_ipv4_state_and_status_rules(self): + name = 'smoketest-state' + self.cli_set(['firewall', 'ipv4', 'name', name, 'default-action', 'drop']) self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'action', 'accept']) self.cli_set(['firewall', 'ipv4', 'name', name, 'rule', '1', 'state', 'established']) @@ -632,12 +648,7 @@ class TestFirewall(VyOSUnitTestSHIM.TestCase): ['ct state new', 'ct status dnat', 'accept'], ['ct state { established, new }', 'ct status snat', 'accept'], ['ct state related', 'ct helper { "ftp", "pptp" }', 'accept'], - ['drop', f'comment "{name} default-action drop"'], - ['jump VYOS_STATE_POLICY'], - ['chain VYOS_STATE_POLICY'], - ['ct state established', 'accept'], - ['ct state invalid', 'drop'], - ['ct state related', 'accept'] + ['drop', f'comment "{name} default-action drop"'] ] self.verify_nftables(nftables_search, 'ip vyos_filter') diff --git a/smoketest/scripts/cli/test_interfaces_bridge.py b/smoketest/scripts/cli/test_interfaces_bridge.py index 3500e97d6..124c1fbcb 100755 --- a/smoketest/scripts/cli/test_interfaces_bridge.py +++ b/smoketest/scripts/cli/test_interfaces_bridge.py @@ -182,6 +182,10 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase): for interface in self._interfaces: cost = 1000 priority = 10 + + tmp = get_interface_config(interface) + self.assertEqual('802.1Q', tmp['linkinfo']['info_data']['vlan_protocol']) # default VLAN protocol + for member in self._members: tmp = get_interface_config(member) self.assertEqual(interface, tmp['master']) @@ -442,5 +446,19 @@ class BridgeInterfaceTest(BasicInterfaceTest.TestCase): self.cli_delete(['interfaces', 'tunnel', tunnel_if]) self.cli_delete(['interfaces', 'ethernet', 'eth0', 'address', eth0_addr]) + def test_bridge_vlan_protocol(self): + protocol = '802.1ad' + + # Add member interface to bridge and set VLAN filter + for interface in self._interfaces: + self.cli_set(self._base_path + [interface, 'protocol', protocol]) + + # commit config + self.cli_commit() + + for interface in self._interfaces: + tmp = get_interface_config(interface) + self.assertEqual(protocol, tmp['linkinfo']['info_data']['vlan_protocol']) + if __name__ == '__main__': unittest.main(verbosity=2) diff --git a/src/conf_mode/system_conntrack.py b/src/conf_mode/system_conntrack.py index a1472aaaa..3d42389f6 100755 --- a/src/conf_mode/system_conntrack.py +++ b/src/conf_mode/system_conntrack.py @@ -185,12 +185,16 @@ def generate(conntrack): conntrack['ipv4_firewall_action'] = 'return' conntrack['ipv6_firewall_action'] = 'return' - for rules, path in dict_search_recursive(conntrack['firewall'], 'rule'): - if any(('state' in rule_conf or 'connection_status' in rule_conf or 'offload_target' 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' + if dict_search_args(conntrack['firewall'], 'global_options', 'state_policy') != None: + 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 or 'offload_target' 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) diff --git a/src/migration-scripts/policy/3-to-4 b/src/migration-scripts/policy/3-to-4 index 1ebb248b0..476fa3af2 100755 --- a/src/migration-scripts/policy/3-to-4 +++ b/src/migration-scripts/policy/3-to-4 @@ -51,7 +51,7 @@ def community_migrate(config: ConfigTree, rule: list[str]) -> bool: :rtype: bool """ community_list = list((config.return_value(rule)).split(" ")) - + config.delete(rule) if 'none' in community_list: config.set(rule + ['none']) return False @@ -61,10 +61,8 @@ def community_migrate(config: ConfigTree, rule: list[str]) -> bool: community_action = 'add' community_list.remove('additive') for community in community_list: - if len(community): - config.set(rule + [community_action], value=community, - replace=False) - config.delete(rule) + config.set(rule + [community_action], value=community, + replace=False) if community_action == 'replace': return False else: |