From bb4427bfb4a8c03784dd6f097cbe521f561edaf4 Mon Sep 17 00:00:00 2001 From: Viacheslav Hletenko Date: Tue, 7 Jan 2025 21:54:47 +0000 Subject: Add vyos-vpp CLI and python3 modules --- src/conf_mode/vpp_interfaces_loopback.py | 153 +++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 src/conf_mode/vpp_interfaces_loopback.py (limited to 'src/conf_mode/vpp_interfaces_loopback.py') diff --git a/src/conf_mode/vpp_interfaces_loopback.py b/src/conf_mode/vpp_interfaces_loopback.py new file mode 100644 index 000000000..67fd049f0 --- /dev/null +++ b/src/conf_mode/vpp_interfaces_loopback.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2023 VyOS Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import os + +from vyos import ConfigError + +from vyos.config import Config +from vyos.configdict import leaf_node_changed +from vyos.configdep import set_dependents, call_dependents +from vyos.template import is_interface + +from vyos.vpp.interface import LoopbackInterface +from vyos.vpp.config_verify import ( + verify_vpp_remove_kernel_interface, + verify_vpp_change_kernel_interface, + verify_vpp_exists_kernel_interface, +) +from vyos.vpp.utils import cli_ifaces_lcp_kernel_list + + +def get_config(config=None, recursive_defaults=True) -> dict: + """Get Loopback interface configuration + + Args: + config (vyos.config.Config, optional): The VyOS configuration dictionary + recursive_defaults (bool, optional): Include recursive defaults + Returns: + dict: Loopback interface configuration + """ + if config: + conf = config + else: + conf = Config() + + base = ['vpp', 'interfaces', 'loopback'] + base_kernel_interfaces = ['vpp', 'kernel-interfaces'] + + ifname = os.environ['VYOS_TAGNODE_VALUE'] + + # Get config_dict with default values + config = conf.get_config_dict( + base + [ifname], + key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True, + with_defaults=True, + with_recursive_defaults=recursive_defaults, + ) + + # Get effective config as we need full dicitonary per interface delete + effective_config = conf.get_config_dict( + base + [ifname], + key_mangling=('-', '_'), + effective=True, + get_first_key=True, + no_tag_node_value_mangle=True, + ) + + if effective_config: + config.update({'effective': effective_config}) + + if not conf.exists(base + [ifname]): + config['remove'] = True + + # Get global 'vpp kernel-interfaces' for verify + config['vpp_kernel_interfaces'] = conf.get_config_dict( + base_kernel_interfaces, + key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True, + ) + + tmp = leaf_node_changed(conf, base + [ifname, 'kernel-interface']) + if tmp: + config['kernel_interface_removed'] = tmp + + # list of all kernel interfaces `vpp interface xxx kernel-interface xxx` + config['candidate_kernel_interfaces'] = cli_ifaces_lcp_kernel_list(conf) + + # Dependency + if effective_config.get('kernel_interface'): + if conf.exists(base + [ifname, 'kernel-interface']): + iface = config.get('kernel_interface') + if conf.exists(['vpp', 'kernel-interfaces', iface]): + set_dependents('vpp_kernel_interface', conf, iface) + + config['ifname'] = ifname + return config + + +def verify(config): + verify_vpp_remove_kernel_interface(config) + + if 'remove' in config: + return None + + verify_vpp_change_kernel_interface(config) + verify_vpp_exists_kernel_interface(config) + + +def generate(config): + pass + + +def apply(config): + ifname = config.get('ifname') + # Delete interface + if 'effective' in config: + i = LoopbackInterface(ifname) + i.delete() + + if 'remove' in config: + return None + + # Add interface + kernel_interface = config.get('kernel_interface', '') + i = LoopbackInterface(ifname, kernel_interface) + i.add() + + # Add kernel-interface (LCP) if interface is not exist + if 'kernel_interface' in config and not is_interface(kernel_interface): + i.kernel_add() + + call_dependents() + + return None + + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) -- cgit v1.2.3 From 26936a2f23a6187efb26a3adcf0f11bec6a4ddba Mon Sep 17 00:00:00 2001 From: Viacheslav Hletenko Date: Sat, 11 Jan 2025 15:00:44 +0000 Subject: Remove recursive_defaults from the get_config arg Do not use 'recursive_defaults' as argument of the funciton get_config() It cause vyos-1x/src/tests/test_configd_inspect.py signature checks fail AssertionError: 2 != 1 : 'vpp_interfaces_bonding.py': 'get_config' incorrect signature --- .../0001-Skip-unittest-during-build-XML.patch | 41 ---------------------- src/conf_mode/vpp_interfaces_bonding.py | 7 ++-- src/conf_mode/vpp_interfaces_bridge.py | 7 ++-- src/conf_mode/vpp_interfaces_ethernet.py | 7 ++-- src/conf_mode/vpp_interfaces_geneve.py | 6 ++-- src/conf_mode/vpp_interfaces_gre.py | 7 ++-- src/conf_mode/vpp_interfaces_ipip.py | 7 ++-- src/conf_mode/vpp_interfaces_loopback.py | 7 ++-- src/conf_mode/vpp_interfaces_vxlan.py | 7 ++-- src/conf_mode/vpp_interfaces_xconnect.py | 7 ++-- 10 files changed, 27 insertions(+), 76 deletions(-) delete mode 100644 patches/vyos-1x/0001-Skip-unittest-during-build-XML.patch (limited to 'src/conf_mode/vpp_interfaces_loopback.py') diff --git a/patches/vyos-1x/0001-Skip-unittest-during-build-XML.patch b/patches/vyos-1x/0001-Skip-unittest-during-build-XML.patch deleted file mode 100644 index 81fd3f07f..000000000 --- a/patches/vyos-1x/0001-Skip-unittest-during-build-XML.patch +++ /dev/null @@ -1,41 +0,0 @@ -From cb46d4d36f9bc0ac4e768a0d7d733a85b9c6a6ad Mon Sep 17 00:00:00 2001 -From: Viacheslav Hletenko -Date: Sat, 11 Jan 2025 14:18:35 +0000 -Subject: [PATCH] Skip unittest during build XML - ---- - src/tests/test_configd_inspect.py | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/src/tests/test_configd_inspect.py b/src/tests/test_configd_inspect.py -index a0470221d..26c85ca1c 100644 ---- a/src/tests/test_configd_inspect.py -+++ b/src/tests/test_configd_inspect.py -@@ -14,6 +14,7 @@ - - import ast - import json -+import unittest - - from unittest import TestCase - -@@ -94,7 +95,7 @@ def get_func_config_instance(self): - return self.func_config_instance - - --class TestConfigdInspect(TestCase): -+class TestConfigdInspect(unittest.TestCase): - def setUp(self): - self.ast_list = [] - -@@ -108,6 +109,7 @@ def setUp(self): - s_tree = ast.parse(s_str) - self.ast_list.append((s, s_tree)) - -+ @unittest.skip("Skipping test_config_modification") - def test_signatures(self): - for s, t in self.ast_list: - visitor = FunctionSig() --- -2.39.5 - diff --git a/src/conf_mode/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index 9b057f992..135be5c04 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -58,12 +58,11 @@ def _get_bond_lb(lb_name: str) -> int: return lb_mapping.get(lb_name, 5) -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get Bonding interface configuration Args: config (vyos.config.Config, optional): The VyOS configuration dictionary - recursive_defaults (bool, optional): Include recursive defaults Returns: dict: Bonding interface configuration """ @@ -84,7 +83,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get effective config as we need full dicitonary per interface delete diff --git a/src/conf_mode/vpp_interfaces_bridge.py b/src/conf_mode/vpp_interfaces_bridge.py index c76d88480..e7a2427f9 100644 --- a/src/conf_mode/vpp_interfaces_bridge.py +++ b/src/conf_mode/vpp_interfaces_bridge.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2024 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,12 +25,11 @@ from vyos.vpp.interface import BridgeInterface from vyos.vpp.utils import iftunnel_transform -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get Bridge interface configuration Args: config (vyos.config.Config, optional): The VyOS configuration dictionary - recursive_defaults (bool, optional): Include recursive defaults Returns: dict: Bridge interface configuration """ @@ -51,7 +50,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get effective config as we need full dicitonary per interface delete diff --git a/src/conf_mode/vpp_interfaces_ethernet.py b/src/conf_mode/vpp_interfaces_ethernet.py index d82acb891..f56cadc3e 100644 --- a/src/conf_mode/vpp_interfaces_ethernet.py +++ b/src/conf_mode/vpp_interfaces_ethernet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -24,12 +24,11 @@ from vyos import ConfigError from vyos.vpp.config_verify import verify_vpp_remove_xconnect_interface -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get Ethernet interface configuration Args: config (vyos.config.Config, optional): The VyOS configuration dictionary - recursive_defaults (bool, optional): Include recursive defaults Returns: dict: Ethernet interface configuration """ @@ -68,7 +67,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get global 'vpp interfaces xconnect' diff --git a/src/conf_mode/vpp_interfaces_geneve.py b/src/conf_mode/vpp_interfaces_geneve.py index a40cc9c84..a7e7ae8e5 100644 --- a/src/conf_mode/vpp_interfaces_geneve.py +++ b/src/conf_mode/vpp_interfaces_geneve.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -36,7 +36,7 @@ from vyos.vpp.config_verify import ( from vyos.vpp.utils import cli_ifaces_lcp_kernel_list -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get Geneve interface configuration Args: @@ -62,7 +62,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get effective config as we need full dicitonary per interface delete diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index b27234d18..f86d59087 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -36,12 +36,11 @@ from vyos.vpp.config_verify import ( from vyos.vpp.utils import cli_ifaces_lcp_kernel_list -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get GRE interface configuration Args: config (vyos.config.Config, optional): The VyOS configuration dictionary - recursive_defaults (bool, optional): Include recursive defaults Returns: dict: GRE interface configuration """ @@ -62,7 +61,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get effective config as we need full dicitonary per interface delete diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index e0f1258d0..6de34e794 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -35,12 +35,11 @@ from vyos.vpp.config_verify import ( from vyos.vpp.utils import cli_ifaces_lcp_kernel_list -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get IPIP interface configuration Args: config (vyos.config.Config, optional): The VyOS configuration dictionary - recursive_defaults (bool, optional): Include recursive defaults Returns: dict: IPIP interface configuration """ @@ -61,7 +60,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get effective config as we need full dicitonary per interface delete diff --git a/src/conf_mode/vpp_interfaces_loopback.py b/src/conf_mode/vpp_interfaces_loopback.py index 67fd049f0..56a825ae6 100644 --- a/src/conf_mode/vpp_interfaces_loopback.py +++ b/src/conf_mode/vpp_interfaces_loopback.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -34,12 +34,11 @@ from vyos.vpp.config_verify import ( from vyos.vpp.utils import cli_ifaces_lcp_kernel_list -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get Loopback interface configuration Args: config (vyos.config.Config, optional): The VyOS configuration dictionary - recursive_defaults (bool, optional): Include recursive defaults Returns: dict: Loopback interface configuration """ @@ -60,7 +59,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get effective config as we need full dicitonary per interface delete diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index 5c957c7fa..a8a918805 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -37,12 +37,11 @@ from vyos.vpp.config_verify import ( from vyos.vpp.utils import cli_ifaces_lcp_kernel_list -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get VXLAN interface configuration Args: config (vyos.config.Config, optional): The VyOS configuration dictionary - recursive_defaults (bool, optional): Include recursive defaults Returns: dict: VXLAN interface configuration """ @@ -63,7 +62,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get effective config as we need full dicitonary per interface delete diff --git a/src/conf_mode/vpp_interfaces_xconnect.py b/src/conf_mode/vpp_interfaces_xconnect.py index dd1348b7c..3659c6479 100644 --- a/src/conf_mode/vpp_interfaces_xconnect.py +++ b/src/conf_mode/vpp_interfaces_xconnect.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) 2023-2025 VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -25,12 +25,11 @@ from vyos.vpp.interface import XconnectInterface from vyos.vpp.utils import cli_ifaces_list -def get_config(config=None, recursive_defaults=True) -> dict: +def get_config(config=None) -> dict: """Get Xconnect interface configuration Args: config (vyos.config.Config, optional): The VyOS configuration dictionary - recursive_defaults (bool, optional): Include recursive defaults Returns: dict: Bridge interface configuration """ @@ -51,7 +50,7 @@ def get_config(config=None, recursive_defaults=True) -> dict: get_first_key=True, no_tag_node_value_mangle=True, with_defaults=True, - with_recursive_defaults=recursive_defaults, + with_recursive_defaults=True, ) # Get effective config as we need full dicitonary per interface delete -- cgit v1.2.3 From 405d3ee7ac909bbf458f522e6539a1f4eacdf7e6 Mon Sep 17 00:00:00 2001 From: Viacheslav Hletenko Date: Wed, 15 Jan 2025 09:50:49 +0000 Subject: warning: introduce a delay between add() and kernel_add() Introduce a delay to address instability in the VPP API, which may fail to create the LCP or establish a connection. This should be reviewed and resolved in future releases. This fixes confgurations with included kernel-itnerface (LCP) And all smoketests Example: set interfaces ethernet eth1 address '192.0.2.1/30' set vpp settings interface eth1 driver 'dpdk' set vpp interfaces vxlan vxlan10 remote '192.0.2.2' set vpp interfaces vxlan vxlan10 source-address '192.0.2.1' set vpp interfaces vxlan vxlan10 vni '10' set vpp interfaces vxlan vxlan10 kernel-interface 'vpptap10' Without this delay we get: vyos@r14# commit [ vpp interfaces vxlan vxlan10 ] Traceback (most recent call last): File "/usr/libexec/vyos/services/vyos-configd", line 139, in run_script script.apply(c) File "/usr/libexec/vyos//conf_mode/vpp_interfaces_vxlan.py", line 174, in apply i.kernel_add() File "/usr/lib/python3/dist-packages/vyos/vpp/interface/vxlan.py", line 85, in kernel_add self.vpp.lcp_pair_add(self.ifname, self.kernel_interface) File "/usr/lib/python3/dist-packages/vyos/vpp/control_vpp.py", line 79, in check_retval_wrapper return_value = decorated_func(cls, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/vyos/vpp/control_vpp.py", line 58, in api_safe_wrapper return decorated_func(cls, *args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/vyos/vpp/control_vpp.py", line 188, in lcp_pair_add return self.__vpp_api_client.api.lcp_itf_pair_add_del_v2(**api_call_args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/vpp_papi/vpp_papi.py", line 129, in __call__ return self._func(**kwargs) ^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/vpp_papi/vpp_papi.py", line 564, in f return self._call_vpp(i, msg, multipart, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/lib/python3/dist-packages/vpp_papi/vpp_papi.py", line 853, in _call_vpp raise VPPIOError(2, "VPP API client: read failed") vpp_papi.vpp_papi.VPPIOError: [Errno 2] VPP API client: read failed --- src/conf_mode/vpp_interfaces_bonding.py | 5 +++++ src/conf_mode/vpp_interfaces_geneve.py | 4 ++++ src/conf_mode/vpp_interfaces_gre.py | 4 ++++ src/conf_mode/vpp_interfaces_ipip.py | 4 ++++ src/conf_mode/vpp_interfaces_loopback.py | 4 ++++ src/conf_mode/vpp_interfaces_vxlan.py | 4 ++++ 6 files changed, 25 insertions(+) (limited to 'src/conf_mode/vpp_interfaces_loopback.py') diff --git a/src/conf_mode/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index 135be5c04..9f8133cfa 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os +import time from vyos.config import Config from vyos.configdict import leaf_node_changed @@ -192,6 +193,10 @@ def apply(config): kernel_interface = config.get('kernel_interface', '') i = BondInterface(ifname, mode, lb, mac, kernel_interface) + # Introduce a delay to address instability in the VPP API, which may fail to create the LCP + # or establish a connection. This should be reviewed and resolved in future releases. + time.sleep(2) + i.add() # Add members to bond if members: diff --git a/src/conf_mode/vpp_interfaces_geneve.py b/src/conf_mode/vpp_interfaces_geneve.py index a7e7ae8e5..17e0f0cfb 100644 --- a/src/conf_mode/vpp_interfaces_geneve.py +++ b/src/conf_mode/vpp_interfaces_geneve.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os +import time from vyos import ConfigError @@ -164,6 +165,9 @@ def apply(config): # Add kernel-interface (LCP) if interface is not exist if 'kernel_interface' in config and not is_interface(kernel_interface): + # Introduce a delay to address instability in the VPP API, which may fail to create the LCP + # or establish a connection. This should be reviewed and resolved in future releases. + time.sleep(2) i.kernel_add() call_dependents() diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index f86d59087..feff0d6b5 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os +import time from vyos import ConfigError @@ -163,6 +164,9 @@ def apply(config): # Add kernel-interface (LCP) if interface is not exist if 'kernel_interface' in config and not is_interface(kernel_interface): + # Introduce a delay to address instability in the VPP API, which may fail to create the LCP + # or establish a connection. This should be reviewed and resolved in future releases. + time.sleep(2) i.kernel_add() call_dependents() diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index 6de34e794..e15eaf5e5 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os +import time from vyos import ConfigError @@ -162,6 +163,9 @@ def apply(config): i.add() if 'kernel_interface' in config: + # Introduce a delay to address instability in the VPP API, which may fail to create the LCP + # or establish a connection. This should be reviewed and resolved in future releases. + time.sleep(2) i.kernel_add() call_dependents() diff --git a/src/conf_mode/vpp_interfaces_loopback.py b/src/conf_mode/vpp_interfaces_loopback.py index 56a825ae6..a96c379a1 100644 --- a/src/conf_mode/vpp_interfaces_loopback.py +++ b/src/conf_mode/vpp_interfaces_loopback.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os +import time from vyos import ConfigError @@ -134,6 +135,9 @@ def apply(config): # Add kernel-interface (LCP) if interface is not exist if 'kernel_interface' in config and not is_interface(kernel_interface): + # Introduce a delay to address instability in the VPP API, which may fail to create the LCP + # or establish a connection. This should be reviewed and resolved in future releases. + time.sleep(2) i.kernel_add() call_dependents() diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index a8a918805..de3114124 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os +import time from vyos import ConfigError @@ -169,6 +170,9 @@ def apply(config): # Add kernel-interface (LCP) if interface is not exist if 'kernel_interface' in config and not is_interface(kernel_interface): + # Introduce a delay to address instability in the VPP API, which may fail to create the LCP + # or establish a connection. This should be reviewed and resolved in future releases. + time.sleep(2) i.kernel_add() call_dependents() -- cgit v1.2.3 From dfda2c7f305df94690cc4538a74ab213d25c579c Mon Sep 17 00:00:00 2001 From: Viacheslav Hletenko Date: Mon, 27 Jan 2025 18:01:57 +0000 Subject: Use common class for none ethernet interfaces state --- python/vyos/vpp/interface/__init__.py | 2 ++ python/vyos/vpp/interface/gre.py | 10 ++++++++-- python/vyos/vpp/interface/ipip.py | 17 ++++++++++++++--- python/vyos/vpp/interface/loopback.py | 11 +++++++---- python/vyos/vpp/interface/vxlan.py | 18 +++++++++++++++--- python/vyos/vpp/interface/xconnect.py | 2 ++ src/conf_mode/vpp_interfaces_gre.py | 5 ++++- src/conf_mode/vpp_interfaces_ipip.py | 3 ++- src/conf_mode/vpp_interfaces_loopback.py | 3 ++- src/conf_mode/vpp_interfaces_vxlan.py | 3 ++- src/conf_mode/vpp_interfaces_xconnect.py | 3 ++- 11 files changed, 60 insertions(+), 17 deletions(-) (limited to 'src/conf_mode/vpp_interfaces_loopback.py') diff --git a/python/vyos/vpp/interface/__init__.py b/python/vyos/vpp/interface/__init__.py index 14659ed7b..2048e07ca 100644 --- a/python/vyos/vpp/interface/__init__.py +++ b/python/vyos/vpp/interface/__init__.py @@ -20,6 +20,7 @@ from .bridge import BridgeInterface from .ethernet import EthernetInterface from .geneve import GeneveInterface from .gre import GREInterface +from .interface import Interface from .ipip import IPIPInterface from .loopback import LoopbackInterface from .vxlan import VXLANInterface @@ -32,6 +33,7 @@ __all__ = [ 'EthernetInterface', 'GeneveInterface', 'GREInterface', + 'Interface', 'IPIPInterface', 'LoopbackInterface', 'VXLANInterface', diff --git a/python/vyos/vpp/interface/gre.py b/python/vyos/vpp/interface/gre.py index 8f3dbebae..5bef280c6 100644 --- a/python/vyos/vpp/interface/gre.py +++ b/python/vyos/vpp/interface/gre.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from vyos.vpp import VPPControl +from vyos.vpp.interface.interface import Interface def show(): @@ -29,7 +30,7 @@ def show(): return vpp.api.gre_tunnel_dump() -class GREInterface: +class GREInterface(Interface): """ Class representing a GRE (Generic Routing Encapsulation) interface. @@ -64,6 +65,7 @@ class GREInterface: tunnel_type: str = 'l3', mode: str = 'point-to-point', kernel_interface: str = '', + state: str = 'up', ): """ Initialize a GREInterface instance. @@ -75,7 +77,9 @@ class GREInterface: mode (str): The mode of the GRE tunnel. Options are 'point-to-point' and 'point-to-multipoint'. Defaults to 'point-to-point'. tunnel_type (str): The type of GRE tunnel. Defaults to 'l3'. kernel_interface (str): The associated kernel interface. Defaults to an empty string. + state (str): The state of the interface. Defaults to 'up'. """ + super().__init__(ifname) self.instance = int(ifname.removeprefix('gre')) self.ifname = ifname self.src_address = source_address @@ -83,7 +87,7 @@ class GREInterface: self.tunnel_type = self.TUNNEL_TYPE_MAP[tunnel_type] self.mode = self.MODE_MAP[mode] self.kernel_interface = kernel_interface - self.vpp = VPPControl() + self.initial_state = state def add(self): """Create GRE interface @@ -103,6 +107,8 @@ class GREInterface: 'type': self.tunnel_type, }, ) + # Set interface state + self.set_state(self.initial_state) def delete(self): """Delete GRE interface diff --git a/python/vyos/vpp/interface/ipip.py b/python/vyos/vpp/interface/ipip.py index 1aa1e22f2..4779a8292 100644 --- a/python/vyos/vpp/interface/ipip.py +++ b/python/vyos/vpp/interface/ipip.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from vyos.vpp import VPPControl +from vyos.vpp.interface.interface import Interface def show(): @@ -29,14 +30,22 @@ def show(): return vpp.api.ipip_tunnel_dump() -class IPIPInterface: - def __init__(self, ifname, source_address, remote, kernel_interface: str = ''): +class IPIPInterface(Interface): + def __init__( + self, + ifname, + source_address, + remote, + kernel_interface: str = '', + state: str = 'up', + ): + super().__init__(ifname) self.instance = int(ifname.removeprefix('ipip')) self.ifname = ifname self.src_address = source_address self.dst_address = remote self.kernel_interface = kernel_interface - self.vpp = VPPControl() + self.initial_state = state def add(self): """Create IPIP interface @@ -53,6 +62,8 @@ class IPIPInterface: 'instance': self.instance, }, ) + # Set interface state + self.set_state(self.initial_state) def delete(self): """Delete IPIP interface diff --git a/python/vyos/vpp/interface/loopback.py b/python/vyos/vpp/interface/loopback.py index 8a5414d54..d417f627d 100644 --- a/python/vyos/vpp/interface/loopback.py +++ b/python/vyos/vpp/interface/loopback.py @@ -16,17 +16,18 @@ # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -from vyos.vpp import VPPControl +from vyos.vpp.interface.interface import Interface -class LoopbackInterface: +class LoopbackInterface(Interface): """Interface Loopback""" - def __init__(self, ifname, kernel_interface: str = ''): + def __init__(self, ifname, kernel_interface: str = '', state: str = 'up'): + super().__init__(ifname) self.instance = int(ifname.removeprefix('lo')) self.ifname = f'loop{self.instance}' self.kernel_interface = kernel_interface - self.vpp = VPPControl() + self.initial_state = state def add(self): """Create Loopback interface @@ -39,6 +40,8 @@ class LoopbackInterface: self.vpp.api.create_loopback_instance( is_specified=True, user_instance=self.instance ) + # Set interface state + self.set_state(self.initial_state) def delete(self): """Delete Loopback interface diff --git a/python/vyos/vpp/interface/vxlan.py b/python/vyos/vpp/interface/vxlan.py index 36206e8c4..eacc901dc 100644 --- a/python/vyos/vpp/interface/vxlan.py +++ b/python/vyos/vpp/interface/vxlan.py @@ -17,6 +17,7 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from vyos.vpp import VPPControl +from vyos.vpp.interface.interface import Interface def show(): @@ -29,17 +30,26 @@ def show(): return vpp.api.vxlan_tunnel_dump() -class VXLANInterface: +class VXLANInterface(Interface): """Interface VXLAN""" - def __init__(self, ifname, source_address, remote, vni, kernel_interface: str = ''): + def __init__( + self, + ifname, + source_address, + remote, + vni, + kernel_interface: str = '', + state: str = 'up', + ): + super().__init__(ifname) self.instance = int(ifname.removeprefix('vxlan')) self.ifname = f'vxlan_tunnel{self.instance}' self.src_address = source_address self.dst_address = remote self.vni = vni self.kernel_interface = kernel_interface - self.vpp = VPPControl() + self.initial_state = state def add(self): """Create VXLAN interface @@ -59,6 +69,8 @@ class VXLANInterface: decap_next_index=1, is_l3=False, ) + # Set interface state + self.set_state(self.initial_state) def delete(self): """Delete VXLAN interface diff --git a/python/vyos/vpp/interface/xconnect.py b/python/vyos/vpp/interface/xconnect.py index 41cf773d9..badece6e8 100644 --- a/python/vyos/vpp/interface/xconnect.py +++ b/python/vyos/vpp/interface/xconnect.py @@ -25,10 +25,12 @@ class XconnectInterface: self, ifname: str, members: list = [], + state: str = 'up', ): self.ifname = ifname self.members = members self.vpp = VPPControl() + self.initial_state = state def add_l2_xconnect(self): """Add l2 cross connect diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index 817345135..c8e84f169 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -167,7 +167,10 @@ def apply(config): kernel_interface = config.get('kernel_interface', '') mode = config.get('mode') tunnel_type = config.get('tunnel_type') - i = GREInterface(ifname, src_addr, dst_addr, tunnel_type, mode, kernel_interface) + state = 'up' if 'disable' not in config else 'down' + i = GREInterface( + ifname, src_addr, dst_addr, tunnel_type, mode, kernel_interface, state + ) i.add() # Add kernel-interface (LCP) if interface is not exist diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index e15eaf5e5..3b03f91cd 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -159,7 +159,8 @@ def apply(config): src_addr = config.get('source_address') dst_addr = config.get('remote') kernel_interface = config.get('kernel_interface', '') - i = IPIPInterface(ifname, src_addr, dst_addr, kernel_interface) + state = 'up' if 'disable' not in config else 'down' + i = IPIPInterface(ifname, src_addr, dst_addr, kernel_interface, state) i.add() if 'kernel_interface' in config: diff --git a/src/conf_mode/vpp_interfaces_loopback.py b/src/conf_mode/vpp_interfaces_loopback.py index a96c379a1..6aa3fc850 100644 --- a/src/conf_mode/vpp_interfaces_loopback.py +++ b/src/conf_mode/vpp_interfaces_loopback.py @@ -130,7 +130,8 @@ def apply(config): # Add interface kernel_interface = config.get('kernel_interface', '') - i = LoopbackInterface(ifname, kernel_interface) + state = 'up' if 'disable' not in config else 'down' + i = LoopbackInterface(ifname, kernel_interface, state) i.add() # Add kernel-interface (LCP) if interface is not exist diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index de3114124..81bc34bea 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -165,7 +165,8 @@ def apply(config): dst_addr = config.get('remote') vni = int(config.get('vni')) kernel_interface = config.get('kernel_interface', '') - i = VXLANInterface(ifname, src_addr, dst_addr, vni, kernel_interface) + state = 'up' if 'disable' not in config else 'down' + i = VXLANInterface(ifname, src_addr, dst_addr, vni, kernel_interface, state) i.add() # Add kernel-interface (LCP) if interface is not exist diff --git a/src/conf_mode/vpp_interfaces_xconnect.py b/src/conf_mode/vpp_interfaces_xconnect.py index 3659c6479..c323684a3 100644 --- a/src/conf_mode/vpp_interfaces_xconnect.py +++ b/src/conf_mode/vpp_interfaces_xconnect.py @@ -124,7 +124,8 @@ def apply(config): # Add xconnect members = config.get('member', {}).get('interface') - i = XconnectInterface(ifname, members=members) + state = 'up' if 'disable' not in config else 'down' + i = XconnectInterface(ifname, members=members, state=state) i.add_l2_xconnect() return None -- cgit v1.2.3 From f5aaef311484f90d87f46d5a5739897e560ceb40 Mon Sep 17 00:00:00 2001 From: Viacheslav Hletenko Date: Wed, 29 Jan 2025 13:31:10 +0000 Subject: Revert "warning: introduce a delay between add() and kernel_add()" This reverts commit 405d3ee7ac909bbf458f522e6539a1f4eacdf7e6. --- src/conf_mode/vpp_interfaces_bonding.py | 5 ----- src/conf_mode/vpp_interfaces_geneve.py | 4 ---- src/conf_mode/vpp_interfaces_gre.py | 4 ---- src/conf_mode/vpp_interfaces_ipip.py | 4 ---- src/conf_mode/vpp_interfaces_loopback.py | 4 ---- src/conf_mode/vpp_interfaces_vxlan.py | 4 ---- 6 files changed, 25 deletions(-) (limited to 'src/conf_mode/vpp_interfaces_loopback.py') diff --git a/src/conf_mode/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index a93239d57..7ab1abb24 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -17,7 +17,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os -import time from vyos.config import Config from vyos.configdict import leaf_node_changed @@ -193,10 +192,6 @@ def apply(config): state = 'up' if 'disable' not in config else 'down' i = BondInterface(ifname, mode, lb, mac, kernel_interface, state) - # Introduce a delay to address instability in the VPP API, which may fail to create the LCP - # or establish a connection. This should be reviewed and resolved in future releases. - time.sleep(2) - i.add() # Add members to bond if members: diff --git a/src/conf_mode/vpp_interfaces_geneve.py b/src/conf_mode/vpp_interfaces_geneve.py index 17e0f0cfb..a7e7ae8e5 100644 --- a/src/conf_mode/vpp_interfaces_geneve.py +++ b/src/conf_mode/vpp_interfaces_geneve.py @@ -17,7 +17,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os -import time from vyos import ConfigError @@ -165,9 +164,6 @@ def apply(config): # Add kernel-interface (LCP) if interface is not exist if 'kernel_interface' in config and not is_interface(kernel_interface): - # Introduce a delay to address instability in the VPP API, which may fail to create the LCP - # or establish a connection. This should be reviewed and resolved in future releases. - time.sleep(2) i.kernel_add() call_dependents() diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index c8e84f169..de7398248 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -17,7 +17,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os -import time from vyos import ConfigError @@ -175,9 +174,6 @@ def apply(config): # Add kernel-interface (LCP) if interface is not exist if 'kernel_interface' in config and not is_interface(kernel_interface): - # Introduce a delay to address instability in the VPP API, which may fail to create the LCP - # or establish a connection. This should be reviewed and resolved in future releases. - time.sleep(2) i.kernel_add() call_dependents() diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index 3b03f91cd..2428a9850 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -17,7 +17,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os -import time from vyos import ConfigError @@ -164,9 +163,6 @@ def apply(config): i.add() if 'kernel_interface' in config: - # Introduce a delay to address instability in the VPP API, which may fail to create the LCP - # or establish a connection. This should be reviewed and resolved in future releases. - time.sleep(2) i.kernel_add() call_dependents() diff --git a/src/conf_mode/vpp_interfaces_loopback.py b/src/conf_mode/vpp_interfaces_loopback.py index 6aa3fc850..f0bcdfb18 100644 --- a/src/conf_mode/vpp_interfaces_loopback.py +++ b/src/conf_mode/vpp_interfaces_loopback.py @@ -17,7 +17,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os -import time from vyos import ConfigError @@ -136,9 +135,6 @@ def apply(config): # Add kernel-interface (LCP) if interface is not exist if 'kernel_interface' in config and not is_interface(kernel_interface): - # Introduce a delay to address instability in the VPP API, which may fail to create the LCP - # or establish a connection. This should be reviewed and resolved in future releases. - time.sleep(2) i.kernel_add() call_dependents() diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index 81bc34bea..b94b39d6d 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -17,7 +17,6 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import os -import time from vyos import ConfigError @@ -171,9 +170,6 @@ def apply(config): # Add kernel-interface (LCP) if interface is not exist if 'kernel_interface' in config and not is_interface(kernel_interface): - # Introduce a delay to address instability in the VPP API, which may fail to create the LCP - # or establish a connection. This should be reviewed and resolved in future releases. - time.sleep(2) i.kernel_add() call_dependents() -- cgit v1.2.3 From 151afffe15ce89755f3c3f81a9d2c647e487f647 Mon Sep 17 00:00:00 2001 From: "Nataliia S." <81954790+natali-rs1985@users.noreply.github.com> Date: Tue, 13 May 2025 17:33:35 +0300 Subject: T7419: VPP ACL implementation (#31) CLI: ``` set vpp acl ip tag-name rule action set vpp acl ip tag-name rule source prefix set vpp acl ip tag-name rule source port set vpp acl ip tag-name rule destination prefix set vpp acl ip tag-name rule destination port set vpp acl ip tag-name rule protocol set vpp acl ip tag-name rule tcp-flags set vpp acl ip tag-name rule tcp-flags not set vpp acl ip interface input acl-tag tag-name set vpp acl ip interface output acl-tag tag-name set vpp acl macip tag-name rule prefix set vpp acl macip tag-name rule mac-address set vpp acl macip tag-name rule mac-mask set vpp acl macip tag-name rule action set vpp acl macip interface tag-name ``` OP mode ``` show vpp acl ip tag-name show vpp acl ip interface show vpp acl macip tag-name show vpp acl macip interface ``` --- data/config-mode-dependencies/vyos-vpp.json | 8 + data/templates/vpp/startup.conf.j2 | 2 + .../include/vpp/acl_common_interface_ip_rule.xml.i | 25 ++ .../include/vpp/acl_port_range.xml.i | 18 + interface-definitions/include/vpp/acl_prefix.xml.i | 20 ++ .../include/vpp/acl_tcp_flags.xml.i | 50 +++ interface-definitions/vpp.xml.in | 254 ++++++++++++- op-mode-definitions/vpp_acl.xml.in | 65 ++++ python/vyos/vpp/acl/__init__.py | 3 + python/vyos/vpp/acl/acl.py | 106 ++++++ src/conf_mode/vpp.py | 4 + src/conf_mode/vpp_acl.py | 393 +++++++++++++++++++++ src/conf_mode/vpp_interfaces_bonding.py | 10 + src/conf_mode/vpp_interfaces_gre.py | 10 + src/conf_mode/vpp_interfaces_ipip.py | 10 + src/conf_mode/vpp_interfaces_loopback.py | 10 + src/conf_mode/vpp_interfaces_vxlan.py | 10 + src/op_mode/vpp_acl.py | 342 ++++++++++++++++++ 18 files changed, 1338 insertions(+), 2 deletions(-) create mode 100644 interface-definitions/include/vpp/acl_common_interface_ip_rule.xml.i create mode 100644 interface-definitions/include/vpp/acl_port_range.xml.i create mode 100644 interface-definitions/include/vpp/acl_prefix.xml.i create mode 100644 interface-definitions/include/vpp/acl_tcp_flags.xml.i create mode 100644 op-mode-definitions/vpp_acl.xml.in create mode 100644 python/vyos/vpp/acl/__init__.py create mode 100644 python/vyos/vpp/acl/acl.py create mode 100644 src/conf_mode/vpp_acl.py create mode 100644 src/op_mode/vpp_acl.py (limited to 'src/conf_mode/vpp_interfaces_loopback.py') diff --git a/data/config-mode-dependencies/vyos-vpp.json b/data/config-mode-dependencies/vyos-vpp.json index 0f1d8af34..2a5613559 100644 --- a/data/config-mode-dependencies/vyos-vpp.json +++ b/data/config-mode-dependencies/vyos-vpp.json @@ -10,41 +10,48 @@ "vpp_interfaces_loopback": ["vpp_interfaces_loopback"], "vpp_interfaces_vxlan": ["vpp_interfaces_vxlan"], "vpp_interfaces_xconnect": ["vpp_interfaces_xconnect"], + "vpp_acl": ["vpp_acl"], "vpp_nat": ["vpp_nat"], "vpp_nat_cgnat": ["vpp_nat_cgnat"], "vpp_kernel_interface": ["vpp_kernel-interfaces"] }, "vpp_interfaces_bonding": { "vpp_interfaces_xconnect": ["vpp_interfaces_xconnect"], + "vpp_acl": ["vpp_acl"], "vpp_nat": ["vpp_nat"], "vpp_nat_cgnat": ["vpp_nat_cgnat"], "vpp_kernel_interface": ["vpp_kernel-interfaces"] }, "vpp_interfaces_ethernet": { "vpp_interfaces_xconnect": ["vpp_interfaces_xconnect"], + "vpp_acl": ["vpp_acl"], "vpp_nat": ["vpp_nat"], "vpp_nat_cgnat": ["vpp_nat_cgnat"], "vpp_kernel_interface": ["vpp_kernel-interfaces"] }, "vpp_interfaces_geneve": { "vpp_interfaces_xconnect": ["vpp_interfaces_xconnect"], + "vpp_acl": ["vpp_acl"], "vpp_nat": ["vpp_nat"], "vpp_nat_cgnat": ["vpp_nat_cgnat"], "vpp_kernel_interface": ["vpp_kernel-interfaces"] }, "vpp_interfaces_gre": { "vpp_interfaces_xconnect": ["vpp_interfaces_xconnect"], + "vpp_acl": ["vpp_acl"], "vpp_nat": ["vpp_nat"], "vpp_nat_cgnat": ["vpp_nat_cgnat"], "vpp_kernel_interface": ["vpp_kernel-interfaces"] }, "vpp_interfaces_ipip": { "vpp_interfaces_xconnect": ["vpp_interfaces_xconnect"], + "vpp_acl": ["vpp_acl"], "vpp_nat": ["vpp_nat"], "vpp_nat_cgnat": ["vpp_nat_cgnat"], "vpp_kernel_interface": ["vpp_kernel-interfaces"] }, "vpp_interfaces_loopback": { + "vpp_acl": ["vpp_acl"], "vpp_nat": ["vpp_nat"], "vpp_nat_cgnat": ["vpp_nat_cgnat"], "vpp_kernel_interface": ["vpp_kernel-interfaces"] @@ -52,6 +59,7 @@ "vpp_interfaces_vxlan": { "vpp_interfaces_bridge": ["vpp_interfaces_bridge"], "vpp_interfaces_xconnect": ["vpp_interfaces_xconnect"], + "vpp_acl": ["vpp_acl"], "vpp_nat": ["vpp_nat"], "vpp_nat_cgnat": ["vpp_nat_cgnat"], "vpp_kernel_interface": ["vpp_kernel-interfaces"] diff --git a/data/templates/vpp/startup.conf.j2 b/data/templates/vpp/startup.conf.j2 index 589afa67b..79a551338 100644 --- a/data/templates/vpp/startup.conf.j2 +++ b/data/templates/vpp/startup.conf.j2 @@ -114,6 +114,8 @@ plugins { plugin crypto_openssl_plugin.so { enable } {% endif %} # plugin wireguard_plugin.so { enable } + # ACL + plugin acl_plugin.so { enable } } linux-cp { diff --git a/interface-definitions/include/vpp/acl_common_interface_ip_rule.xml.i b/interface-definitions/include/vpp/acl_common_interface_ip_rule.xml.i new file mode 100644 index 000000000..a719a6223 --- /dev/null +++ b/interface-definitions/include/vpp/acl_common_interface_ip_rule.xml.i @@ -0,0 +1,25 @@ + + + + ACL rule (tag) number + + u32 + Number + + + + + Number must be between 1 and 4294967295 + + + + + ACL tag name + + vpp acl ip tag-name + + + + + + diff --git a/interface-definitions/include/vpp/acl_port_range.xml.i b/interface-definitions/include/vpp/acl_port_range.xml.i new file mode 100644 index 000000000..26bd2de45 --- /dev/null +++ b/interface-definitions/include/vpp/acl_port_range.xml.i @@ -0,0 +1,18 @@ + + + + Port number or range + + u32:1-65535 + Numeric IP port + + + range + Numbered port range (e.g., 1001-1005) + + + + + + + diff --git a/interface-definitions/include/vpp/acl_prefix.xml.i b/interface-definitions/include/vpp/acl_prefix.xml.i new file mode 100644 index 000000000..790153c8f --- /dev/null +++ b/interface-definitions/include/vpp/acl_prefix.xml.i @@ -0,0 +1,20 @@ + + + + IP prefix + + ipv4net + IPv4 prefix + + + ipv6net + IPv6 prefix + + + + + + + + + diff --git a/interface-definitions/include/vpp/acl_tcp_flags.xml.i b/interface-definitions/include/vpp/acl_tcp_flags.xml.i new file mode 100644 index 000000000..da17f3fe5 --- /dev/null +++ b/interface-definitions/include/vpp/acl_tcp_flags.xml.i @@ -0,0 +1,50 @@ + + + + Synchronise flag + + + + + + Acknowledge flag + + + + + + Finish flag + + + + + + Reset flag + + + + + + Urgent flag + + + + + + Push flag + + + + + + Explicit Congestion Notification flag + + + + + + Congestion Window Reduced flag + + + + diff --git a/interface-definitions/vpp.xml.in b/interface-definitions/vpp.xml.in index 368405a02..dab0ea308 100644 --- a/interface-definitions/vpp.xml.in +++ b/interface-definitions/vpp.xml.in @@ -942,7 +942,7 @@ Carrier-grade NAT (CGNAT) - 321 + 331 @@ -1060,7 +1060,7 @@ NAT44 - 320 + 330 @@ -1265,6 +1265,256 @@ + + + Access Control Lists (ACLs) + 332 + + + + + Access Control List by IPv4/IPv6 + + + + + ACL tag name + + txt + Tag name + + + + #include + + + Rule number for Access control element (ACE) + + u32 + Number of ACE + + + + + Rule number must be between 1 and 4294967295 + + + #include + + + Rule action + + permit deny permit-reflect + + + permit + Permit matching traffic + + + deny + Deny matching traffic + + + permit-reflect + Permit the matching outbound traffic and allow the reverse traffic + + + (permit|deny|permit-reflect) + + + + + + Source parameters + + + #include + #include + + + + + Destination parameters + + + #include + #include + + + + + Protocol + + + all + + + all + All IP protocols + + + <protocol> + IP protocol name + + + + + + all + + + + TCP flags + + + #include + + + Match flags not set + + + #include + + + + + + + + + + + Apply an ACL to an interface + + + + + + + + Input direction + + + #include + + + + + Output direction + + + #include + + + + + + + + + Access Control List by mac address + + + + + ACL tag name + + txt + ACL name + + + + #include + + + Rule number for Access control element (ACE) + + u32 + Number of ACE + + + + + Rule number must be between 1 and 4294967295 + + + #include + + + Rule action + + permit deny + + + permit + Permit matching traffic + + + deny + Deny matching traffic + + + (permit|deny) + + + + #include + + + Source IP prefix + + + + + Source MAC address + + macaddr + MAC address + + + + + + + + + Source MAC mask (default ff:ff:ff:ff:ff:ff) + + macaddr + MAC mask + + + + + + ff:ff:ff:ff:ff:ff + + + + + + + + Apply an ACL to an input interface + + + + + + + + ACL tag name + + vpp acl macip tag-name + + + + + + + + + VPP kernel interface settings diff --git a/op-mode-definitions/vpp_acl.xml.in b/op-mode-definitions/vpp_acl.xml.in new file mode 100644 index 000000000..a901a537d --- /dev/null +++ b/op-mode-definitions/vpp_acl.xml.in @@ -0,0 +1,65 @@ + + + + + + + + + Show VPP ACL information + + + + + Show VPP ACL by IPv4/IPv6 + + + + + Show specified VPP ACL + + vpp acl ip tag-name + + + sudo ${vyos_op_scripts_dir}/vpp_acl.py show_ip_acls --tag-name="$6" + + + + Show VPP ACL interfaces + + sudo ${vyos_op_scripts_dir}/vpp_acl.py show_interfaces + + + sudo ${vyos_op_scripts_dir}/vpp_acl.py show_ip_acls + + + + Show VPP ACL by macip + + + + + Show specified VPP ACL + + vpp acl macip tag-name + + + sudo ${vyos_op_scripts_dir}/vpp_acl.py show_macip_acls --tag-name="$6" + + + + Show VPP ACL interfaces + + sudo ${vyos_op_scripts_dir}/vpp_acl.py show_macip_interfaces + + + sudo ${vyos_op_scripts_dir}/vpp_acl.py show_macip_acls + + + sudo ${vyos_op_scripts_dir}/vpp_acl.py show_all_acls + + + + + + diff --git a/python/vyos/vpp/acl/__init__.py b/python/vyos/vpp/acl/__init__.py new file mode 100644 index 000000000..6bd6cdb23 --- /dev/null +++ b/python/vyos/vpp/acl/__init__.py @@ -0,0 +1,3 @@ +from .acl import Acl + +__all__ = ['Acl'] diff --git a/python/vyos/vpp/acl/acl.py b/python/vyos/vpp/acl/acl.py new file mode 100644 index 000000000..9da241f1c --- /dev/null +++ b/python/vyos/vpp/acl/acl.py @@ -0,0 +1,106 @@ +# +# Copyright (C) 2025 VyOS Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from vyos.vpp import VPPControl + + +NO_ACL_INDEX = 0xFFFFFFFF + + +class Acl: + def __init__(self): + self.vpp = VPPControl() + + def get_acl_index_by_tag(self, tag): + """Get ACL index by tag name + https://github.com/FDio/vpp/blob/21c641f9356da5137760cdc799127064c8c1fd31/src/plugins/acl/acl.api + """ + for acl in self.vpp.api.acl_dump(acl_index=NO_ACL_INDEX): + if acl.tag == tag: + return acl.acl_index + return NO_ACL_INDEX + + def add_replace_acl(self, tag, rules): + """Add new ACL or replace existing one""" + self.vpp.api.acl_add_replace( + tag=tag, + acl_index=self.get_acl_index_by_tag(tag), + count=len(rules), + r=rules, + ) + + def delete_acl(self, tag): + """Delete existing ACL""" + self.vpp.api.acl_del(acl_index=self.get_acl_index_by_tag(tag)) + + def add_acl_interface(self, interface, input_tags, output_tags): + """Add or replace ACLs on interface""" + acls = [] + for tag in input_tags: + acl_index = self.get_acl_index_by_tag(tag) + acls.append(acl_index) + for tag in output_tags: + acl_index = self.get_acl_index_by_tag(tag) + acls.append(acl_index) + self.vpp.api.acl_interface_set_acl_list( + sw_if_index=self.vpp.get_sw_if_index(interface), + count=len(acls), + n_input=len(input_tags), + acls=acls, + ) + + def delete_acl_interface(self, interface): + """Delete ACLs from interface""" + self.vpp.api.acl_interface_set_acl_list( + sw_if_index=self.vpp.get_sw_if_index(interface), + count=0, + ) + + def get_macip_acl_index_by_tag(self, tag): + """Get macip ACL by tag name""" + for acl in self.vpp.api.macip_acl_dump(): + if acl.tag == tag: + return acl.acl_index + return NO_ACL_INDEX + + def add_replace_acl_macip(self, tag, rules): + """Add or replace existing macip ACL""" + self.vpp.api.macip_acl_add_replace( + tag=tag, + acl_index=self.get_macip_acl_index_by_tag(tag), + count=len(rules), + r=rules, + ) + + def delete_acl_macip(self, tag): + """Delete existing macip ACL""" + self.vpp.api.macip_acl_del(acl_index=self.get_macip_acl_index_by_tag(tag)) + + def add_acl_macip_interface(self, interface, tag): + """Add or replace macip ACLs on interface""" + self.vpp.api.macip_acl_interface_add_del( + sw_if_index=self.vpp.get_sw_if_index(interface), + acl_index=self.get_macip_acl_index_by_tag(tag), + is_add=True, + ) + + def delete_acl_macip_interface(self, interface): + """Delete macip ACLs from interface""" + self.vpp.api.macip_acl_interface_add_del( + sw_if_index=self.vpp.get_sw_if_index(interface), + is_add=False, + ) diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py index 3718f3897..ed0e80c2c 100755 --- a/src/conf_mode/vpp.py +++ b/src/conf_mode/vpp.py @@ -141,6 +141,10 @@ def get_config(config=None): if conf.exists(['vpp', 'nat', 'cgnat']): set_dependents('vpp_nat_cgnat', conf) + # ACL dependency + if conf.exists(['vpp', 'acl']): + set_dependents('vpp_acl', conf) + if not conf.exists(base): return { 'removed_ifaces': removed_ifaces, diff --git a/src/conf_mode/vpp_acl.py b/src/conf_mode/vpp_acl.py new file mode 100644 index 000000000..28eae485b --- /dev/null +++ b/src/conf_mode/vpp_acl.py @@ -0,0 +1,393 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2025 VyOS Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import ipaddress + +from vyos import ConfigError + +from vyos.configdiff import Diff +from vyos.configdict import node_changed +from vyos.config import Config +from vyos.utils.network import get_protocol_by_name + +from vyos.vpp.utils import cli_ifaces_list +from vyos.vpp.acl import Acl + + +# TCP flag names to bit values +TCP_FLAGS = { + 'FIN': 0x01, + 'SYN': 0x02, + 'RST': 0x04, + 'PSH': 0x08, + 'ACK': 0x10, + 'URG': 0x20, + 'ECN': 0x40, + 'CWR': 0x80, +} + +# ACL action flags +action_map = { + 'deny': 0, + 'permit': 1, + 'permit-reflect': 2, +} + + +def get_tcp_mask_value(set_flags, unset_flags): + mask = 0 + value = 0 + + for flag in set_flags + unset_flags: + bit = TCP_FLAGS.get(flag.upper()) + mask |= bit + if flag in set_flags: + value |= bit + + return mask, value + + +def get_port_first_last(port_range, protocol): + first_port = 0 + last_port = 65535 + if not port_range: + if protocol in ['icmp', 'ipv6-icmp']: + last_port = 255 + elif '-' not in port_range: + first_port = last_port = port_range + else: + first_port, last_port = port_range.split('-') + return int(first_port), int(last_port) + + +def create_ip_rules_list(rules): + rules_list = [] + for rule in rules.values(): + r = { + 'is_permit': action_map[rule.get('action')], + 'src_prefix': rule.get('source', {}).get('prefix', ''), + 'dst_prefix': rule.get('destination', {}).get('prefix', ''), + 'proto': ( + int(get_protocol_by_name(rule.get('protocol'))) + if rule.get('protocol') != 'all' + else 0 + ), + } + + tcp_flags = rule.get('tcp_flags', {}) + set_flags = [flag for flag in tcp_flags if flag != 'not'] + unet_flags = list(tcp_flags.get('not', {}).keys()) + tcp_mask, tcp_value = get_tcp_mask_value(set_flags, unet_flags) + r['tcp_flags_mask'] = tcp_mask + r['tcp_flags_value'] = tcp_value + + src_ports = rule.get('source', {}).get('port') + src_first_port, src_last_port = get_port_first_last( + src_ports, rule.get('protocol') + ) + r['srcport_or_icmptype_first'] = src_first_port + r['srcport_or_icmptype_last'] = src_last_port + + dst_ports = rule.get('destination', {}).get('port') + dst_first_port, dst_last_port = get_port_first_last( + dst_ports, rule.get('protocol') + ) + r['dstport_or_icmpcode_first'] = dst_first_port + r['dstport_or_icmpcode_last'] = dst_last_port + + rules_list.append(r) + + return rules_list + + +def create_macip_rules_list(rules): + rules_list = [] + for rule in rules.values(): + r = { + 'is_permit': action_map[rule.get('action')], + 'src_prefix': rule.get('prefix', ''), + 'src_mac': rule.get('mac_address', ''), + 'src_mac_mask': rule.get('mac_mask', ''), + } + rules_list.append(r) + + return rules_list + + +def get_config(config=None) -> dict: + if config: + conf = config + else: + conf = Config() + + base = ['vpp', 'acl'] + + # Get config_dict with default values + config = conf.get_config_dict( + base, + key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True, + with_defaults=True, + with_recursive_defaults=True, + ) + + # Get effective config as we need full dictionary for deletion + effective_config = conf.get_config_dict( + base, + key_mangling=('-', '_'), + effective=True, + get_first_key=True, + no_tag_node_value_mangle=True, + ) + + if not config: + config['remove'] = True + + changed_ip_ifaces = node_changed( + conf, + base + ['ip', 'interface'], + key_mangling=('-', '_'), + recursive=True, + expand_nodes=Diff.DELETE | Diff.ADD, + ) + + changed_macip_ifaces = node_changed( + conf, + base + ['macip', 'interface'], + key_mangling=('-', '_'), + recursive=True, + expand_nodes=Diff.DELETE | Diff.ADD, + ) + + config.update( + { + 'changed_ip_ifaces': changed_ip_ifaces, + 'changed_macip_ifaces': changed_macip_ifaces, + 'vpp_ifaces': cli_ifaces_list(conf), + } + ) + + if effective_config: + config.update({'effective': effective_config}) + + return config + + +def verify(config): + if 'remove' in config: + return None + + for acl_type in ['ip', 'macip']: + if acl_type in config: + acl = config.get(acl_type) + if 'tag_name' not in acl: + raise ConfigError(f'"tag-name" is required for "acl {acl_type}"') + + for acl_name, acl_config in acl.get('tag_name').items(): + if 'rule' not in acl_config: + raise ConfigError(f'Rules must be configured for ACL {acl_name}') + + for rule, rule_config in acl_config.get('rule').items(): + err_msg = f'Configuration error for {acl_type} ACL {acl_name} in rule {rule}:' + if 'action' not in rule_config: + raise ConfigError(f'{err_msg} action must be defined') + + for iface, iface_config in acl.get('interface', {}).items(): + if iface not in config.get('vpp_ifaces'): + raise ConfigError( + f'{iface} must be a VPP interface for ACL interface' + ) + + if 'ip' in config: + acl = config.get('ip') + for acl_name, acl_config in acl.get('tag_name').items(): + for rule, rule_config in acl_config.get('rule').items(): + err_msg = ( + f'Configuration error for {acl_type} ACL {acl_name} in rule {rule}:' + ) + + # verify IPv4 and IPv6 address family + src_prefix = rule_config.get('source', {}).get('prefix') + dst_prefix = rule_config.get('destination', {}).get('prefix') + src = ipaddress.ip_network(src_prefix) if src_prefix else None + dst = ipaddress.ip_network(dst_prefix) if dst_prefix else None + + if src and dst: + if src.version != dst.version: + raise ConfigError( + f'{err_msg} source and destination prefixes must be from the same IP family' + ) + elif src or dst: + family = src.version if src else dst.version + if family == 6: + raise ConfigError( + f'{err_msg} both source and destination prefixes must be defined for IPv6' + ) + + # verify protocol + protocol = rule_config.get('protocol') + if protocol != 'all': + proto = get_protocol_by_name(protocol) + if not isinstance(proto, int) and ( + not proto.isdigit() or int(proto) > 147 + ): + raise ConfigError( + f'{err_msg} protocol name {protocol} is not valid' + ) + + # verify TCP flags + if 'tcp_flags' in rule_config: + if rule_config.get('protocol') != 'tcp': + raise ConfigError( + f'{err_msg} protocol must be tcp when specifying tcp flags' + ) + + not_flags = rule_config.get('tcp_flags').get('not', []) + if not_flags: + duplicates = [ + flag + for flag in rule_config.get('tcp_flags') + if flag in not_flags + ] + if duplicates: + raise ConfigError( + f'{err_msg} cannot match a tcp flag as set and not set: {duplicates}' + ) + + for iface, iface_config in acl.get('interface', {}).items(): + if not any(key in iface_config for key in ('input', 'output')): + raise ConfigError( + f'Please specify direction input/output for interface {iface}' + ) + + for direction in ['input', 'output']: + if direction in iface_config: + iface_acl = iface_config.get(direction) + if 'acl_tag' not in iface_acl: + raise ConfigError( + f'"acl-tag" is required for {direction} interface {iface}' + ) + + used_names = [] + for tag, tag_conf in iface_acl.get('acl_tag').items(): + if 'tag_name' not in tag_conf: + raise ConfigError( + f'"tag-name" is required for {direction} interface {iface} with acl-tag {tag}' + ) + name = tag_conf.get('tag_name') + if name not in acl.get('tag_name').keys(): + raise ConfigError( + f'ACL with tag-name {name} does not exist. ' + f'Cannot use it for {direction} interface {iface}' + ) + if name in used_names: + raise ConfigError( + f'ACL with tag-name {name} is already used for {direction} interface {iface}' + ) + used_names.append(name) + + if 'macip' in config: + acl = config.get('macip') + for iface, iface_config in acl.get('interface', {}).items(): + if 'tag_name' not in iface_config: + raise ConfigError(f'"tag-name" is required for interface {iface}') + name = iface_config.get('tag_name') + if name not in acl.get('tag_name').keys(): + raise ConfigError( + f'ACL with tag-name {name} does not exist. Cannot use it for interface {iface}' + ) + + +def generate(config): + pass + + +def apply(config): + acl = Acl() + + if 'effective' in config: + # Delete ACL ip + if 'ip' in config.get('effective'): + remove_config_ip = config.get('effective').get('ip') + + # Delete ACL interfaces + for interface in config.get('changed_ip_ifaces'): + acl.delete_acl_interface(interface) + + # Delete ACLs + for acl_name in remove_config_ip.get('tag_name'): + if acl_name not in config.get('ip', {}).get('tag_name', {}): + acl.delete_acl(acl_name) + + # Delete ACL macip + if 'macip' in config.get('effective'): + remove_config_macip = config.get('effective').get('macip') + + # Delete ACL interfaces + for interface in config.get('changed_macip_ifaces'): + acl.delete_acl_macip_interface(interface) + + # Delete ACL macip + for acl_name in remove_config_macip.get('tag_name'): + if acl_name not in config.get('macip', {}).get('tag_name', {}): + acl.delete_acl_macip(acl_name) + + if 'remove' in config: + return None + + # Add or replace ACL ip + config_ip = config.get('ip', {}) + for acl_name in config_ip.get('tag_name', {}): + rules = create_ip_rules_list( + config_ip.get('tag_name').get(acl_name).get('rule') + ) + acl.add_replace_acl(acl_name, rules) + + for iface, iface_config in config_ip.get('interface', {}).items(): + input_tags = [ + v['tag_name'] + for v in iface_config.get('input', {}).get('acl_tag', {}).values() + ] + output_tags = [ + v['tag_name'] + for v in iface_config.get('output', {}).get('acl_tag', {}).values() + ] + acl.add_acl_interface(iface, input_tags, output_tags) + + # Add or replace ACL macip + config_macip = config.get('macip', {}) + for acl_name in config_macip.get('tag_name', {}): + rules = create_macip_rules_list( + config_macip.get('tag_name').get(acl_name).get('rule') + ) + acl.add_replace_acl_macip(acl_name, rules) + + for iface, iface_config in config_macip.get('interface', {}).items(): + acl.add_acl_macip_interface(iface, iface_config.get('tag_name')) + + +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/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index 7ab1abb24..2b17acb24 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -139,6 +139,16 @@ def get_config(config=None) -> dict: if conf.exists(['vpp', 'kernel-interfaces', iface]): set_dependents('vpp_kernel_interface', conf, iface) + # NAT dependency + if conf.exists(['vpp', 'nat44']): + set_dependents('vpp_nat', conf) + if conf.exists(['vpp', 'nat', 'cgnat']): + set_dependents('vpp_nat_cgnat', conf) + + # ACL dependency + if conf.exists(['vpp', 'acl']): + set_dependents('vpp_acl', conf) + config['ifname'] = ifname return config diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index 823f3ff4d..f6da2d55d 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -110,6 +110,16 @@ def get_config(config=None) -> dict: if conf.exists(['vpp', 'kernel-interfaces', iface]): set_dependents('vpp_kernel_interface', conf, iface) + # NAT dependency + if conf.exists(['vpp', 'nat44']): + set_dependents('vpp_nat', conf) + if conf.exists(['vpp', 'nat', 'cgnat']): + set_dependents('vpp_nat_cgnat', conf) + + # ACL dependency + if conf.exists(['vpp', 'acl']): + set_dependents('vpp_acl', conf) + config['ifname'] = ifname return config diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index c52e7c997..f40a4e243 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -109,6 +109,16 @@ def get_config(config=None) -> dict: if iface in config.get('vpp_kernel_interfaces'): set_dependents('vpp_kernel_interface', conf, iface) + # NAT dependency + if conf.exists(['vpp', 'nat44']): + set_dependents('vpp_nat', conf) + if conf.exists(['vpp', 'nat', 'cgnat']): + set_dependents('vpp_nat_cgnat', conf) + + # ACL dependency + if conf.exists(['vpp', 'acl']): + set_dependents('vpp_acl', conf) + config['ifname'] = ifname return config diff --git a/src/conf_mode/vpp_interfaces_loopback.py b/src/conf_mode/vpp_interfaces_loopback.py index f0bcdfb18..2b37b5e1c 100644 --- a/src/conf_mode/vpp_interfaces_loopback.py +++ b/src/conf_mode/vpp_interfaces_loopback.py @@ -99,6 +99,16 @@ def get_config(config=None) -> dict: if conf.exists(['vpp', 'kernel-interfaces', iface]): set_dependents('vpp_kernel_interface', conf, iface) + # NAT dependency + if conf.exists(['vpp', 'nat44']): + set_dependents('vpp_nat', conf) + if conf.exists(['vpp', 'nat', 'cgnat']): + set_dependents('vpp_nat_cgnat', conf) + + # ACL dependency + if conf.exists(['vpp', 'acl']): + set_dependents('vpp_acl', conf) + config['ifname'] = ifname return config diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index 963cd90ec..065a8eafb 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -116,6 +116,16 @@ def get_config(config=None) -> dict: if conf.exists(['vpp', 'kernel-interfaces', iface]): set_dependents('vpp_kernel_interface', conf, iface) + # NAT dependency + if conf.exists(['vpp', 'nat44']): + set_dependents('vpp_nat', conf) + if conf.exists(['vpp', 'nat', 'cgnat']): + set_dependents('vpp_nat_cgnat', conf) + + # ACL dependency + if conf.exists(['vpp', 'acl']): + set_dependents('vpp_acl', conf) + config['ifname'] = ifname return config diff --git a/src/op_mode/vpp_acl.py b/src/op_mode/vpp_acl.py new file mode 100644 index 000000000..7afe96433 --- /dev/null +++ b/src/op_mode/vpp_acl.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2025 VyOS Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# 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, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import json +import sys +import typing +from tabulate import tabulate + +import vyos.opmode +from vyos.config import Config +from vyos.configquery import ConfigTreeQuery + +from vyos.vpp import VPPControl + + +NO_ACL_INDEX = 0xFFFFFFFF + +# ACL action flags +action_map = { + 0: 'deny', + 1: 'permit', + 2: 'permit-reflect', +} + +# TCP flag names to bit values +TCP_FLAGS = { + 'FIN': 0x01, + 'SYN': 0x02, + 'RST': 0x04, + 'PSH': 0x08, + 'ACK': 0x10, + 'URG': 0x20, + 'ECN': 0x40, + 'CWR': 0x80, +} + + +def _verify(target): + """Decorator checks if config for VPP NAT CGNAT exists""" + from functools import wraps + + if target not in ['ip', 'macip', 'no_target']: + raise ValueError('Invalid target') + + def _verify_target(func): + @wraps(func) + def _wrapper(*args, **kwargs): + config = ConfigTreeQuery() + path = 'vpp acl' + if target == 'ip': + path += ' ip' + elif target == 'macip': + path += ' macip' + if not config.exists(path): + raise vyos.opmode.UnconfiguredSubsystem(f'"{path}" is not configured') + return func(*args, **kwargs) + + return _wrapper + + return _verify_target + + +def _get_acl_tag_by_index(vpp, acl_index): + acl = vpp.api.acl_dump(acl_index=acl_index) + if acl: + return acl[0].tag + + return None + + +def _get_macip_acl_tag_by_index(vpp, acl_index): + acl = vpp.api.macip_acl_dump(acl_index=acl_index) + if acl: + return acl[0].tag + + return None + + +def _get_tcp_flag_states(value, mask): + set_flags = [] + unset_flags = [] + for flag, bit in TCP_FLAGS.items(): + if mask & bit: # This flag is being checked + if value & bit: + set_flags.append(flag) + else: + unset_flags.append(flag) + return sorted(set_flags), sorted(unset_flags) + + +def _get_raw_output_acls(data_dump): + out = [] + for data in data_dump: + rules = [json.loads(json.dumps(d._asdict(), default=str)) for d in data.r] + out.append( + { + 'acl_index': data.acl_index, + 'tag': data.tag, + 'count': data.count, + 'r': rules, + } + ) + return out + + +def _get_raw_output_interfaces(data_dump): + ifaces_list = [] + for iface in data_dump: + if iface.count != 0: + ifaces_list.append(json.loads(json.dumps(iface._asdict(), default=str))) + return ifaces_list + + +def _get_formatted_output_interfaces(vpp, interfaces): + data_entries = [] + for interface in interfaces: + name = vpp.get_interface_name(interface.get('sw_if_index')) + input_acls = [] + for acl_index in interface.get('acls')[: interface.get('n_input')]: + input_acls.append(_get_acl_tag_by_index(vpp, int(acl_index))) + output_acls = [] + for acl_index in interface.get('acls')[interface.get('n_input') :]: + output_acls.append(_get_acl_tag_by_index(vpp, int(acl_index))) + values = [ + name, + '\n'.join(input_acls), + '\n'.join(output_acls), + ] + data_entries.append(values) + + headers = ['Interface', 'Input ACLs', 'Output ACLs'] + return tabulate(data_entries, headers=headers, tablefmt='simple') + + +def _get_formatted_output_macip_interfaces(vpp, interfaces): + data_entries = [] + for interface in interfaces: + name = vpp.get_interface_name(interface.get('sw_if_index')) + acl = _get_macip_acl_tag_by_index(vpp, int(interface.get('acls')[0])) + data_entries.append([name, acl]) + + headers = ['Interface', 'ACL'] + return tabulate(data_entries, headers=headers, tablefmt='simple') + + +def _get_formatted_output_acls(acls_list): + conf = Config() + + for acl in acls_list: + acl_index = acl.get('acl_index') + tag = acl.get('tag') + rules = acl.get('r') + print( + '\n---------------------------------\n' + f'IP ACL "tag-name {tag}" acl_index {acl_index}\n' + ) + + path = ['vpp', 'acl', 'ip', 'tag-name', tag, 'rule'] + conf_rules = conf.list_nodes(path) + data_entries = [] + for rule_index, rule in enumerate(rules): + srcport_first = str(rule.get('srcport_or_icmptype_first')) + srcport_last = str(rule.get('srcport_or_icmptype_last')) + dstport_first = str(rule.get('dstport_or_icmpcode_first')) + dstport_last = str(rule.get('dstport_or_icmpcode_last')) + set_flags, unset_flags = _get_tcp_flag_states( + rule.get('tcp_flags_value'), rule.get('tcp_flags_mask') + ) + + values = [ + conf_rules[rule_index], + action_map.get(rule.get('is_permit')), + rule.get('src_prefix'), + ( + f'{srcport_first}-{srcport_last}' + if srcport_first != srcport_last + else srcport_first + ), + rule.get('dst_prefix'), + ( + f'{dstport_first}-{dstport_last}' + if dstport_first != dstport_last + else dstport_first + ), + rule.get('proto'), + '\n'.join(set_flags), + '\n'.join(unset_flags), + ] + data_entries.append(values) + + headers = [ + 'Rule', + 'Action', + 'Src prefix', + 'Src port', + 'Dst prefix', + 'Dst port', + 'Proto', + 'TCP flags set', + 'TCP flags not set', + ] + print(tabulate(data_entries, headers=headers, tablefmt='simple')) + print('\n') + + +def _get_formatted_output_macip_acls(acls_list): + conf = Config() + + for acl in acls_list: + acl_index = acl.get('acl_index') + tag = acl.get('tag') + rules = acl.get('r') + print( + '\n---------------------------------\n' + f'MACIP ACL "tag-name {tag}" acl_index {acl_index}\n' + ) + + path = ['vpp', 'acl', 'macip', 'tag-name', tag, 'rule'] + conf_rules = conf.list_nodes(path) + data_entries = [] + for rule_index, rule in enumerate(rules): + values = [ + conf_rules[rule_index], + action_map.get(rule.get('is_permit')), + rule.get('src_prefix'), + rule.get('src_mac'), + rule.get('src_mac_mask'), + ] + data_entries.append(values) + + headers = [ + 'Rule', + 'Action', + 'IP prefix', + 'MAC address', + 'MAC mask', + ] + print(tabulate(data_entries, headers=headers, tablefmt='simple')) + print('\n') + + +def _find_acl_by_tag(acls, tag_name): + return [acl for acl in acls if acl['tag'] == tag_name] + + +@_verify('ip') +def show_ip_acls(raw: bool, tag_name: typing.Optional[str]): + vpp = VPPControl() + acls_dump = vpp.api.acl_dump(acl_index=NO_ACL_INDEX) + acls: list[dict] = _get_raw_output_acls(acls_dump) + + if tag_name: + acls = _find_acl_by_tag(acls, tag_name) + + if raw: + return acls + + else: + return _get_formatted_output_acls(acls) + + +@_verify('macip') +def show_macip_acls(raw: bool, tag_name: typing.Optional[str]): + vpp = VPPControl() + acls_dump = vpp.api.macip_acl_dump(acl_index=NO_ACL_INDEX) + acls: list[dict] = _get_raw_output_acls(acls_dump) + + if tag_name: + acls = _find_acl_by_tag(acls, tag_name) + + if raw: + return acls + + else: + return _get_formatted_output_macip_acls(acls) + + +@_verify('ip') +def show_interfaces(raw: bool): + vpp = VPPControl() + interfaces_dump = vpp.api.acl_interface_list_dump() + interfaces: list[dict] = _get_raw_output_interfaces(interfaces_dump) + + if raw: + return interfaces + + else: + return _get_formatted_output_interfaces(vpp, interfaces) + + +@_verify('macip') +def show_macip_interfaces(raw: bool): + vpp = VPPControl() + interfaces_dump = vpp.api.macip_acl_interface_list_dump() + interfaces: list[dict] = _get_raw_output_interfaces(interfaces_dump) + + if raw: + return interfaces + + else: + return _get_formatted_output_macip_interfaces(vpp, interfaces) + + +@_verify('no_target') +def show_all_acls(raw: bool): + conf = Config() + acls_all = {} + path = ['vpp', 'acl'] + if conf.exists(path + ['ip']): + ip_acls = show_ip_acls(raw, tag_name=None) + acls_all['ip'] = ip_acls + if conf.exists(path + ['macip']): + macip_acls = show_macip_acls(raw, tag_name=None) + acls_all['macip'] = macip_acls + + if raw: + return acls_all + + +if __name__ == '__main__': + try: + res = vyos.opmode.run(sys.modules[__name__]) + if res: + print(res) + except (ValueError, vyos.opmode.Error) as e: + print(e) + sys.exit(1) -- cgit v1.2.3 From 31beaf550786502f5b62034c6e4b2e0e52508f8c Mon Sep 17 00:00:00 2001 From: Nataliia Solomko Date: Tue, 27 May 2025 14:27:50 +0300 Subject: T7488: Make VPP restartable --- data/templates/vpp/override.conf.j2 | 4 ++-- src/conf_mode/vpp_acl.py | 9 ++++++++- src/conf_mode/vpp_interfaces_bonding.py | 10 ++++++++++ src/conf_mode/vpp_interfaces_bridge.py | 9 ++++++++- src/conf_mode/vpp_interfaces_geneve.py | 11 +++++++++++ src/conf_mode/vpp_interfaces_gre.py | 11 +++++++++++ src/conf_mode/vpp_interfaces_ipip.py | 11 +++++++++++ src/conf_mode/vpp_interfaces_loopback.py | 11 +++++++++++ src/conf_mode/vpp_interfaces_vxlan.py | 11 +++++++++++ src/conf_mode/vpp_interfaces_xconnect.py | 9 ++++++++- src/conf_mode/vpp_kernel-interfaces.py | 9 ++++++++- src/conf_mode/vpp_nat.py | 9 ++++++++- src/conf_mode/vpp_nat_cgnat.py | 9 ++++++++- src/systemd/vpp-failure-handler.service | 9 +++++++++ 14 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 src/systemd/vpp-failure-handler.service (limited to 'src/conf_mode/vpp_interfaces_loopback.py') diff --git a/data/templates/vpp/override.conf.j2 b/data/templates/vpp/override.conf.j2 index a2c2b04ed..04bb7be15 100644 --- a/data/templates/vpp/override.conf.j2 +++ b/data/templates/vpp/override.conf.j2 @@ -3,6 +3,7 @@ After= After=vyos-router.service ConditionPathExists= ConditionPathExists=/run/vpp/vpp.conf +OnFailure=vpp-failure-handler.service [Service] EnvironmentFile= @@ -10,5 +11,4 @@ ExecStart= ExecStart=/usr/bin/vpp -c /run/vpp/vpp.conf WorkingDirectory= WorkingDirectory=/run/vpp -Restart=always -RestartSec=10 +Restart=no diff --git a/src/conf_mode/vpp_acl.py b/src/conf_mode/vpp_acl.py index 28eae485b..d6a9150d1 100644 --- a/src/conf_mode/vpp_acl.py +++ b/src/conf_mode/vpp_acl.py @@ -147,6 +147,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dictionary for deletion effective_config = conf.get_config_dict( base, @@ -190,7 +194,7 @@ def get_config(config=None) -> dict: def verify(config): - if 'remove' in config: + if 'remove' in config or 'remove_vpp' in config: return None for acl_type in ['ip', 'macip']: @@ -319,6 +323,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + acl = Acl() if 'effective' in config: diff --git a/src/conf_mode/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index 2b17acb24..c9aa6276c 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -86,6 +86,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete effective_config = conf.get_config_dict( base + [ifname], @@ -155,6 +159,9 @@ def get_config(config=None) -> dict: def verify(config): + if 'remove_vpp' in config: + return None + verify_vpp_remove_kernel_interface(config) verify_vpp_remove_xconnect_interface(config) @@ -175,6 +182,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') # remove old members if 'effective' in config: diff --git a/src/conf_mode/vpp_interfaces_bridge.py b/src/conf_mode/vpp_interfaces_bridge.py index dd5b49599..4272db616 100644 --- a/src/conf_mode/vpp_interfaces_bridge.py +++ b/src/conf_mode/vpp_interfaces_bridge.py @@ -53,6 +53,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete effective_config = conf.get_config_dict( base + [ifname], @@ -87,7 +91,7 @@ def get_config(config=None) -> dict: def verify(config): - if 'remove' in config: + if 'remove' in config or 'remove_vpp' in config: return None # Check if interface exists in vpp before adding to bridge-domain @@ -122,6 +126,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') # vxlan10 in the vpp is vxlan_tunnel10 interface_transform_filter = ('geneve', 'vxlan') diff --git a/src/conf_mode/vpp_interfaces_geneve.py b/src/conf_mode/vpp_interfaces_geneve.py index a7e7ae8e5..12fac83fb 100644 --- a/src/conf_mode/vpp_interfaces_geneve.py +++ b/src/conf_mode/vpp_interfaces_geneve.py @@ -65,6 +65,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete effective_config = conf.get_config_dict( base + [ifname], @@ -112,6 +116,10 @@ def get_config(config=None) -> dict: def verify(config): + # No need to verify anything if vpp is removed + if 'remove_vpp' in config: + return None + # Verify that removed kernel interface is not used in 'vpp kernel-interfaces'. # vpp interfaces geneve geneveX kernel-interface vpp-tunX # vpp kernel-interface vpp-tunX @@ -141,6 +149,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') # Delete interface if 'effective' in config: diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index f6da2d55d..5ec6feeb0 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -65,6 +65,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete effective_config = conf.get_config_dict( base + [ifname], @@ -125,6 +129,10 @@ def get_config(config=None) -> dict: def verify(config): + # No need to verify anything if vpp is removed + if 'remove_vpp' in config: + return None + # Verify that removed kernel interface is not used in 'vpp kernel-interfaces'. # vpp interfaces gre greX kernel-interface vpp-tunX # vpp kernel-interface vpp-tunX @@ -167,6 +175,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') # Delete interface if 'effective' in config: diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index f40a4e243..430b7b334 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -64,6 +64,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete effective_config = conf.get_config_dict( base + [ifname], @@ -125,6 +129,10 @@ def get_config(config=None) -> dict: def verify(config): + # No need to verify anything if vpp is removed + if 'remove_vpp' in config: + return None + # Verify that removed kernel interface is not used in 'vpp kernel-interfaces'. # vpp interfaces ipip ipipX kernel-interface vpp-tunX # vpp kernel-interface vpp-tunX @@ -161,6 +169,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') # Delete interface if 'effective' in config: diff --git a/src/conf_mode/vpp_interfaces_loopback.py b/src/conf_mode/vpp_interfaces_loopback.py index 2b37b5e1c..92ba110f1 100644 --- a/src/conf_mode/vpp_interfaces_loopback.py +++ b/src/conf_mode/vpp_interfaces_loopback.py @@ -62,6 +62,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete effective_config = conf.get_config_dict( base + [ifname], @@ -114,6 +118,10 @@ def get_config(config=None) -> dict: def verify(config): + # No need to verify anything if vpp is removed + if 'remove_vpp' in config: + return None + verify_vpp_remove_kernel_interface(config) if 'remove' in config: @@ -128,6 +136,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') # Delete interface if 'effective' in config: diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index 065a8eafb..c4068818e 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -66,6 +66,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete effective_config = conf.get_config_dict( base + [ifname], @@ -131,6 +135,10 @@ def get_config(config=None) -> dict: def verify(config): + # No need to verify anything if vpp is removed + if 'remove_vpp' in config: + return None + # Verify that removed kernel interface is not used in 'vpp kernel-interfaces'. # vpp interfaces vxlan vxlanX kernel-interface vpp-tunX # vpp kernel-interface vpp-tunX @@ -165,6 +173,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') # Delete interface if 'effective' in config: diff --git a/src/conf_mode/vpp_interfaces_xconnect.py b/src/conf_mode/vpp_interfaces_xconnect.py index c323684a3..220c1d44e 100644 --- a/src/conf_mode/vpp_interfaces_xconnect.py +++ b/src/conf_mode/vpp_interfaces_xconnect.py @@ -53,6 +53,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete effective_config = conf.get_config_dict( base + [ifname], @@ -85,7 +89,7 @@ def get_config(config=None) -> dict: def verify(config): - if 'remove' in config: + if 'remove' in config or 'remove_vpp' in config: return None # Xconnect requires 2 members @@ -110,6 +114,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') # Delete xconnect diff --git a/src/conf_mode/vpp_kernel-interfaces.py b/src/conf_mode/vpp_kernel-interfaces.py index 4e4ecb442..f9354c964 100644 --- a/src/conf_mode/vpp_kernel-interfaces.py +++ b/src/conf_mode/vpp_kernel-interfaces.py @@ -47,6 +47,10 @@ def get_config(config=None) -> dict: with_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dicitonary per interface delete if __name__ == '__main__': effective_config = conf.get_config_dict( @@ -81,7 +85,7 @@ def get_config(config=None) -> dict: def verify(config): - if 'remove' in config: + if 'remove' in config or 'remove_vpp' in config: return None # Interface must exists before it is configured @@ -96,6 +100,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + ifname = config.get('ifname') i = Interface(ifname) # update/remove addresses diff --git a/src/conf_mode/vpp_nat.py b/src/conf_mode/vpp_nat.py index a6bc70032..f8ac4f0e3 100644 --- a/src/conf_mode/vpp_nat.py +++ b/src/conf_mode/vpp_nat.py @@ -55,6 +55,10 @@ def get_config(config=None) -> dict: with_recursive_defaults=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dictionary for deletion effective_config = conf.get_config_dict( base, @@ -131,7 +135,7 @@ def convert_range_to_list_ips(address_range) -> list: def verify(config): - if 'remove' in config: + if 'remove' in config or 'remove_vpp' in config: return None if 'interface' not in config: @@ -329,6 +333,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + n = Nat44() if 'remove' in config: diff --git a/src/conf_mode/vpp_nat_cgnat.py b/src/conf_mode/vpp_nat_cgnat.py index 05260c476..68695b78e 100644 --- a/src/conf_mode/vpp_nat_cgnat.py +++ b/src/conf_mode/vpp_nat_cgnat.py @@ -41,6 +41,10 @@ def get_config(config=None) -> dict: no_tag_node_value_mangle=True, ) + if not conf.exists(['vpp']): + config['remove_vpp'] = True + return config + # Get effective config as we need full dictionary to delete effective_config = conf.get_config_dict( base, @@ -91,7 +95,7 @@ def get_config(config=None) -> dict: def verify(config): - if 'remove' in config: + if 'remove' in config or 'remove_vpp' in config: return None if 'interface' not in config: @@ -142,6 +146,9 @@ def generate(config): def apply(config): + if 'remove_vpp' in config: + return None + cgnat = Det44() if 'remove' in config: diff --git a/src/systemd/vpp-failure-handler.service b/src/systemd/vpp-failure-handler.service new file mode 100644 index 000000000..3a75f9519 --- /dev/null +++ b/src/systemd/vpp-failure-handler.service @@ -0,0 +1,9 @@ +[Unit] +Description=Restart VPP on failure + +[Service] +Type=oneshot +User=root +Group=vyattacfg +UMask=0002 +ExecStart=/usr/bin/python3 /usr/libexec/vyos/reset_section.py vpp --reload -- cgit v1.2.3 From 6801f0ef7365556d1c8eb60aeed01789a7620cb7 Mon Sep 17 00:00:00 2001 From: Viacheslav Date: Thu, 7 Aug 2025 15:43:25 +0000 Subject: T7697: Remove year from copyright --- python/vyos/vpp/__init__.py | 2 +- python/vyos/vpp/acl/acl.py | 2 +- python/vyos/vpp/config_deps.py | 2 +- python/vyos/vpp/config_filter.py | 2 +- python/vyos/vpp/config_resource_checks/cpu.py | 2 +- python/vyos/vpp/config_resource_checks/memory.py | 2 +- python/vyos/vpp/config_resource_checks/resource_defaults.py | 2 +- python/vyos/vpp/config_verify.py | 2 +- python/vyos/vpp/configdb.py | 2 +- python/vyos/vpp/control_host.py | 2 +- python/vyos/vpp/control_vpp.py | 2 +- python/vyos/vpp/interface/__init__.py | 2 +- python/vyos/vpp/interface/bond.py | 2 +- python/vyos/vpp/interface/bridge.py | 2 +- python/vyos/vpp/interface/ethernet.py | 2 +- python/vyos/vpp/interface/geneve.py | 2 +- python/vyos/vpp/interface/gre.py | 2 +- python/vyos/vpp/interface/interface.py | 2 +- python/vyos/vpp/interface/ipip.py | 2 +- python/vyos/vpp/interface/loopback.py | 2 +- python/vyos/vpp/interface/vxlan.py | 2 +- python/vyos/vpp/interface/wireguard.py | 2 +- python/vyos/vpp/interface/xconnect.py | 2 +- python/vyos/vpp/nat/det44.py | 2 +- python/vyos/vpp/nat/nat44.py | 2 +- python/vyos/vpp/utils.py | 2 +- smoketest/scripts/cli/test_vpp.py | 2 +- src/completion/list_mem_page_size.py | 2 +- src/completion/list_vpp_interfaces.py | 2 +- src/conf_mode/vpp.py | 2 +- src/conf_mode/vpp_acl.py | 2 +- src/conf_mode/vpp_interfaces_bonding.py | 2 +- src/conf_mode/vpp_interfaces_bridge.py | 2 +- src/conf_mode/vpp_interfaces_ethernet.py | 2 +- src/conf_mode/vpp_interfaces_geneve.py | 2 +- src/conf_mode/vpp_interfaces_gre.py | 2 +- src/conf_mode/vpp_interfaces_ipip.py | 2 +- src/conf_mode/vpp_interfaces_loopback.py | 2 +- src/conf_mode/vpp_interfaces_vxlan.py | 2 +- src/conf_mode/vpp_interfaces_xconnect.py | 2 +- src/conf_mode/vpp_kernel-interfaces.py | 2 +- src/conf_mode/vpp_nat.py | 2 +- src/conf_mode/vpp_nat_cgnat.py | 2 +- src/conf_mode/vpp_sflow.py | 2 +- src/op_mode/show_vpp_interfaces.py | 2 +- src/op_mode/show_vpp_nat44.py | 2 +- src/op_mode/vpp_acl.py | 2 +- src/op_mode/vpp_nat_cgnat.py | 2 +- 48 files changed, 48 insertions(+), 48 deletions(-) (limited to 'src/conf_mode/vpp_interfaces_loopback.py') diff --git a/python/vyos/vpp/__init__.py b/python/vyos/vpp/__init__.py index a320ac7d1..3352914f1 100644 --- a/python/vyos/vpp/__init__.py +++ b/python/vyos/vpp/__init__.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/acl/acl.py b/python/vyos/vpp/acl/acl.py index 9da241f1c..57d36ac91 100644 --- a/python/vyos/vpp/acl/acl.py +++ b/python/vyos/vpp/acl/acl.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/config_deps.py b/python/vyos/vpp/config_deps.py index d826dedbb..dffd865d1 100644 --- a/python/vyos/vpp/config_deps.py +++ b/python/vyos/vpp/config_deps.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2023-2024 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/config_filter.py b/python/vyos/vpp/config_filter.py index 4ab9ffda2..dc864930b 100644 --- a/python/vyos/vpp/config_filter.py +++ b/python/vyos/vpp/config_filter.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2024 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/config_resource_checks/cpu.py b/python/vyos/vpp/config_resource_checks/cpu.py index ee0bace2d..b319608e4 100644 --- a/python/vyos/vpp/config_resource_checks/cpu.py +++ b/python/vyos/vpp/config_resource_checks/cpu.py @@ -1,6 +1,6 @@ # Used for validating estimated CPU/physical cores use # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/config_resource_checks/memory.py b/python/vyos/vpp/config_resource_checks/memory.py index f8ccf7d47..bce2df2bb 100644 --- a/python/vyos/vpp/config_resource_checks/memory.py +++ b/python/vyos/vpp/config_resource_checks/memory.py @@ -1,6 +1,6 @@ # Used for memory consumption calculations # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/config_resource_checks/resource_defaults.py b/python/vyos/vpp/config_resource_checks/resource_defaults.py index 828683456..797b45701 100644 --- a/python/vyos/vpp/config_resource_checks/resource_defaults.py +++ b/python/vyos/vpp/config_resource_checks/resource_defaults.py @@ -1,6 +1,6 @@ # Default values for resource consumption checks # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/config_verify.py b/python/vyos/vpp/config_verify.py index 0e21a5a8a..1beb3141b 100644 --- a/python/vyos/vpp/config_verify.py +++ b/python/vyos/vpp/config_verify.py @@ -1,6 +1,6 @@ # Used for verifying configuration vpp interfaces # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/configdb.py b/python/vyos/vpp/configdb.py index 1830937ad..13c1cd3a0 100644 --- a/python/vyos/vpp/configdb.py +++ b/python/vyos/vpp/configdb.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2024 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/control_host.py b/python/vyos/vpp/control_host.py index 1ac004fbb..6a6b9d72f 100644 --- a/python/vyos/vpp/control_host.py +++ b/python/vyos/vpp/control_host.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/control_vpp.py b/python/vyos/vpp/control_vpp.py index 5959b68b5..596ef4f12 100644 --- a/python/vyos/vpp/control_vpp.py +++ b/python/vyos/vpp/control_vpp.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/__init__.py b/python/vyos/vpp/interface/__init__.py index 2048e07ca..903b7cbfc 100644 --- a/python/vyos/vpp/interface/__init__.py +++ b/python/vyos/vpp/interface/__init__.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/bond.py b/python/vyos/vpp/interface/bond.py index 6a96bce58..604ba2ae5 100644 --- a/python/vyos/vpp/interface/bond.py +++ b/python/vyos/vpp/interface/bond.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/bridge.py b/python/vyos/vpp/interface/bridge.py index 5ebe46d45..25f0b4660 100644 --- a/python/vyos/vpp/interface/bridge.py +++ b/python/vyos/vpp/interface/bridge.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/ethernet.py b/python/vyos/vpp/interface/ethernet.py index 368d94c7f..523211db8 100644 --- a/python/vyos/vpp/interface/ethernet.py +++ b/python/vyos/vpp/interface/ethernet.py @@ -1,6 +1,6 @@ # VyOS implementation of VPP Ethernet interface # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/geneve.py b/python/vyos/vpp/interface/geneve.py index 8260b1bfa..2d6347f12 100644 --- a/python/vyos/vpp/interface/geneve.py +++ b/python/vyos/vpp/interface/geneve.py @@ -1,6 +1,6 @@ # VyOS implementation of Geneve interface # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/gre.py b/python/vyos/vpp/interface/gre.py index 5bef280c6..bc278d2a0 100644 --- a/python/vyos/vpp/interface/gre.py +++ b/python/vyos/vpp/interface/gre.py @@ -1,6 +1,6 @@ # VyOS implementation of VPP GRE interface # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/interface.py b/python/vyos/vpp/interface/interface.py index 33dc779c2..05c1d14d6 100644 --- a/python/vyos/vpp/interface/interface.py +++ b/python/vyos/vpp/interface/interface.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/ipip.py b/python/vyos/vpp/interface/ipip.py index 4779a8292..e6ed44537 100644 --- a/python/vyos/vpp/interface/ipip.py +++ b/python/vyos/vpp/interface/ipip.py @@ -1,6 +1,6 @@ # VyOS implementation of VPP IPIP interface # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/loopback.py b/python/vyos/vpp/interface/loopback.py index d417f627d..357423780 100644 --- a/python/vyos/vpp/interface/loopback.py +++ b/python/vyos/vpp/interface/loopback.py @@ -1,6 +1,6 @@ # VyOS implementation of VPP Loopback interface # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/vxlan.py b/python/vyos/vpp/interface/vxlan.py index eacc901dc..4be5b5ec9 100644 --- a/python/vyos/vpp/interface/vxlan.py +++ b/python/vyos/vpp/interface/vxlan.py @@ -1,6 +1,6 @@ # VyOS implementation of VPP VXLAN interface # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/wireguard.py b/python/vyos/vpp/interface/wireguard.py index 649ed5b05..c2d36e1b0 100644 --- a/python/vyos/vpp/interface/wireguard.py +++ b/python/vyos/vpp/interface/wireguard.py @@ -1,6 +1,6 @@ # VyOS implementation of VPP Wireguard interface # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/interface/xconnect.py b/python/vyos/vpp/interface/xconnect.py index badece6e8..299a61405 100644 --- a/python/vyos/vpp/interface/xconnect.py +++ b/python/vyos/vpp/interface/xconnect.py @@ -1,6 +1,6 @@ # VyOS implementation of VPP bridge interface # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/nat/det44.py b/python/vyos/vpp/nat/det44.py index 1046d7cf9..70f903086 100644 --- a/python/vyos/vpp/nat/det44.py +++ b/python/vyos/vpp/nat/det44.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/nat/nat44.py b/python/vyos/vpp/nat/nat44.py index 6b02688aa..b7e2d7744 100644 --- a/python/vyos/vpp/nat/nat44.py +++ b/python/vyos/vpp/nat/nat44.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/python/vyos/vpp/utils.py b/python/vyos/vpp/utils.py index fe08a98b8..8b3a8c038 100644 --- a/python/vyos/vpp/utils.py +++ b/python/vyos/vpp/utils.py @@ -1,5 +1,5 @@ # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/smoketest/scripts/cli/test_vpp.py b/smoketest/scripts/cli/test_vpp.py index 16302adea..07b4b1b19 100755 --- a/smoketest/scripts/cli/test_vpp.py +++ b/smoketest/scripts/cli/test_vpp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/completion/list_mem_page_size.py b/src/completion/list_mem_page_size.py index 1ed81a15f..4d2cb11c6 100644 --- a/src/completion/list_mem_page_size.py +++ b/src/completion/list_mem_page_size.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public diff --git a/src/completion/list_vpp_interfaces.py b/src/completion/list_vpp_interfaces.py index ea6a77bed..e5751119c 100644 --- a/src/completion/list_vpp_interfaces.py +++ b/src/completion/list_vpp_interfaces.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2024 VyOS Inc. +# Copyright (C) VyOS Inc. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py index 0ea8d261b..4fa056a19 100755 --- a/src/conf_mode/vpp.py +++ b/src/conf_mode/vpp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_acl.py b/src/conf_mode/vpp_acl.py index d6a9150d1..cbc915226 100644 --- a/src/conf_mode/vpp_acl.py +++ b/src/conf_mode/vpp_acl.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index c9aa6276c..098cf8bed 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_bridge.py b/src/conf_mode/vpp_interfaces_bridge.py index 4272db616..64722c10c 100644 --- a/src/conf_mode/vpp_interfaces_bridge.py +++ b/src/conf_mode/vpp_interfaces_bridge.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_ethernet.py b/src/conf_mode/vpp_interfaces_ethernet.py index f56cadc3e..81050444e 100644 --- a/src/conf_mode/vpp_interfaces_ethernet.py +++ b/src/conf_mode/vpp_interfaces_ethernet.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_geneve.py b/src/conf_mode/vpp_interfaces_geneve.py index 12fac83fb..efac4e65a 100644 --- a/src/conf_mode/vpp_interfaces_geneve.py +++ b/src/conf_mode/vpp_interfaces_geneve.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index 5ec6feeb0..0b60d06b5 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index 430b7b334..e4db1e93c 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_loopback.py b/src/conf_mode/vpp_interfaces_loopback.py index 92ba110f1..8874ecf2d 100644 --- a/src/conf_mode/vpp_interfaces_loopback.py +++ b/src/conf_mode/vpp_interfaces_loopback.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index c4068818e..355139ffa 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_interfaces_xconnect.py b/src/conf_mode/vpp_interfaces_xconnect.py index 220c1d44e..994332ba2 100644 --- a/src/conf_mode/vpp_interfaces_xconnect.py +++ b/src/conf_mode/vpp_interfaces_xconnect.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_kernel-interfaces.py b/src/conf_mode/vpp_kernel-interfaces.py index f9354c964..85706094e 100644 --- a/src/conf_mode/vpp_kernel-interfaces.py +++ b/src/conf_mode/vpp_kernel-interfaces.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_nat.py b/src/conf_mode/vpp_nat.py index 2c0298902..7c9fd2765 100644 --- a/src/conf_mode/vpp_nat.py +++ b/src/conf_mode/vpp_nat.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_nat_cgnat.py b/src/conf_mode/vpp_nat_cgnat.py index 68695b78e..be2386ba2 100644 --- a/src/conf_mode/vpp_nat_cgnat.py +++ b/src/conf_mode/vpp_nat_cgnat.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/conf_mode/vpp_sflow.py b/src/conf_mode/vpp_sflow.py index ebe91617b..7da4c24d6 100644 --- a/src/conf_mode/vpp_sflow.py +++ b/src/conf_mode/vpp_sflow.py @@ -1,4 +1,4 @@ -# Copyright (C) 2025 VyOS maintainers and contributors +# Copyright 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 diff --git a/src/op_mode/show_vpp_interfaces.py b/src/op_mode/show_vpp_interfaces.py index b7c42eb58..c159ad0aa 100755 --- a/src/op_mode/show_vpp_interfaces.py +++ b/src/op_mode/show_vpp_interfaces.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2023-2024 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/op_mode/show_vpp_nat44.py b/src/op_mode/show_vpp_nat44.py index d0569ac49..500280210 100644 --- a/src/op_mode/show_vpp_nat44.py +++ b/src/op_mode/show_vpp_nat44.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/op_mode/vpp_acl.py b/src/op_mode/vpp_acl.py index 7afe96433..ed9b35ef6 100644 --- a/src/op_mode/vpp_acl.py +++ b/src/op_mode/vpp_acl.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/op_mode/vpp_nat_cgnat.py b/src/op_mode/vpp_nat_cgnat.py index 5112c70be..9a7dd2086 100644 --- a/src/op_mode/vpp_nat_cgnat.py +++ b/src/op_mode/vpp_nat_cgnat.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2025 VyOS Inc. +# Copyright (C) VyOS Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by -- cgit v1.2.3