summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2021-08-20 17:13:32 +0200
committerChristian Poessinger <christian@poessinger.com>2021-08-21 21:48:58 +0200
commit64c9fdef02323309e97b2bb682604ada52d651e8 (patch)
tree7ff06658f014454e73304c808a1b23fdd1552c93 /src
parent0d127067b692c7610b49287b11e2fde69016c70f (diff)
downloadvyos-1x-64c9fdef02323309e97b2bb682604ada52d651e8.tar.gz
vyos-1x-64c9fdef02323309e97b2bb682604ada52d651e8.zip
pppoe: T3090: migrate to vyos.ifconfig library to use the full potential
Now that MSS clamping is done on the "per-interface" level the entire PPPoE stuff would have needed to get a full copy in GNU BASH for this or, participate in the common library. Add a new PPP ip-up script named 99-vyos-pppoe-callback which will call the vyos.ifconfig.PPPoEIf.update() function to configure everything as done with all other interfaces. This removes duplicated code for VRF assignment and route installation when a PPPoE interface is brought up or down.
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/interfaces-pppoe.py93
-rwxr-xr-xsrc/etc/ppp/ip-up.d/99-vyos-pppoe-callback59
2 files changed, 113 insertions, 39 deletions
diff --git a/src/conf_mode/interfaces-pppoe.py b/src/conf_mode/interfaces-pppoe.py
index 6c4c6c95b..584adc75e 100755
--- a/src/conf_mode/interfaces-pppoe.py
+++ b/src/conf_mode/interfaces-pppoe.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2021 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
@@ -22,12 +22,16 @@ from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
+from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_authentication
from vyos.configverify import verify_source_interface
+from vyos.configverify import verify_interface_exists
from vyos.configverify import verify_vrf
from vyos.configverify import verify_mtu_ipv6
+from vyos.ifconfig import PPPoEIf
from vyos.template import render
from vyos.util import call
+from vyos.util import is_systemd_service_running
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -44,6 +48,32 @@ def get_config(config=None):
base = ['interfaces', 'pppoe']
pppoe = get_interface_dict(conf, base)
+ # We should only terminate the PPPoE session if critical parameters change.
+ # All parameters that can be changed on-the-fly (like interface description)
+ # should not lead to a reconnect!
+ tmp = leaf_node_changed(conf, ['access-concentrator'])
+ if tmp: pppoe.update({'shutdown_required': {}})
+
+ tmp = leaf_node_changed(conf, ['connect-on-demand'])
+ if tmp: pppoe.update({'shutdown_required': {}})
+
+ tmp = leaf_node_changed(conf, ['service-name'])
+ if tmp: pppoe.update({'shutdown_required': {}})
+
+ tmp = leaf_node_changed(conf, ['source-interface'])
+ if tmp: pppoe.update({'shutdown_required': {}})
+
+ tmp = leaf_node_changed(conf, ['vrf'])
+ # leaf_node_changed() returns a list, as VRF is a non-multi node, there
+ # will be only one list element
+ if tmp: pppoe.update({'vrf_old': tmp[0]})
+
+ tmp = leaf_node_changed(conf, ['authentication', 'user'])
+ if tmp: pppoe.update({'shutdown_required': {}})
+
+ tmp = leaf_node_changed(conf, ['authentication', 'password'])
+ if tmp: pppoe.update({'shutdown_required': {}})
+
return pppoe
def verify(pppoe):
@@ -66,57 +96,42 @@ def generate(pppoe):
# rendered into
ifname = pppoe['ifname']
config_pppoe = f'/etc/ppp/peers/{ifname}'
- script_pppoe_pre_up = f'/etc/ppp/ip-pre-up.d/1000-vyos-pppoe-{ifname}'
- script_pppoe_ip_up = f'/etc/ppp/ip-up.d/1000-vyos-pppoe-{ifname}'
- script_pppoe_ip_down = f'/etc/ppp/ip-down.d/1000-vyos-pppoe-{ifname}'
- script_pppoe_ipv6_up = f'/etc/ppp/ipv6-up.d/1000-vyos-pppoe-{ifname}'
- config_wide_dhcp6c = f'/run/dhcp6c/dhcp6c.{ifname}.conf'
-
- config_files = [config_pppoe, script_pppoe_pre_up, script_pppoe_ip_up,
- script_pppoe_ip_down, script_pppoe_ipv6_up, config_wide_dhcp6c]
if 'deleted' in pppoe or 'disable' in pppoe:
- # stop DHCPv6-PD client
- call(f'systemctl stop dhcp6c@{ifname}.service')
- # Hang-up PPPoE connection
- call(f'systemctl stop ppp@{ifname}.service')
-
- # Delete PPP configuration files
- for file in config_files:
- if os.path.exists(file):
- os.unlink(file)
+ if os.path.exists(config_pppoe):
+ os.unlink(config_pppoe)
return None
# Create PPP configuration files
- render(config_pppoe, 'pppoe/peer.tmpl', pppoe, permission=0o755)
-
- # Create script for ip-pre-up.d
- render(script_pppoe_pre_up, 'pppoe/ip-pre-up.script.tmpl', pppoe,
- permission=0o755)
- # Create script for ip-up.d
- render(script_pppoe_ip_up, 'pppoe/ip-up.script.tmpl', pppoe,
- permission=0o755)
- # Create script for ip-down.d
- render(script_pppoe_ip_down, 'pppoe/ip-down.script.tmpl', pppoe,
- permission=0o755)
- # Create script for ipv6-up.d
- render(script_pppoe_ipv6_up, 'pppoe/ipv6-up.script.tmpl', pppoe,
- permission=0o755)
-
- if 'dhcpv6_options' in pppoe and 'pd' in pppoe['dhcpv6_options']:
- # ipv6.tmpl relies on ifname - this should be made consitent in the
- # future better then double key-ing the same value
- render(config_wide_dhcp6c, 'dhcp-client/ipv6.tmpl', pppoe)
+ render(config_pppoe, 'pppoe/peer.tmpl', pppoe, permission=0o640)
return None
def apply(pppoe):
+ ifname = pppoe['ifname']
if 'deleted' in pppoe or 'disable' in pppoe:
- call('systemctl stop ppp@{ifname}.service'.format(**pppoe))
+ if os.path.isdir(f'/sys/class/net/{ifname}'):
+ p = PPPoEIf(ifname)
+ p.remove()
+ call(f'systemctl stop ppp@{ifname}.service')
return None
- call('systemctl restart ppp@{ifname}.service'.format(**pppoe))
+ # reconnect should only be necessary when certain config options change,
+ # like ACS name, authentication, no-peer-dns, source-interface
+ if ((not is_systemd_service_running(f'ppp@{ifname}.service')) or
+ 'shutdown_required' in pppoe):
+
+ # cleanup system (e.g. FRR routes first)
+ if os.path.isdir(f'/sys/class/net/{ifname}'):
+ p = PPPoEIf(ifname)
+ p.remove()
+
+ call(f'systemctl restart ppp@{ifname}.service')
+ else:
+ if os.path.isdir(f'/sys/class/net/{ifname}'):
+ p = PPPoEIf(ifname)
+ p.update(pppoe)
return None
diff --git a/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback b/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback
new file mode 100755
index 000000000..bb918a468
--- /dev/null
+++ b/src/etc/ppp/ip-up.d/99-vyos-pppoe-callback
@@ -0,0 +1,59 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021 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/>.
+
+# This is a Python hook script which is invoked whenever a PPPoE session goes
+# "ip-up". It will call into our vyos.ifconfig library and will then execute
+# common tasks for the PPPoE interface. The reason we have to "hook" this is
+# that we can not create a pppoeX interface in advance in linux and then connect
+# pppd to this already existing interface.
+
+from sys import argv
+from sys import exit
+
+from syslog import syslog
+from syslog import openlog
+from syslog import LOG_PID
+from syslog import LOG_INFO
+
+from vyos.configquery import ConfigTreeQuery
+from vyos.ifconfig import PPPoEIf
+from vyos.util import read_file
+
+# When the ppp link comes up, this script is called with the following
+# parameters
+# $1 the interface name used by pppd (e.g. ppp3)
+# $2 the tty device name
+# $3 the tty device speed
+# $4 the local IP address for the interface
+# $5 the remote IP address
+# $6 the parameter specified by the 'ipparam' option to pppd
+
+if (len(argv) < 7):
+ exit(1)
+
+interface = argv[6]
+dialer_pid = read_file(f'/var/run/{interface}.pid')
+
+openlog(ident=f'pppd[{dialer_pid}]', facility=LOG_INFO)
+syslog('executing ' + argv[0])
+
+conf = ConfigTreeQuery()
+pppoe = conf.get_config_dict(['interfaces', 'pppoe', argv[6]],
+ get_first_key=True, key_mangling=('-', '_'))
+pppoe['ifname'] = argv[6]
+
+p = PPPoEIf(pppoe['ifname'])
+p.update(pppoe)