summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/dhcpv6_relay.py94
-rwxr-xr-xsrc/conf_mode/dhcpv6_server.py2
-rwxr-xr-xsrc/conf_mode/nat.py2
-rwxr-xr-xsrc/conf_mode/protocols_igmp.py5
-rwxr-xr-xsrc/conf_mode/protocols_isis.py39
-rwxr-xr-xsrc/conf_mode/protocols_mpls.py36
-rwxr-xr-xsrc/conf_mode/protocols_pim.py5
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py67
-rwxr-xr-xsrc/op_mode/lldp_op.py96
-rw-r--r--src/systemd/isc-dhcp-relay6.service8
10 files changed, 210 insertions, 144 deletions
diff --git a/src/conf_mode/dhcpv6_relay.py b/src/conf_mode/dhcpv6_relay.py
index d4212b8be..cf8a26674 100755
--- a/src/conf_mode/dhcpv6_relay.py
+++ b/src/conf_mode/dhcpv6_relay.py
@@ -17,90 +17,84 @@
import os
from sys import exit
-from copy import deepcopy
from vyos.config import Config
-from vyos import ConfigError
-from vyos.util import call
+from vyos.configdict import dict_merge
+from vyos.ifconfig import Interface
from vyos.template import render
-
+from vyos.util import call
+from vyos.util import dict_search
+from vyos.validate import is_ipv6_link_local
+from vyos.xml import defaults
+from vyos import ConfigError
from vyos import airbag
airbag.enable()
-config_file = r'/run/dhcp-relay/dhcpv6.conf'
-
-default_config_data = {
- 'listen_addr': [],
- 'upstream_addr': [],
- 'options': [],
-}
+config_file = '/run/dhcp-relay/dhcrelay6.conf'
def get_config(config=None):
- relay = deepcopy(default_config_data)
if config:
conf = config
else:
conf = Config()
- if not conf.exists('service dhcpv6-relay'):
+ base = ['service', 'dhcpv6-relay']
+ if not conf.exists(base):
return None
- else:
- conf.set_level('service dhcpv6-relay')
-
- # Network interfaces/address to listen on for DHCPv6 query(s)
- if conf.exists('listen-interface'):
- interfaces = conf.list_nodes('listen-interface')
- for intf in interfaces:
- if conf.exists('listen-interface {0} address'.format(intf)):
- addr = conf.return_value('listen-interface {0} address'.format(intf))
- listen = addr + '%' + intf
- relay['listen_addr'].append(listen)
-
- # Upstream interface/address for remote DHCPv6 server
- if conf.exists('upstream-interface'):
- interfaces = conf.list_nodes('upstream-interface')
- for intf in interfaces:
- addresses = conf.return_values('upstream-interface {0} address'.format(intf))
- for addr in addresses:
- server = addr + '%' + intf
- relay['upstream_addr'].append(server)
-
- # Maximum hop count. When forwarding packets, dhcrelay discards packets
- # which have reached a hop count of COUNT. Default is 10. Maximum is 255.
- if conf.exists('max-hop-count'):
- count = '-c ' + conf.return_value('max-hop-count')
- relay['options'].append(count)
-
- if conf.exists('use-interface-id-option'):
- relay['options'].append('-I')
+
+ relay = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=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)
+ relay = dict_merge(default_values, relay)
return relay
def verify(relay):
# bail out early - looks like removal from running config
- if relay is None:
+ if not relay:
return None
- if len(relay['listen_addr']) == 0 or len(relay['upstream_addr']) == 0:
- raise ConfigError('Must set at least one listen and upstream interface addresses.')
+ if 'upstream_interface' not in relay:
+ raise ConfigError('At least one upstream interface required!')
+ for interface, config in relay['upstream_interface'].items():
+ if 'address' not in config:
+ raise ConfigError('DHCPv6 server required for upstream ' \
+ f'interface {interface}!')
+
+ if 'listen_interface' not in relay:
+ raise ConfigError('At least one listen interface required!')
+
+ # DHCPv6 relay requires at least one global unicat address assigned to the
+ # interface
+ for interface in relay['listen_interface']:
+ has_global = False
+ for addr in Interface(interface).get_addr():
+ if not is_ipv6_link_local(addr.split('/')[0]):
+ has_global = True
+ if not has_global:
+ raise ConfigError(f'Interface {interface} does not have global '\
+ 'IPv6 address assigned!')
return None
def generate(relay):
# bail out early - looks like removal from running config
- if relay is None:
+ if not relay:
return None
- render(config_file, 'dhcpv6-relay/config.tmpl', relay)
+ render(config_file, 'dhcp-relay/dhcrelay6.conf.tmpl', relay)
return None
def apply(relay):
- if relay is not None:
- call('systemctl restart isc-dhcp-relay6.service')
- else:
+ # bail out early - looks like removal from running config
+ if not relay:
# DHCPv6 relay support is removed in the commit
call('systemctl stop isc-dhcp-relay6.service')
if os.path.exists(config_file):
os.unlink(config_file)
+ return None
+
+ call('systemctl restart isc-dhcp-relay6.service')
return None
diff --git a/src/conf_mode/dhcpv6_server.py b/src/conf_mode/dhcpv6_server.py
index c2868e078..db248de50 100755
--- a/src/conf_mode/dhcpv6_server.py
+++ b/src/conf_mode/dhcpv6_server.py
@@ -390,7 +390,7 @@ def generate(dhcpv6):
if not dhcpv6 or dhcpv6['disabled']:
return None
- render(config_file, 'dhcpv6-server/dhcpdv6.conf.tmpl', dhcpv6)
+ render(config_file, 'dhcp-server/dhcpdv6.conf.tmpl', dhcpv6)
return None
def apply(dhcpv6):
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index f5c023b81..1ccec3d2e 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -130,7 +130,7 @@ def verify(nat):
# no need to verify the CLI as NAT is going to be deactivated
return None
- if nat['helper_functions']:
+ if 'helper_functions' in nat:
if not (nat['pre_ct_ignore'] or nat['pre_ct_conntrack'] or nat['out_ct_ignore'] or nat['out_ct_conntrack']):
raise Exception('could not determine nftable ruleset handlers')
diff --git a/src/conf_mode/protocols_igmp.py b/src/conf_mode/protocols_igmp.py
index 8606e7364..28d560d03 100755
--- a/src/conf_mode/protocols_igmp.py
+++ b/src/conf_mode/protocols_igmp.py
@@ -28,6 +28,9 @@ from signal import SIGTERM
from vyos import airbag
airbag.enable()
+# Required to use the full path to pimd, in another case daemon will not be started
+pimd_cmd = f'/usr/lib/frr/pimd -d -F traditional --daemon -A 127.0.0.1'
+
config_file = r'/tmp/igmp.frr'
def get_config(config=None):
@@ -115,7 +118,7 @@ def apply(igmp):
pim_pid = process_named_running('pimd')
if igmp['igmp_conf'] or igmp['pim_conf']:
if not pim_pid:
- call(f'pimd -d -F traditional --daemon -A 127.0.0.1')
+ call(pimd_cmd)
if os.path.exists(config_file):
call(f'vtysh -d pimd -f {config_file}')
diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py
index df03fd990..97ab79583 100755
--- a/src/conf_mode/protocols_isis.py
+++ b/src/conf_mode/protocols_isis.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2017-2020 VyOS maintainers and contributors
+# Copyright (C) 2020 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
@@ -28,8 +28,6 @@ from vyos import frr
from vyos import airbag
airbag.enable()
-config_file = r'/tmp/isis.frr'
-
def get_config(config=None):
if config:
conf = config
@@ -39,13 +37,6 @@ def get_config(config=None):
isis = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # determine which members have been removed
- for instance in isis:
- conf.set_level(base + [instance])
- tmp = node_changed(conf, ['interface'])
- if tmp:
- isis[instance].update({'interface_remove': tmp})
-
return isis
def verify(isis):
@@ -106,9 +97,6 @@ def generate(isis):
process = list(isis.keys())[0]
isis[process]['process'] = process
- # render(config) not needed, its only for debug
- render(config_file, 'frr/isis.frr.tmpl', isis[process])
-
isis['new_frr_config'] = render_to_string('frr/isis.frr.tmpl',
isis[process])
@@ -116,24 +104,27 @@ def generate(isis):
def apply(isis):
# Save original configuration prior to starting any commit actions
- frr_cfg = {}
- frr_cfg['original_config'] = frr.get_configuration(daemon='isisd')
- frr_cfg['modified_config'] = frr.replace_section(frr_cfg['original_config'], isis['new_frr_config'], from_re='router isis .*')
+ frr_cfg = frr.FRRConfig()
+ frr_cfg.load_configuration(daemon='isisd')
+ frr_cfg.modify_section(r'interface \S+', '')
+ frr_cfg.modify_section(f'router isis \S+', '')
+ frr_cfg.add_before(r'(ip prefix-list .*|route-map .*|line vty)', isis['new_frr_config'])
+ frr_cfg.commit_configuration(daemon='isisd')
+
+ # If FRR config is blank, rerun the blank commit x times due to frr-reload
+ # behavior/bug not properly clearing out on one commit.
+ if isis['new_frr_config'] == '':
+ for a in range(5):
+ frr_cfg.commit_configuration(daemon='isisd')
# Debugging
+ '''
print('')
print('--------- DEBUGGING ----------')
print(f'Existing config:\n{frr_cfg["original_config"]}\n\n')
print(f'Replacement config:\n{isis["new_frr_config"]}\n\n')
print(f'Modified config:\n{frr_cfg["modified_config"]}\n\n')
-
- # FRR mark configuration will test for syntax errors and throws an
- # exception if any syntax errors is detected
- frr.mark_configuration(frr_cfg['modified_config'])
-
- # Commit resulting configuration to FRR, this will throw CommitError
- # on failure
- frr.reload_configuration(frr_cfg['modified_config'], daemon='isisd')
+ '''
return None
diff --git a/src/conf_mode/protocols_mpls.py b/src/conf_mode/protocols_mpls.py
index 791b18110..3b27608da 100755
--- a/src/conf_mode/protocols_mpls.py
+++ b/src/conf_mode/protocols_mpls.py
@@ -18,11 +18,13 @@ import os
from sys import exit
+from glob import glob
from vyos.config import Config
from vyos.configdict import node_changed
from vyos.template import render_to_string
from vyos.util import call
from vyos.util import dict_search
+from vyos.util import read_file
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -118,22 +120,28 @@ def apply(mpls):
# Enable and disable MPLS processing on interfaces per configuration
if 'interface' in mpls:
system_interfaces = []
- system_interfaces.append(((os.popen('sysctl net.mpls.conf').read()).split('\n')))
- del system_interfaces[0][-1]
- for configured_interface in mpls['interface']:
- for system_interface in system_interfaces[0]:
- if configured_interface in system_interface:
- call(f'sysctl -wq net.mpls.conf.{configured_interface}.input=1')
- elif system_interface.endswith(' = 1'):
- system_interface = system_interface.replace(' = 1', '=0')
- call(f'sysctl -wq {system_interface}')
+ # Populate system interfaces list with local MPLS capable interfaces
+ for interface in glob('/proc/sys/net/mpls/conf/*'):
+ system_interfaces.append(os.path.basename(interface))
+ # This is where the comparison is done on if an interface needs to be enabled/disabled.
+ for system_interface in system_interfaces:
+ interface_state = read_file(f'/proc/sys/net/mpls/conf/{system_interface}/input')
+ if '1' in interface_state:
+ if system_interface not in mpls['interface']:
+ system_interface = system_interface.replace('.', '/')
+ call(f'sysctl -wq net.mpls.conf.{system_interface}.input=0')
+ elif '0' in interface_state:
+ if system_interface in mpls['interface']:
+ system_interface = system_interface.replace('.', '/')
+ call(f'sysctl -wq net.mpls.conf.{system_interface}.input=1')
else:
- # If MPLS interfaces are not configured, set MPLS processing disabled
system_interfaces = []
- system_interfaces.append(((os.popen('sysctl net.mpls.conf').read()).replace(" = 1", "=0")).split('\n'))
- del system_interfaces[0][-1]
- for interface in (system_interfaces[0]):
- call(f'sysctl -wq {interface}')
+ # If MPLS interfaces are not configured, set MPLS processing disabled
+ for interface in glob('/proc/sys/net/mpls/conf/*'):
+ system_interfaces.append(os.path.basename(interface))
+ for system_interface in system_interfaces:
+ system_interface = system_interface.replace('.', '/')
+ call(f'sysctl -wq net.mpls.conf.{system_interface}.input=0')
return None
diff --git a/src/conf_mode/protocols_pim.py b/src/conf_mode/protocols_pim.py
index 8a9f034d5..df2e6f941 100755
--- a/src/conf_mode/protocols_pim.py
+++ b/src/conf_mode/protocols_pim.py
@@ -28,6 +28,9 @@ from signal import SIGTERM
from vyos import airbag
airbag.enable()
+# Required to use the full path to pimd, in another case daemon will not be started
+pimd_cmd = f'/usr/lib/frr/pimd -d -F traditional --daemon -A 127.0.0.1'
+
config_file = r'/tmp/pimd.frr'
def get_config(config=None):
@@ -142,7 +145,7 @@ def apply(pim):
pim_pid = process_named_running('pimd')
if pim['igmp_conf'] or pim['pim_conf']:
if not pim_pid:
- call(f'pimd -d -F traditional --daemon -A 127.0.0.1')
+ call(pimd_cmd)
if os.path.exists(config_file):
call("vtysh -d pimd -f " + config_file)
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
new file mode 100755
index 000000000..969266c30
--- /dev/null
+++ b/src/conf_mode/vpn_ipsec.py
@@ -0,0 +1,67 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2020 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/>.
+
+import os
+
+from sys import exit
+
+from vyos.config import Config
+from vyos.template import render
+from vyos.util import call
+from vyos.util import dict_search
+from vyos import ConfigError
+from vyos import airbag
+from pprint import pprint
+airbag.enable()
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+ base = ['vpn', 'nipsec']
+ if not conf.exists(base):
+ return None
+
+ # retrieve common dictionary keys
+ ipsec = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ return ipsec
+
+def verify(ipsec):
+ if not ipsec:
+ return None
+
+def generate(ipsec):
+ if not ipsec:
+ return None
+
+ return ipsec
+
+def apply(ipsec):
+ if not ipsec:
+ return None
+
+ pprint(ipsec)
+
+if __name__ == '__main__':
+ try:
+ c = get_config()
+ verify(c)
+ generate(c)
+ apply(c)
+ except ConfigError as e:
+ print(e)
+ exit(1)
diff --git a/src/op_mode/lldp_op.py b/src/op_mode/lldp_op.py
index fa19e7d45..731e71891 100755
--- a/src/op_mode/lldp_op.py
+++ b/src/op_mode/lldp_op.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019 VyOS maintainers and contributors
+# Copyright (C) 2019-2020 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
@@ -45,47 +45,51 @@ Device ID Local Proto Cap Platform Port ID
def get_neighbors():
return cmd('/usr/sbin/lldpcli -f json show neighbors')
-def parse_data(data):
+def parse_data(data, interface):
output = []
- for local_if, values in data.items():
- for chassis, c_value in values.get('chassis', {}).items():
- capabilities = c_value['capability']
- if isinstance(capabilities, dict):
- capabilities = [capabilities]
-
- cap = ''
- for capability in capabilities:
- if capability['enabled']:
- if capability['type'] == 'Router':
- cap += 'R'
- if capability['type'] == 'Bridge':
- cap += 'B'
- if capability['type'] == 'Wlan':
- cap += 'W'
- if capability['type'] == 'Station':
- cap += 'S'
- if capability['type'] == 'Repeater':
- cap += 'r'
- if capability['type'] == 'Telephone':
- cap += 'T'
- if capability['type'] == 'Docsis':
- cap += 'D'
- if capability['type'] == 'Other':
- cap += 'O'
-
-
- remote_if = 'Unknown'
- if 'descr' in values.get('port', {}):
- remote_if = values.get('port', {}).get('descr')
- elif 'id' in values.get('port', {}):
- remote_if = values.get('port', {}).get('id').get('value', 'Unknown')
-
- output.append({local_if: {'chassis': chassis,
- 'remote_if': remote_if,
- 'proto': values.get('via','Unknown'),
- 'platform': c_value.get('descr', 'Unknown'),
- 'capabilities': cap}})
-
+ if not isinstance(data, list):
+ data = [data]
+
+ for neighbor in data:
+ for local_if, values in neighbor.items():
+ if interface is not None and local_if != interface:
+ continue
+ for chassis, c_value in values.get('chassis', {}).items():
+ capabilities = c_value['capability']
+ if isinstance(capabilities, dict):
+ capabilities = [capabilities]
+
+ cap = ''
+ for capability in capabilities:
+ if capability['enabled']:
+ if capability['type'] == 'Router':
+ cap += 'R'
+ if capability['type'] == 'Bridge':
+ cap += 'B'
+ if capability['type'] == 'Wlan':
+ cap += 'W'
+ if capability['type'] == 'Station':
+ cap += 'S'
+ if capability['type'] == 'Repeater':
+ cap += 'r'
+ if capability['type'] == 'Telephone':
+ cap += 'T'
+ if capability['type'] == 'Docsis':
+ cap += 'D'
+ if capability['type'] == 'Other':
+ cap += 'O'
+
+ remote_if = 'Unknown'
+ if 'descr' in values.get('port', {}):
+ remote_if = values.get('port', {}).get('descr')
+ elif 'id' in values.get('port', {}):
+ remote_if = values.get('port', {}).get('id').get('value', 'Unknown')
+
+ output.append({local_if: {'chassis': chassis,
+ 'remote_if': remote_if,
+ 'proto': values.get('via','Unknown'),
+ 'platform': c_value.get('descr', 'Unknown'),
+ 'capabilities': cap}})
output = {'neighbors': output}
return output
@@ -107,18 +111,14 @@ if __name__ == '__main__':
neighbors = dict()
if 'interface' in tmp.get('lldp'):
- if args.all:
- neighbors = tmp['lldp']['interface']
- elif args.interface:
- if args.interface in tmp['lldp']['interface']:
- neighbors[args.interface] = tmp['lldp']['interface'][args.interface]
+ neighbors = tmp['lldp']['interface']
else:
parser.print_help()
exit(1)
- tmpl = jinja2.Template(lldp_out)
- config_text = tmpl.render(parse_data(neighbors))
+ tmpl = jinja2.Template(lldp_out, trim_blocks=True)
+ config_text = tmpl.render(parse_data(neighbors, interface=args.interface))
print(config_text)
exit(0)
diff --git a/src/systemd/isc-dhcp-relay6.service b/src/systemd/isc-dhcp-relay6.service
index 85ff16e41..30037e013 100644
--- a/src/systemd/isc-dhcp-relay6.service
+++ b/src/systemd/isc-dhcp-relay6.service
@@ -3,7 +3,7 @@ Description=ISC DHCP IPv6 relay
Documentation=man:dhcrelay(8)
Wants=network-online.target
RequiresMountsFor=/run
-ConditionPathExists=/run/dhcp-relay/dhcpv6.conf
+ConditionPathExists=/run/dhcp-relay/dhcrelay6.conf
After=vyos-router.service
[Service]
@@ -11,9 +11,9 @@ Type=forking
WorkingDirectory=/run/dhcp-relay
RuntimeDirectory=dhcp-relay
RuntimeDirectoryPreserve=yes
-EnvironmentFile=/run/dhcp-relay/dhcpv6.conf
-PIDFile=/run/dhcp-relay/dhcrelayv6.pid
-ExecStart=/usr/sbin/dhcrelay -6 -pf /run/dhcp-relay/dhcrelayv6.pid $OPTIONS
+EnvironmentFile=/run/dhcp-relay/dhcrelay6.conf
+PIDFile=/run/dhcp-relay/dhcrelay6.pid
+ExecStart=/usr/sbin/dhcrelay -6 -pf /run/dhcp-relay/dhcrelay6.pid $OPTIONS
Restart=always
[Install]