summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNataliia Solomko <natalirs1985@gmail.com>2025-09-15 19:12:04 +0300
committerNataliia Solomko <natalirs1985@gmail.com>2025-09-17 17:49:45 +0300
commit03ded6c071b9bfee98c7ccf3983be56f0ad98c4f (patch)
treefb4a131462fb3845982f9aa5c2158a07798368a5 /src
parent4669748ca1b39dc0cb54496d5ce695d05c8431f7 (diff)
downloadvyos-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-xsrc/conf_mode/service_pppoe-server.py73
-rwxr-xr-xsrc/conf_mode/vpp.py33
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