diff options
| author | Nataliia Solomko <natalirs1985@gmail.com> | 2025-09-15 19:12:04 +0300 |
|---|---|---|
| committer | Nataliia Solomko <natalirs1985@gmail.com> | 2025-09-17 17:49:45 +0300 |
| commit | 03ded6c071b9bfee98c7ccf3983be56f0ad98c4f (patch) | |
| tree | fb4a131462fb3845982f9aa5c2158a07798368a5 /src | |
| parent | 4669748ca1b39dc0cb54496d5ce695d05c8431f7 (diff) | |
| download | vyos-1x-03ded6c071b9bfee98c7ccf3983be56f0ad98c4f.tar.gz vyos-1x-03ded6c071b9bfee98c7ccf3983be56f0ad98c4f.zip | |
T7796: PPPoE-server add mapping in vpp if vpp-cp is enabled
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/service_pppoe-server.py | 73 | ||||
| -rwxr-xr-x | src/conf_mode/vpp.py | 33 |
2 files changed, 101 insertions, 5 deletions
diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py index d910e770d..bfa475b95 100755 --- a/src/conf_mode/service_pppoe-server.py +++ b/src/conf_mode/service_pppoe-server.py @@ -21,6 +21,7 @@ from sys import exit from vyos.config import Config from vyos.configdict import get_accel_dict from vyos.configdict import is_node_changed +from vyos.configdiff import get_config_diff, Diff from vyos.configverify import verify_interface_exists from vyos.template import render from vyos.utils.process import call @@ -32,6 +33,7 @@ from vyos.accel_ppp_util import verify_accel_ppp_ip_pool from vyos.accel_ppp_util import get_pools_in_order from vyos import ConfigError from vyos import airbag +from vyos.vpp.control_vpp import VPPControl airbag.enable() @@ -54,12 +56,40 @@ def get_config(config=None): else: conf = Config() base = ['service', 'pppoe-server'] - if not conf.exists(base): - return None # retrieve common dictionary keys pppoe = get_accel_dict(conf, base, pppoe_chap_secrets) + if conf.exists(['vpp']): + pppoe['vpp_config'] = conf.get_config_dict( + ['vpp'], + key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True, + ) + + diff = get_config_diff(conf) + node_diff = diff.get_child_nodes_diff( + base + ['interface'], expand_nodes=Diff.DELETE, recursive=True + ) + + pppoe['vpp_cp_interfaces'] = { + 'add': [ + ifname + for ifname, iface_conf in pppoe.get('interface', {}).items() + if 'vpp_cp' in iface_conf + ], + 'delete': [ + iface + for iface, iface_config in node_diff.get('delete').items() + if 'vpp-cp' in iface_config + ], + } + + if not conf.exists(base): + pppoe['remove'] = True + return pppoe + if dict_search('client_ip_pool', pppoe): # Multiple named pools require ordered values T5099 pppoe['ordered_named_pools'] = get_pools_in_order(dict_search('client_ip_pool', pppoe)) @@ -110,7 +140,7 @@ def verify_pado_delay(pppoe): ) def verify(pppoe): - if not pppoe: + if 'remove' in pppoe: return None verify_accel_ppp_authentication(pppoe) @@ -129,11 +159,28 @@ def verify(pppoe): if 'vlan_mon' in interface_config and not 'vlan' in interface_config: raise ConfigError('Option "vlan-mon" requires "vlan" to be set!') + vpp_cp_interfaces = pppoe.get('vpp_cp_interfaces', {}).get('add', []) + if vpp_cp_interfaces: + try: + vpp = VPPControl() + except Exception: + raise ConfigError( + 'PPPoE control-plane integration with VPP is enabled on ' + f'interface(s) {", ".join(vpp_cp_interfaces)} ' + 'but VPP service was not started' + ) + + for iface in vpp_cp_interfaces: + if vpp.get_sw_if_index(iface) is None: + raise ConfigError( + f'{iface} should be a VPP interface for control-plane integration' + ) + return None def generate(pppoe): - if not pppoe: + if 'remove' in pppoe: return None render(pppoe_conf, 'accel-ppp/pppoe.config.j2', pppoe) @@ -146,7 +193,15 @@ def generate(pppoe): def apply(pppoe): systemd_service = 'accel-ppp@pppoe.service' - if not pppoe: + + # delete pppoe mapping in vpp + vpp_cp_ifaces_delete = pppoe.get('vpp_cp_interfaces', {}).get('delete', []) + if 'vpp_config' in pppoe and vpp_cp_ifaces_delete: + vpp = VPPControl() + for iface in vpp_cp_ifaces_delete: + vpp.map_pppoe_interface(iface, is_add=False) + + if 'remove' in pppoe: call(f'systemctl stop {systemd_service}') for file in [pppoe_conf, pppoe_chap_secrets]: if os.path.exists(file): @@ -158,6 +213,14 @@ def apply(pppoe): else: call(f'systemctl reload-or-restart {systemd_service}') + # add pppoe mapping in vpp + vpp_cp_ifaces_add = pppoe.get('vpp_cp_interfaces', {}).get('add', []) + if vpp_cp_ifaces_add: + vpp = VPPControl() + for iface in vpp_cp_ifaces_add: + vpp.map_pppoe_interface(iface, is_add=True) + + if __name__ == '__main__': try: c = get_config() diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py index dc9ba1507..492fa92da 100755 --- a/src/conf_mode/vpp.py +++ b/src/conf_mode/vpp.py @@ -229,11 +229,25 @@ def get_config(config=None): if conf.exists(['vpp', 'acl']): set_dependents('vpp_acl', conf) + # Get interfaces that are used in PPPoe for control-plane integration + pppoe_conf = conf.get_config_dict( + ['service', 'pppoe-server'], + key_mangling=('-', '_'), + get_first_key=True, + no_tag_node_value_mangle=True, + ) + pppoe_map_ifaces = [ + ifname + for ifname, iface_conf in pppoe_conf.get('interface', {}).items() + if 'vpp_cp' in iface_conf + ] + if not conf.exists(base): return { 'removed_ifaces': removed_ifaces, 'xconn_members': xconn_members, 'persist_config': eth_ifaces_persist, + **({'pppoe_ifaces': pppoe_map_ifaces} if pppoe_map_ifaces else {}), } config = conf.get_config_dict( @@ -372,6 +386,11 @@ def get_config(config=None): eth_ifaces_persist[iface]['bus_id'] = control_host.get_bus_name(iface) eth_ifaces_persist[iface]['dev_id'] = control_host.get_dev_id(iface) + # PPPoE dependency + if pppoe_map_ifaces: + config['pppoe_ifaces'] = pppoe_map_ifaces + set_dependents('pppoe_server', conf) + # Return to config dictionary config['persist_config'] = eth_ifaces_persist @@ -379,6 +398,20 @@ def get_config(config=None): def verify(config): + # Cannot remove interface if PPPoE control-plane is still enabled + removed_ifaces = [iface['iface_name'] for iface in config.get('removed_ifaces', [])] + pppoe_removed_ifaces = [ + p + for p in config.get('pppoe_ifaces', []) + for r in removed_ifaces + if p == r or p.startswith(f'{r}.') + ] + if pppoe_removed_ifaces: + raise ConfigError( + f'{", ".join(pppoe_removed_ifaces)} still in use by the PPPoE server. ' + 'Disable PPPoE control-plane integration with VPP before proceeding.' + ) + # bail out early - looks like removal from running config if not config or ('removed_ifaces' in config and 'settings' not in config): return None |
