summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorViacheslav Hletenko <v.gletenko@vyos.io>2023-06-26 11:24:01 +0000
committerViacheslav Hletenko <v.gletenko@vyos.io>2023-06-27 10:54:04 +0000
commit8f402c2ba47ed3ccbf94f9f037ec6e18d6b975ea (patch)
tree7c375531f875abbea9236e8f1bc2d29f4da93eb6 /src
parent3f197566f957cb0e354a474bccee0aefd62b33be (diff)
downloadvyos-1x-8f402c2ba47ed3ccbf94f9f037ec6e18d6b975ea.tar.gz
vyos-1x-8f402c2ba47ed3ccbf94f9f037ec6e18d6b975ea.zip
T1797: Add initial vpp configuration
Add initial configuration mode for VPP (PoC) set vpp cpu corelist-workers '2' set vpp cpu main-core '1' set vpp interface eth1 num-rx-desc '256' set vpp interface eth1 num-rx-queues '512' set vpp interface eth1 num-tx-desc '256' set vpp interface eth1 num-tx-queues '512' set vpp interface eth1 pci '0000:02:00.0' set vpp interface eth1 rx-mode 'polling' set vpp interface eth2 pci '0000:08:00.0' Limitation: - 'set vpp interface ethX pci auto' works only per first commit, then interface detached from default stack and creates tun interface 'ethX' to communicate with default stack. In this case we can't get PCI address via ethtool for 'tun' interfaces. But we can set pci address manualy. - Interface sync between default stack and VPP-DPDK stack After vpp change it doesn't trigger iproute2 for changes (should be written later) I.e. if we change something in vpp per each commit it restarts vpp.service it gets empty interface config as we don't configure vpp directly and it should be configured via iproute2 But then if we do any change on interface (for example description) it gets IP address, MTU, state, etc.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/vpp.py145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py
new file mode 100755
index 000000000..aa6c14e89
--- /dev/null
+++ b/src/conf_mode/vpp.py
@@ -0,0 +1,145 @@
+#!/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/>.
+
+
+from pathlib import Path
+
+from vyos.config import Config
+from vyos.configdict import dict_merge
+from vyos.ifconfig import Section
+from vyos.ifconfig import EthernetIf
+from vyos.ifconfig import interface
+from vyos.util import call
+from vyos.util import rc_cmd
+from vyos.template import render
+from vyos.xml import defaults
+
+from vyos import ConfigError
+from vyos import vpp
+from vyos import airbag
+
+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'
+
+
+def _get_pci_address_by_interface(iface):
+ from vyos.util import rc_cmd
+ rc, out = rc_cmd(f'ethtool -i {iface}')
+ if rc == 0:
+ output_lines = out.split('\n')
+ for line in output_lines:
+ if 'bus-info' in line:
+ return line.split(None, 1)[1].strip()
+
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+
+ base = ['vpp']
+ base_ethernet = ['interfaces', 'ethernet']
+ if not conf.exists(base):
+ return None
+
+ config = conf.get_config_dict(base,
+ get_first_key=True,
+ key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True)
+
+ # We have gathered the dict representation of the CLI, but there are default
+ # options which we need to update into the dictionary retrived.
+ default_values = defaults(base)
+ if 'interface' in default_values:
+ del default_values['interface']
+ config = dict_merge(default_values, config)
+
+ if 'interface' in config:
+ for iface, iface_config in config['interface'].items():
+ default_values_iface = defaults(base + ['interface'])
+ config['interface'][iface] = dict_merge(default_values_iface, config['interface'][iface])
+
+ # Get PCI address auto
+ for iface, iface_config in config['interface'].items():
+ 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)
+
+ return config
+
+
+def verify(config):
+ # bail out early - looks like removal from running config
+ if not config:
+ return None
+
+ if 'interface' not in config:
+ raise ConfigError(f'"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(f'"cpu main-core" is required but not set!')
+
+
+def generate(config):
+ if not 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)
+
+ return None
+
+
+def apply(config):
+ if not config:
+ print(f'systemctl stop {service_name}.service')
+ call(f'systemctl stop {service_name}.service')
+ return
+ else:
+ print(f'systemctl restart {service_name}.service')
+ call(f'systemctl restart {service_name}.service')
+
+ call('systemctl daemon-reload')
+
+ call('sudo sysctl -w vm.nr_hugepages=4096')
+ for iface, _ in config['interface'].items():
+ # Create lcp
+ if iface not in Section.interfaces():
+ vpp.lcp_create_host_interface(iface)
+
+ # update interface config
+ #e = EthernetIf(iface)
+ #e.update(config['other_interfaces'][iface])
+
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)