summaryrefslogtreecommitdiff
path: root/src/conf_mode/vpp_kernel-interfaces.py
diff options
context:
space:
mode:
authorViacheslav Hletenko <v.gletenko@vyos.io>2025-01-07 21:54:47 +0000
committerViacheslav Hletenko <v.gletenko@vyos.io>2025-01-07 22:30:38 +0000
commitbb4427bfb4a8c03784dd6f097cbe521f561edaf4 (patch)
tree5773be78c736903e21d31eed4af31cd2e58f7096 /src/conf_mode/vpp_kernel-interfaces.py
parentdef342ffc4244e345f02685c12dc157372d5dd68 (diff)
downloadvyos-1x-bb4427bfb4a8c03784dd6f097cbe521f561edaf4.tar.gz
vyos-1x-bb4427bfb4a8c03784dd6f097cbe521f561edaf4.zip
Add vyos-vpp CLI and python3 modules
Diffstat (limited to 'src/conf_mode/vpp_kernel-interfaces.py')
-rw-r--r--src/conf_mode/vpp_kernel-interfaces.py192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/conf_mode/vpp_kernel-interfaces.py b/src/conf_mode/vpp_kernel-interfaces.py
new file mode 100644
index 000000000..4e4ecb442
--- /dev/null
+++ b/src/conf_mode/vpp_kernel-interfaces.py
@@ -0,0 +1,192 @@
+#!/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.config import Config
+from vyos.configdict import leaf_node_changed
+from vyos.configdict import node_changed
+from vyos import ConfigError
+from vyos.ifconfig import Interface
+from vyos.utils.network import interface_exists
+from vyos.utils.process import call
+from vyos.vpp import VPPControl
+
+
+def get_config(config=None) -> dict:
+ if config:
+ conf = config
+ else:
+ conf = Config()
+
+ base = ['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,
+ )
+
+ # Get effective config as we need full dicitonary per interface delete
+ if __name__ == '__main__':
+ effective_config = conf.get_config_dict(
+ base + [ifname],
+ key_mangling=('-', '_'),
+ effective=True,
+ get_first_key=True,
+ no_tag_node_value_mangle=True,
+ )
+ # if a file was started as dependency, we are starting from empty config
+ else:
+ effective_config = {}
+
+ if effective_config:
+ config.update({'effective': effective_config})
+
+ address_removed = leaf_node_changed(conf, base + [ifname, 'address'])
+ if address_removed:
+ config['address_removed'] = address_removed
+
+ description_removed = leaf_node_changed(conf, base + [ifname, 'description'])
+ if description_removed:
+ config['description_removed'] = {}
+
+ vlans_removed = node_changed(conf, base + [ifname, 'vif'])
+ if vlans_removed:
+ config['vlans_removed'] = vlans_removed
+
+ config['ifname'] = ifname
+
+ return config
+
+
+def verify(config):
+ if 'remove' in config:
+ return None
+
+ # Interface must exists before it is configured
+ if not interface_exists(config['ifname']):
+ raise ConfigError(
+ f'Interface {config["ifname"]} must be created before using in configuration'
+ )
+
+
+def generate(config):
+ pass
+
+
+def apply(config):
+ ifname = config.get('ifname')
+ i = Interface(ifname)
+ # update/remove addresses
+ if 'address_removed' in config:
+ for address in config['address_removed']:
+ i.del_addr(address)
+ # remove description
+ if 'description_removed' in config:
+ i.set_alias('')
+
+ # remove VLANs
+ if 'vlans_removed' in config:
+ for vlan in config['vlans_removed']:
+ call(f'ip link del dev {ifname}.{vlan}')
+
+ # Delete
+ if 'remove' in config:
+ pass
+ else:
+ # Add address
+ if 'address' in config:
+ for address in config['address']:
+ i.add_addr(address)
+ # Set MTU
+ if 'mtu' in config:
+ i.set_mtu(config.get('mtu'))
+ # Set description
+ if 'description' in config:
+ i.set_alias(config.get('description'))
+ # Admin state down
+ if 'disable' in config:
+ i.set_admin_state('down')
+ else:
+ i.set_admin_state('up')
+
+ for vlan, vlan_config in config.get('vif', {}).items():
+ if vlan not in config.get('effective', {}).get('vif', {}).keys():
+ call(
+ f'ip link add link {ifname} name {ifname}.{vlan} type vlan id {vlan}'
+ )
+ call(f'ip link set dev {ifname}.{vlan} up')
+ v = Interface(f'{ifname}.{vlan}')
+
+ # VLAN address
+ addresses_effective = (
+ config.get('effective', {})
+ .get('vif', {})
+ .get(vlan, {})
+ .get('address', [])
+ )
+ addresses_candidate = vlan_config.get('address', [])
+
+ for ipaddr in addresses_effective:
+ if ipaddr not in addresses_candidate:
+ v.del_addr(ipaddr)
+ for ipaddr in addresses_candidate:
+ if ipaddr not in addresses_effective:
+ v.add_addr(ipaddr)
+
+ # VLAN description
+ description_effective = (
+ config.get('effective', {})
+ .get('vif', {})
+ .get(vlan, {})
+ .get('description', '')
+ )
+ description_candidate = vlan_config.get('description', '')
+
+ if description_candidate:
+ v.set_alias(description_candidate)
+ elif description_effective and not description_candidate:
+ v.set_alias('')
+
+ v.set_admin_state('up')
+
+ # Set rx-mode
+ rx_mode = config.get('rx_mode')
+ if rx_mode:
+ vpp_control = VPPControl()
+ lcp_name = vpp_control.lcp_pair_find(kernel_name=ifname).get('vpp_name_kernel')
+ vpp_control.iface_rxmode(lcp_name, rx_mode)
+
+ return None
+
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)