diff options
Diffstat (limited to 'src/conf_mode/interfaces-macsec.py')
-rwxr-xr-x | src/conf_mode/interfaces-macsec.py | 88 |
1 files changed, 54 insertions, 34 deletions
diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py index 279dd119b..649ea8d50 100755 --- a/src/conf_mode/interfaces-macsec.py +++ b/src/conf_mode/interfaces-macsec.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2020 VyOS maintainers and contributors +# Copyright (C) 2020-2022 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 @@ -21,16 +21,21 @@ from sys import exit from vyos.config import Config from vyos.configdict import get_interface_dict -from vyos.ifconfig import MACsecIf -from vyos.ifconfig import Interface -from vyos.template import render -from vyos.util import call +from vyos.configdict import is_node_changed +from vyos.configdict import is_source_interface from vyos.configverify import verify_vrf from vyos.configverify import verify_address from vyos.configverify import verify_bridge_delete from vyos.configverify import verify_mtu_ipv6 from vyos.configverify import verify_mirror_redirect from vyos.configverify import verify_source_interface +from vyos.configverify import verify_bond_bridge_member +from vyos.ifconfig import MACsecIf +from vyos.ifconfig import Interface +from vyos.template import render +from vyos.util import call +from vyos.util import dict_search +from vyos.util import is_systemd_service_running from vyos import ConfigError from vyos import airbag airbag.enable() @@ -52,9 +57,19 @@ def get_config(config=None): # Check if interface has been removed if 'deleted' in macsec: - source_interface = conf.return_effective_value(['source-interface']) + source_interface = conf.return_effective_value(base + [ifname, 'source-interface']) macsec.update({'source_interface': source_interface}) + if is_node_changed(conf, base + [ifname, 'security']): + macsec.update({'shutdown_required': {}}) + + if is_node_changed(conf, base + [ifname, 'source_interface']): + macsec.update({'shutdown_required': {}}) + + if 'source_interface' in macsec: + tmp = is_source_interface(conf, macsec['source_interface'], ['macsec', 'pseudo-ethernet']) + if tmp and tmp != ifname: macsec.update({'is_source_interface' : tmp}) + return macsec @@ -67,22 +82,25 @@ def verify(macsec): verify_vrf(macsec) verify_mtu_ipv6(macsec) verify_address(macsec) + verify_bond_bridge_member(macsec) verify_mirror_redirect(macsec) - if not (('security' in macsec) and - ('cipher' in macsec['security'])): - raise ConfigError( - 'Cipher suite must be set for MACsec "{ifname}"'.format(**macsec)) + if dict_search('security.cipher', macsec) == None: + raise ConfigError('Cipher suite must be set for MACsec "{ifname}"'.format(**macsec)) + + if dict_search('security.encrypt', macsec) != None: + if dict_search('security.mka.cak', macsec) == None or dict_search('security.mka.ckn', macsec) == None: + raise ConfigError('Missing mandatory MACsec security keys as encryption is enabled!') + + cak_len = len(dict_search('security.mka.cak', macsec)) - if (('security' in macsec) and - ('encrypt' in macsec['security'])): - tmp = macsec.get('security') + if dict_search('security.cipher', macsec) == 'gcm-aes-128' and cak_len != 32: + # gcm-aes-128 requires a 128bit long key - 32 characters (string) = 16byte = 128bit + raise ConfigError('gcm-aes-128 requires a 128bit long key!') - if not (('mka' in tmp) and - ('cak' in tmp['mka']) and - ('ckn' in tmp['mka'])): - raise ConfigError('Missing mandatory MACsec security ' - 'keys as encryption is enabled!') + elif dict_search('security.cipher', macsec) == 'gcm-aes-256' and cak_len != 64: + # gcm-aes-128 requires a 128bit long key - 64 characters (string) = 32byte = 256bit + raise ConfigError('gcm-aes-128 requires a 256bit long key!') if 'source_interface' in macsec: # MACsec adds a 40 byte overhead (32 byte MACsec + 8 bytes VLAN 802.1ad @@ -97,33 +115,35 @@ def verify(macsec): def generate(macsec): - render(wpa_suppl_conf.format(**macsec), - 'macsec/wpa_supplicant.conf.j2', macsec) + render(wpa_suppl_conf.format(**macsec), 'macsec/wpa_supplicant.conf.j2', macsec) return None def apply(macsec): - # Remove macsec interface - if 'deleted' in macsec: - call('systemctl stop wpa_supplicant-macsec@{source_interface}' - .format(**macsec)) + systemd_service = 'wpa_supplicant-macsec@{source_interface}'.format(**macsec) + + # Remove macsec interface on deletion or mandatory parameter change + if 'deleted' in macsec or 'shutdown_required' in macsec: + call(f'systemctl stop {systemd_service}') if macsec['ifname'] in interfaces(): tmp = MACsecIf(macsec['ifname']) tmp.remove() - # delete configuration on interface removal - if os.path.isfile(wpa_suppl_conf.format(**macsec)): - os.unlink(wpa_suppl_conf.format(**macsec)) + if 'deleted' in macsec: + # delete configuration on interface removal + if os.path.isfile(wpa_suppl_conf.format(**macsec)): + os.unlink(wpa_suppl_conf.format(**macsec)) - else: - # It is safe to "re-create" the interface always, there is a sanity - # check that the interface will only be create if its non existent - i = MACsecIf(**macsec) - i.update(macsec) + return None + + # It is safe to "re-create" the interface always, there is a sanity + # check that the interface will only be create if its non existent + i = MACsecIf(**macsec) + i.update(macsec) - call('systemctl restart wpa_supplicant-macsec@{source_interface}' - .format(**macsec)) + if not is_systemd_service_running(systemd_service) or 'shutdown_required' in macsec: + call(f'systemctl reload-or-restart {systemd_service}') return None |