summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2023-11-09 09:31:04 -0600
committerGitHub <noreply@github.com>2023-11-09 09:31:04 -0600
commitb8b3a39449a98f1ca6d3e0b6d65b59ffc3edcfab (patch)
tree304d9b91f48bd6c3dc755f8d8bdfe1ba64bd3957
parent3238cb64c53337cb5238495aba96621ee8bf9692 (diff)
parent54b4a0a50f472ece513e97365619b6a3df63f273 (diff)
downloadvyos-1x-b8b3a39449a98f1ca6d3e0b6d65b59ffc3edcfab.tar.gz
vyos-1x-b8b3a39449a98f1ca6d3e0b6d65b59ffc3edcfab.zip
Merge pull request #2463 from vyos/mergify/bp/sagitta/pr-2370
T1797: Delete VPP from vyos-1x as it is implemented in addon (backport #2370)
-rw-r--r--data/config-mode-dependencies/vyos-1x.json3
-rw-r--r--data/templates/vpp/override.conf.j214
-rw-r--r--data/templates/vpp/startup.conf.j2116
-rw-r--r--debian/vyos-1x.postinst11
-rw-r--r--interface-definitions/vpp.xml.in342
-rw-r--r--python/vyos/vpp.py315
-rwxr-xr-xsrc/conf_mode/vpp.py207
7 files changed, 0 insertions, 1008 deletions
diff --git a/data/config-mode-dependencies/vyos-1x.json b/data/config-mode-dependencies/vyos-1x.json
index 948aab3a6..37333a19c 100644
--- a/data/config-mode-dependencies/vyos-1x.json
+++ b/data/config-mode-dependencies/vyos-1x.json
@@ -34,8 +34,5 @@
"wireguard": ["interfaces-wireguard"],
"wireless": ["interfaces-wireless"],
"wwan": ["interfaces-wwan"]
- },
- "vpp": {
- "ethernet": ["interfaces-ethernet"]
}
}
diff --git a/data/templates/vpp/override.conf.j2 b/data/templates/vpp/override.conf.j2
deleted file mode 100644
index a2c2b04ed..000000000
--- a/data/templates/vpp/override.conf.j2
+++ /dev/null
@@ -1,14 +0,0 @@
-[Unit]
-After=
-After=vyos-router.service
-ConditionPathExists=
-ConditionPathExists=/run/vpp/vpp.conf
-
-[Service]
-EnvironmentFile=
-ExecStart=
-ExecStart=/usr/bin/vpp -c /run/vpp/vpp.conf
-WorkingDirectory=
-WorkingDirectory=/run/vpp
-Restart=always
-RestartSec=10
diff --git a/data/templates/vpp/startup.conf.j2 b/data/templates/vpp/startup.conf.j2
deleted file mode 100644
index f33539fba..000000000
--- a/data/templates/vpp/startup.conf.j2
+++ /dev/null
@@ -1,116 +0,0 @@
-# Generated by /usr/libexec/vyos/conf_mode/vpp.py
-
-unix {
- nodaemon
- log /var/log/vpp.log
- full-coredump
- cli-listen /run/vpp/cli.sock
- gid vpp
- # exec /etc/vpp/bootstrap.vpp
-{% if unix is vyos_defined %}
-{% if unix.poll_sleep_usec is vyos_defined %}
- poll-sleep-usec {{ unix.poll_sleep_usec }}
-{% endif %}
-{% endif %}
-}
-
-{% if cpu is vyos_defined %}
-cpu {
-{% if cpu.main_core is vyos_defined %}
- main-core {{ cpu.main_core }}
-{% endif %}
-{% if cpu.corelist_workers is vyos_defined %}
- corelist-workers {{ cpu.corelist_workers | join(',') }}
-{% endif %}
-{% if cpu.skip_cores is vyos_defined %}
- skip-cores {{ cpu.skip_cores }}
-{% endif %}
-{% if cpu.workers is vyos_defined %}
- workers {{ cpu.workers }}
-{% endif %}
-}
-{% endif %}
-
-{# ip heap-size does not work now (23.06-rc2~1-g3a4e62ad4) #}
-{# vlib_call_all_config_functions: unknown input `ip heap-size 32M ' #}
-{% if ip is vyos_defined %}
-#ip {
-#{% if ip.heap_size is vyos_defined %}
-# heap-size {{ ip.heap_size }}M
-#{% endif %}
-#}
-{% endif %}
-
-{% if ip6 is vyos_defined %}
-ip6 {
-{% if ip6.hash_buckets is vyos_defined %}
- hash-buckets {{ ip6.hash_buckets }}
-{% endif %}
-{% if ip6.heap_size is vyos_defined %}
- heap-size {{ ip6.heap_size }}M
-{% endif %}
-}
-{% endif %}
-
-{% if l2learn is vyos_defined %}
-l2learn {
-{% if l2learn.limit is vyos_defined %}
- limit {{ l2learn.limit }}
-{% endif %}
-}
-{% endif %}
-
-{% if logging is vyos_defined %}
-logging {
-{% if logging.default_log_level is vyos_defined %}
- default-log-level {{ logging.default_log_level }}
-{% endif %}
-}
-{% endif %}
-
-{% if physmem is vyos_defined %}
-physmem {
-{% if physmem.max_size is vyos_defined %}
- max-size {{ physmem.max_size.upper() }}
-{% endif %}
-}
-{% endif %}
-
-plugins {
- path /usr/lib/x86_64-linux-gnu/vpp_plugins/
- plugin default { disable }
- plugin dpdk_plugin.so { enable }
- plugin linux_cp_plugin.so { enable }
- plugin linux_nl_plugin.so { enable }
-}
-
-linux-cp {
- lcp-sync
- lcp-auto-subint
-}
-
-dpdk {
- # Whitelist the fake PCI address 0000:00:00.0
- # This prevents all devices from being added to VPP-DPDK by default
- dev 0000:00:00.0
-{% for iface, iface_config in interface.items() %}
-{% if iface_config.pci is vyos_defined %}
- dev {{ iface_config.pci }} {
- name {{ iface }}
-{% if iface_config.num_rx_desc is vyos_defined %}
- num-rx-desc {{ iface_config.num_rx_desc }}
-{% endif %}
-{% if iface_config.num_tx_desc is vyos_defined %}
- num-tx-desc {{ iface_config.num_tx_desc }}
-{% endif %}
-{% if iface_config.num_rx_queues is vyos_defined %}
- num-rx-queues {{ iface_config.num_rx_queues }}
-{% endif %}
-{% if iface_config.num_tx_queues is vyos_defined %}
- num-tx-queues {{ iface_config.num_tx_queues }}
-{% endif %}
- }
-{% endif %}
-{% endfor %}
- uio-bind-force
-}
diff --git a/debian/vyos-1x.postinst b/debian/vyos-1x.postinst
index b43416152..232600b48 100644
--- a/debian/vyos-1x.postinst
+++ b/debian/vyos-1x.postinst
@@ -204,14 +204,3 @@ systemctl enable vyos-config-cloud-init.service
# Update XML cache
python3 /usr/lib/python3/dist-packages/vyos/xml_ref/update_cache.py
-# T1797: disable VPP support for rolling release, should be used by developers
-# only (in the initial phase). If you wan't to enable VPP use the below command
-# on your VyOS installation:
-#
-# sudo mv /opt/vyatta/share/vyatta-cfg/vpp /opt/vyatta/share/vyatta-cfg/templates/vpp
-if [ -d /opt/vyatta/share/vyatta-cfg/templates/vpp ]; then
- if [ -d /opt/vyatta/share/vyatta-cfg/vpp ]; then
- rm -rf /opt/vyatta/share/vyatta-cfg/vpp
- fi
- mv /opt/vyatta/share/vyatta-cfg/templates/vpp /opt/vyatta/share/vyatta-cfg/vpp
-fi
diff --git a/interface-definitions/vpp.xml.in b/interface-definitions/vpp.xml.in
deleted file mode 100644
index 3f0758c0a..000000000
--- a/interface-definitions/vpp.xml.in
+++ /dev/null
@@ -1,342 +0,0 @@
-<?xml version="1.0"?>
-<interfaceDefinition>
- <node name="vpp" owner="${vyos_conf_scripts_dir}/vpp.py">
- <properties>
- <help>Accelerated data-plane</help>
- <priority>295</priority>
- </properties>
- <children>
- <node name="cpu">
- <properties>
- <help>CPU settings</help>
- </properties>
- <children>
- <leafNode name="corelist-workers">
- <properties>
- <help>List of cores worker threads</help>
- <valueHelp>
- <format>&lt;id&gt;</format>
- <description>CPU core id</description>
- </valueHelp>
- <valueHelp>
- <format>&lt;idN&gt;-&lt;idM&gt;</format>
- <description>CPU core id range (use '-' as delimiter)</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--allow-range --range 0-512"/>
- </constraint>
- <constraintErrorMessage>not a valid CPU core value or range</constraintErrorMessage>
- <multi/>
- </properties>
- </leafNode>
- <leafNode name="main-core">
- <properties>
- <help>Main core</help>
- <valueHelp>
- <format>u32:0-512</format>
- <description>Assign main thread to specific core</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 0-512"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="skip-cores">
- <properties>
- <help>Skip cores</help>
- <valueHelp>
- <format>u32:0-512</format>
- <description>Skip cores</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 0-512"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="workers">
- <properties>
- <help>Create worker threads</help>
- <valueHelp>
- <format>u32:0-4294967295</format>
- <description>Worker threads</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 0-512"/>
- </constraint>
- </properties>
- </leafNode>
- </children>
- </node>
- <tagNode name="interface">
- <properties>
- <help>Interface</help>
- <valueHelp>
- <format>ethN</format>
- <description>Interface name</description>
- </valueHelp>
- <constraint>
- <regex>((eth|lan)[0-9]+|(eno|ens|enp|enx).+)</regex>
- </constraint>
- <constraintErrorMessage>Invalid interface name</constraintErrorMessage>
- </properties>
- <children>
- <leafNode name="num-rx-desc">
- <properties>
- <help>Number of receive ring descriptors</help>
- <valueHelp>
- <format>u32:256-8192</format>
- <description>Number of receive ring descriptors</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 256-8192"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="num-tx-desc">
- <properties>
- <help>Number of tranceive ring descriptors</help>
- <valueHelp>
- <format>u32:256-8192</format>
- <description>Number of tranceive ring descriptors</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 256-8192"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="num-rx-queues">
- <properties>
- <help>Number of receive ring descriptors</help>
- <valueHelp>
- <format>u32:256-8192</format>
- <description>Number of receive queues</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 256-8192"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name="num-tx-queues">
- <properties>
- <help>Number of tranceive ring descriptors</help>
- <valueHelp>
- <format>u32:256-8192</format>
- <description>Number of tranceive queues</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 256-8192"/>
- </constraint>
- </properties>
- </leafNode>
- <leafNode name='pci'>
- <properties>
- <help>PCI address allocation</help>
- <valueHelp>
- <format>auto</format>
- <description>Auto detect PCI address</description>
- </valueHelp>
- <valueHelp>
- <format>&lt;xxxx:xx:xx.x&gt;</format>
- <description>Set Peripheral Component Interconnect (PCI) address</description>
- </valueHelp>
- <constraint>
- <regex>(auto|[0-9a-fA-F]{4}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}\.[0-9a-fA-F])</regex>
- </constraint>
- </properties>
- <defaultValue>auto</defaultValue>
- </leafNode>
- <leafNode name="rx-mode">
- <properties>
- <help>Receive packet processing mode</help>
- <completionHelp>
- <list>polling interrupt adaptive</list>
- </completionHelp>
- <valueHelp>
- <format>polling</format>
- <description>Constantly check for new data</description>
- </valueHelp>
- <valueHelp>
- <format>interrupt</format>
- <description>Interrupt mode</description>
- </valueHelp>
- <valueHelp>
- <format>adaptive</format>
- <description>Adaptive mode</description>
- </valueHelp>
- <constraint>
- <regex>(polling|interrupt|adaptive)</regex>
- </constraint>
- </properties>
- </leafNode>
- </children>
- </tagNode>
- <node name="ip">
- <properties>
- <help>IP settings</help>
- </properties>
- <children>
- <leafNode name="heap-size">
- <properties>
- <help>IPv4 heap size</help>
- <valueHelp>
- <format>u32:0-4294967295</format>
- <description>Amount of memory (in Mbytes) dedicated to the destination IP lookup table</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 1-4294967295"/>
- </constraint>
- </properties>
- <defaultValue>32</defaultValue>
- </leafNode>
- </children>
- </node>
- <node name="ip6">
- <properties>
- <help>IPv6 settings</help>
- </properties>
- <children>
- <leafNode name="heap-size">
- <properties>
- <help>IPv6 heap size</help>
- <valueHelp>
- <format>u32:0-4294967295</format>
- <description>Amount of memory (in Mbytes) dedicated to the destination IP lookup table</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 1-4294967295"/>
- </constraint>
- </properties>
- <defaultValue>32</defaultValue>
- </leafNode>
- <leafNode name="hash-buckets">
- <properties>
- <help>IPv6 forwarding table hash buckets</help>
- <valueHelp>
- <format>u32:1-4294967295</format>
- <description>IPv6 forwarding table hash buckets</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 1-4294967295"/>
- </constraint>
- </properties>
- <defaultValue>65536</defaultValue>
- </leafNode>
- </children>
- </node>
- <node name="l2learn">
- <properties>
- <help>Level 2 MAC address learning settings</help>
- </properties>
- <children>
- <leafNode name="limit">
- <properties>
- <help>Number of MAC addresses in the L2 FIB</help>
- <valueHelp>
- <format>u32:1-4294967295</format>
- <description>Number of concurent entries</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 1-4294967295"/>
- </constraint>
- </properties>
- <defaultValue>4194304</defaultValue>
- </leafNode>
- </children>
- </node>
- <node name="logging">
- <properties>
- <help>Loggint settings</help>
- </properties>
- <children>
- <leafNode name="default-log-level">
- <properties>
- <help>default-log-level</help>
- <completionHelp>
- <list>alert crit debug disabled emerg err info notice warn</list>
- </completionHelp>
- <valueHelp>
- <format>alert</format>
- <description>Alert</description>
- </valueHelp>
- <valueHelp>
- <format>crit</format>
- <description>Critical</description>
- </valueHelp>
- <valueHelp>
- <format>debug</format>
- <description>Debug</description>
- </valueHelp>
- <valueHelp>
- <format>disabled</format>
- <description>Disabled</description>
- </valueHelp>
- <valueHelp>
- <format>emerg</format>
- <description>Emergency</description>
- </valueHelp>
- <valueHelp>
- <format>err</format>
- <description>Error</description>
- </valueHelp>
- <valueHelp>
- <format>info</format>
- <description>Informational</description>
- </valueHelp>
- <valueHelp>
- <format>notice</format>
- <description>Notice</description>
- </valueHelp>
- <valueHelp>
- <format>warn</format>
- <description>Warning</description>
- </valueHelp>
- <constraint>
- <regex>(alert|crit|debug|disabled|emerg|err|info|notice|warn)</regex>
- </constraint>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="physmem">
- <properties>
- <help>Memory settings</help>
- </properties>
- <children>
- <leafNode name="max-size">
- <properties>
- <help>Set memory size for protectable memory allocator (pmalloc) memory space</help>
- <valueHelp>
- <format>&lt;number&gt;m</format>
- <description>Megabyte</description>
- </valueHelp>
- <valueHelp>
- <format>&lt;number&gt;g</format>
- <description>Gigabyte</description>
- </valueHelp>
- </properties>
- </leafNode>
- </children>
- </node>
- <node name="unix">
- <properties>
- <help>Unix settings</help>
- </properties>
- <children>
- <leafNode name="poll-sleep-usec">
- <properties>
- <help>Add a fixed-sleep between main loop poll</help>
- <valueHelp>
- <format>u32:0-4294967295</format>
- <description>Number of receive queues</description>
- </valueHelp>
- <constraint>
- <validator name="numeric" argument="--range 0-4294967295"/>
- </constraint>
- </properties>
- <defaultValue>0</defaultValue>
- </leafNode>
- </children>
- </node>
- </children>
- </node>
-</interfaceDefinition>
diff --git a/python/vyos/vpp.py b/python/vyos/vpp.py
deleted file mode 100644
index 76e5d29c3..000000000
--- a/python/vyos/vpp.py
+++ /dev/null
@@ -1,315 +0,0 @@
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
-#
-# This library is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2.1 of the License, or (at your option) any later version.
-#
-# This library 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
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library. If not, see <http://www.gnu.org/licenses/>.
-
-from functools import wraps
-from pathlib import Path
-from re import search as re_search, fullmatch as re_fullmatch, MULTILINE as re_M
-from subprocess import run
-from time import sleep
-
-from vpp_papi import VPPApiClient
-from vpp_papi import VPPIOError, VPPValueError
-
-
-class VPPControl:
- """Control VPP network stack
- """
-
- class _Decorators:
- """Decorators for VPPControl
- """
-
- @classmethod
- def api_call(cls, decorated_func):
- """Check if API is connected before API call
-
- Args:
- decorated_func: function to decorate
-
- Raises:
- VPPIOError: Connection to API is not established
- """
-
- @wraps(decorated_func)
- def api_safe_wrapper(cls, *args, **kwargs):
- if not cls.vpp_api_client.transport.connected:
- raise VPPIOError(2, 'VPP API is not connected')
- return decorated_func(cls, *args, **kwargs)
-
- return api_safe_wrapper
-
- @classmethod
- def check_retval(cls, decorated_func):
- """Check retval from API response
-
- Args:
- decorated_func: function to decorate
-
- Raises:
- VPPValueError: raised when retval is not 0
- """
-
- @wraps(decorated_func)
- def check_retval_wrapper(cls, *args, **kwargs):
- return_value = decorated_func(cls, *args, **kwargs)
- if not return_value.retval == 0:
- raise VPPValueError(
- f'VPP API call failed: {return_value.retval}')
- return return_value
-
- return check_retval_wrapper
-
- def __init__(self, attempts: int = 5, interval: int = 1000) -> None:
- """Create VPP API connection
-
- Args:
- attempts (int, optional): attempts to connect. Defaults to 5.
- interval (int, optional): interval between attempts in ms. Defaults to 1000.
-
- Raises:
- VPPIOError: Connection to API cannot be established
- """
- self.vpp_api_client = VPPApiClient()
- # connect with interval
- while attempts:
- try:
- attempts -= 1
- self.vpp_api_client.connect('vpp-vyos')
- break
- except (ConnectionRefusedError, FileNotFoundError) as err:
- print(f'VPP API connection timeout: {err}')
- sleep(interval / 1000)
- # raise exception if connection was not successful in the end
- if not self.vpp_api_client.transport.connected:
- raise VPPIOError(2, 'Cannot connect to VPP API')
-
- def __del__(self) -> None:
- """Disconnect from VPP API (destructor)
- """
- self.disconnect()
-
- def disconnect(self) -> None:
- """Disconnect from VPP API
- """
- if self.vpp_api_client.transport.connected:
- self.vpp_api_client.disconnect()
-
- @_Decorators.check_retval
- @_Decorators.api_call
- def cli_cmd(self, command: str):
- """Send raw CLI command
-
- Args:
- command (str): command to send
-
- Returns:
- vpp_papi.vpp_serializer.cli_inband_reply: CLI reply class
- """
- return self.vpp_api_client.api.cli_inband(cmd=command)
-
- @_Decorators.api_call
- def get_mac(self, ifname: str) -> str:
- """Find MAC address by interface name in VPP
-
- Args:
- ifname (str): interface name inside VPP
-
- Returns:
- str: MAC address
- """
- for iface in self.vpp_api_client.api.sw_interface_dump():
- if iface.interface_name == ifname:
- return iface.l2_address.mac_string
- return ''
-
- @_Decorators.api_call
- def get_sw_if_index(self, ifname: str) -> int | None:
- """Find interface index by interface name in VPP
-
- Args:
- ifname (str): interface name inside VPP
-
- Returns:
- int | None: Interface index or None (if was not fount)
- """
- for iface in self.vpp_api_client.api.sw_interface_dump():
- if iface.interface_name == ifname:
- return iface.sw_if_index
- return None
-
- @_Decorators.check_retval
- @_Decorators.api_call
- def lcp_pair_add(self, iface_name_vpp: str, iface_name_kernel: str) -> None:
- """Create LCP interface pair between VPP and kernel
-
- Args:
- iface_name_vpp (str): interface name in VPP
- iface_name_kernel (str): interface name in kernel
- """
- iface_index = self.get_sw_if_index(iface_name_vpp)
- if iface_index:
- return self.vpp_api_client.api.lcp_itf_pair_add_del(
- is_add=True,
- sw_if_index=iface_index,
- host_if_name=iface_name_kernel)
-
- @_Decorators.check_retval
- @_Decorators.api_call
- def lcp_pair_del(self, iface_name_vpp: str, iface_name_kernel: str) -> None:
- """Delete LCP interface pair between VPP and kernel
-
- Args:
- iface_name_vpp (str): interface name in VPP
- iface_name_kernel (str): interface name in kernel
- """
- iface_index = self.get_sw_if_index(iface_name_vpp)
- if iface_index:
- return self.vpp_api_client.api.lcp_itf_pair_add_del(
- is_add=False,
- sw_if_index=iface_index,
- host_if_name=iface_name_kernel)
-
- @_Decorators.check_retval
- @_Decorators.api_call
- def iface_rxmode(self, iface_name: str, rx_mode: str) -> None:
- """Set interface rx-mode in VPP
-
- Args:
- iface_name (str): interface name in VPP
- rx_mode (str): mode (polling, interrupt, adaptive)
- """
- modes_dict: dict[str, int] = {
- 'polling': 1,
- 'interrupt': 2,
- 'adaptive': 3
- }
- if rx_mode not in modes_dict:
- raise VPPValueError(f'Mode {rx_mode} is not known')
- iface_index = self.get_sw_if_index(iface_name)
- return self.vpp_api_client.api.sw_interface_set_rx_mode(
- sw_if_index=iface_index, mode=modes_dict[rx_mode])
-
- @_Decorators.api_call
- def get_pci_addr(self, ifname: str) -> str:
- """Find PCI address of interface by interface name in VPP
-
- Args:
- ifname (str): interface name inside VPP
-
- Returns:
- str: PCI address
- """
- hw_info = self.cli_cmd(f'show hardware-interfaces {ifname}').reply
-
- regex_filter = r'^\s+pci: device (?P<device>\w+:\w+) subsystem (?P<subsystem>\w+:\w+) address (?P<address>\w+:\w+:\w+\.\w+) numa (?P<numa>\w+)$'
- re_obj = re_search(regex_filter, hw_info, re_M)
-
- # return empty string if no interface or no PCI info was found
- if not hw_info or not re_obj:
- return ''
-
- address = re_obj.groupdict().get('address', '')
-
- # we need to modify address to math kernel style
- # for example: 0000:06:14.00 -> 0000:06:14.0
- address_chunks: list[str] = address.split('.')
- address_normalized: str = f'{address_chunks[0]}.{int(address_chunks[1])}'
-
- return address_normalized
-
-
-class HostControl:
- """Control Linux host
- """
-
- @staticmethod
- def pci_rescan(pci_addr: str = '') -> None:
- """Rescan PCI device by removing it and rescan PCI bus
-
- If PCI address is not defined - just rescan PCI bus
-
- Args:
- address (str, optional): PCI address of device. Defaults to ''.
- """
- if pci_addr:
- device_file = Path(f'/sys/bus/pci/devices/{pci_addr}/remove')
- if device_file.exists():
- device_file.write_text('1')
- # wait 10 seconds max until device will be removed
- attempts = 100
- while device_file.exists() and attempts:
- attempts -= 1
- sleep(0.1)
- if device_file.exists():
- raise TimeoutError(
- f'Timeout was reached for removing PCI device {pci_addr}'
- )
- else:
- raise FileNotFoundError(f'PCI device {pci_addr} does not exist')
- rescan_file = Path('/sys/bus/pci/rescan')
- rescan_file.write_text('1')
- if pci_addr:
- # wait 10 seconds max until device will be installed
- attempts = 100
- while not device_file.exists() and attempts:
- attempts -= 1
- sleep(0.1)
- if not device_file.exists():
- raise TimeoutError(
- f'Timeout was reached for installing PCI device {pci_addr}')
-
- @staticmethod
- def get_eth_name(pci_addr: str) -> str:
- """Find Ethernet interface name by PCI address
-
- Args:
- pci_addr (str): PCI address
-
- Raises:
- FileNotFoundError: no Ethernet interface was found
-
- Returns:
- str: Ethernet interface name
- """
- # find all PCI devices with eth* names
- net_devs: dict[str, str] = {}
- net_devs_dir = Path('/sys/class/net')
- regex_filter = r'^/sys/devices/pci[\w/:\.]+/(?P<pci_addr>\w+:\w+:\w+\.\w+)/[\w/:\.]+/(?P<iface_name>eth\d+)$'
- for dir in net_devs_dir.iterdir():
- real_dir: str = dir.resolve().as_posix()
- re_obj = re_fullmatch(regex_filter, real_dir)
- if re_obj:
- iface_name: str = re_obj.group('iface_name')
- iface_addr: str = re_obj.group('pci_addr')
- net_devs.update({iface_addr: iface_name})
- # match to provided PCI address and return a name if found
- if pci_addr in net_devs:
- return net_devs[pci_addr]
- # raise error if device was not found
- raise FileNotFoundError(
- f'PCI device {pci_addr} not found in ethernet interfaces')
-
- @staticmethod
- def rename_iface(name_old: str, name_new: str) -> None:
- """Rename interface
-
- Args:
- name_old (str): old name
- name_new (str): new name
- """
- rename_cmd: list[str] = [
- 'ip', 'link', 'set', name_old, 'name', name_new
- ]
- run(rename_cmd)
diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py
deleted file mode 100755
index 82c2f236e..000000000
--- a/src/conf_mode/vpp.py
+++ /dev/null
@@ -1,207 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2023 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-from psutil import virtual_memory
-
-from pathlib import Path
-from re import search as re_search, MULTILINE as re_M
-
-from vyos.config import Config
-from vyos.configdep import set_dependents, call_dependents
-from vyos.configdict import node_changed
-from vyos.ifconfig import Section
-from vyos.utils.boot import boot_configuration_complete
-from vyos.utils.process import call
-from vyos.utils.process import rc_cmd
-from vyos.utils.system import sysctl_read
-from vyos.utils.system import sysctl_apply
-from vyos.template import render
-
-from vyos import ConfigError
-from vyos import airbag
-from vyos.vpp import VPPControl
-from vyos.vpp import HostControl
-
-airbag.enable()
-
-service_name = 'vpp'
-service_conf = Path(f'/run/vpp/{service_name}.conf')
-systemd_override = '/run/systemd/system/vpp.service.d/10-override.conf'
-
-# Free memory required for VPP
-# 2 GB for hugepages + 1 GB for other services
-MIN_AVAILABLE_MEMORY: int = 3 * 1024**3
-
-
-def _get_pci_address_by_interface(iface) -> str:
- rc, out = rc_cmd(f'ethtool -i {iface}')
- # if ethtool command was successful
- if rc == 0 and out:
- regex_filter = r'^bus-info: (?P<address>\w+:\w+:\w+\.\w+)$'
- re_obj = re_search(regex_filter, out, re_M)
- # if bus-info with PCI address found
- if re_obj:
- address = re_obj.groupdict().get('address', '')
- return address
- # use VPP - maybe interface already attached to it
- vpp_control = VPPControl(attempts=20, interval=500)
- pci_addr = vpp_control.get_pci_addr(iface)
- if pci_addr:
- return pci_addr
- # raise error if PCI address was not found
- raise ConfigError(f'Cannot find PCI address for interface {iface}')
-
-
-def get_config(config=None):
- if config:
- conf = config
- else:
- conf = Config()
-
- base = ['vpp']
- base_ethernet = ['interfaces', 'ethernet']
-
- # find interfaces removed from VPP
- removed_ifaces = []
- tmp = node_changed(conf, base + ['interface'])
- if tmp:
- for removed_iface in tmp:
- pci_address: str = _get_pci_address_by_interface(removed_iface)
- removed_ifaces.append({
- 'iface_name': removed_iface,
- 'iface_pci_addr': pci_address
- })
- # add an interface to a list of interfaces that need
- # to be reinitialized after the commit
- set_dependents('ethernet', conf, removed_iface)
-
- if not conf.exists(base):
- return {'removed_ifaces': removed_ifaces}
-
- config = conf.get_config_dict(base, key_mangling=('-', '_'),
- no_tag_node_value_mangle=True,
- get_first_key=True,
- with_recursive_defaults=True)
-
- if 'interface' in config:
- for iface, iface_config in config['interface'].items():
- # add an interface to a list of interfaces that need
- # to be reinitialized after the commit
- set_dependents('ethernet', conf, iface)
-
- # Get PCI address auto
- if iface_config['pci'] == 'auto':
- config['interface'][iface]['pci'] = _get_pci_address_by_interface(iface)
-
- config['other_interfaces'] = conf.get_config_dict(base_ethernet, key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
-
- if removed_ifaces:
- config['removed_ifaces'] = removed_ifaces
-
- return config
-
-
-def verify(config):
- # bail out early - looks like removal from running config
- if not config or (len(config) == 1 and 'removed_ifaces' in config):
- return None
-
- if 'interface' not in config:
- raise ConfigError('"interface" is required but not set!')
-
- if 'cpu' in config:
- if 'corelist_workers' in config['cpu'] and 'main_core' not in config[
- 'cpu']:
- raise ConfigError('"cpu main-core" is required but not set!')
-
- memory_available: int = virtual_memory().available
- if memory_available < MIN_AVAILABLE_MEMORY:
- raise ConfigError(
- 'Not enough free memory to start VPP:\n'
- f'available: {round(memory_available / 1024**3, 1)}GB\n'
- f'required: {round(MIN_AVAILABLE_MEMORY / 1024**3, 1)}GB')
-
-
-def generate(config):
- if not config or (len(config) == 1 and 'removed_ifaces' in config):
- # Remove old config and return
- service_conf.unlink(missing_ok=True)
- return None
-
- render(service_conf, 'vpp/startup.conf.j2', config)
- render(systemd_override, 'vpp/override.conf.j2', config)
-
- # apply default sysctl values from
- # https://github.com/FDio/vpp/blob/v23.06/src/vpp/conf/80-vpp.conf
- sysctl_config: dict[str, str] = {
- 'vm.nr_hugepages': '1024',
- 'vm.max_map_count': '3096',
- 'vm.hugetlb_shm_group': '0',
- 'kernel.shmmax': '2147483648'
- }
- # we do not want to reduce `kernel.shmmax`
- kernel_shmnax_current: str = sysctl_read('kernel.shmmax')
- if int(kernel_shmnax_current) > int(sysctl_config['kernel.shmmax']):
- sysctl_config['kernel.shmmax'] = kernel_shmnax_current
-
- if not sysctl_apply(sysctl_config):
- raise ConfigError('Cannot configure sysctl parameters for VPP')
-
- return None
-
-
-def apply(config):
- if not config or (len(config) == 1 and 'removed_ifaces' in config):
- call(f'systemctl stop {service_name}.service')
- else:
- call('systemctl daemon-reload')
- call(f'systemctl restart {service_name}.service')
-
- # Initialize interfaces removed from VPP
- for iface in config.get('removed_ifaces', []):
- host_control = HostControl()
- # rescan PCI to use a proper driver
- host_control.pci_rescan(iface['iface_pci_addr'])
- # rename to the proper name
- iface_new_name: str = host_control.get_eth_name(iface['iface_pci_addr'])
- host_control.rename_iface(iface_new_name, iface['iface_name'])
-
- if 'interface' in config:
- # connect to VPP
- # must be performed multiple attempts because API is not available
- # immediately after the service restart
- vpp_control = VPPControl(attempts=20, interval=500)
- for iface, _ in config['interface'].items():
- # Create lcp
- if iface not in Section.interfaces():
- vpp_control.lcp_pair_add(iface, iface)
-
- # reinitialize interfaces, but not during the first boot
- if boot_configuration_complete():
- call_dependents()
-
-
-if __name__ == '__main__':
- try:
- c = get_config()
- verify(c)
- generate(c)
- apply(c)
- except ConfigError as e:
- print(e)
- exit(1)