From 488024e698ac5479b652f072b1680cdc62396f73 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Mon, 18 Jul 2022 23:48:31 +0200 Subject: macsec: T4537: support online ciper and source-interface re-configuration (cherry picked from commit 82d8494d349edd7707c3811a71ca0e9c0648204e) --- src/conf_mode/interfaces-macsec.py | 89 ++++++++++++++++++++------------------ 1 file changed, 46 insertions(+), 43 deletions(-) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py index e3527a366..eac92f149 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,17 +21,19 @@ 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.util import dict_search +from vyos.configdict import is_node_changed 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_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() @@ -56,6 +58,13 @@ def get_config(config=None): source_interface = conf.return_effective_value(['source-interface']) macsec.update({'source_interface': source_interface}) + ifname = macsec['ifname'] + 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': {}}) + return macsec @@ -70,20 +79,12 @@ def verify(macsec): verify_address(macsec) verify_bond_bridge_member(macsec) - if not (('security' in macsec) and - ('cipher' in macsec['security'])): - raise ConfigError( - 'Cipher suite must be set for MACsec "{ifname}"'.format(**macsec)) - - if (('security' in macsec) and - ('encrypt' in macsec['security'])): - tmp = macsec.get('security') + if dict_search('security.cipher', macsec) == None: + raise ConfigError('Cipher suite must be set for MACsec "{ifname}"'.format(**macsec)) - 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!') + 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)) @@ -114,35 +115,37 @@ def generate(macsec): 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)) - - else: - # This is a special type of interface which needs additional parameters - # when created using iproute2. Instead of passing a ton of arguments, - # use a dictionary provided by the interface class which holds all the - # options necessary. - conf = MACsecIf.get_config() - conf['source_interface'] = macsec['source_interface'] - conf['security_cipher'] = macsec['security']['cipher'] - - # 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['ifname'], **conf) - i.update(macsec) - - call('systemctl restart wpa_supplicant-macsec@{source_interface}' - .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)) + return None + + # This is a special type of interface which needs additional parameters + # when created using iproute2. Instead of passing a ton of arguments, + # use a dictionary provided by the interface class which holds all the + # options necessary. + conf = MACsecIf.get_config() + conf['source_interface'] = macsec['source_interface'] + conf['security_cipher'] = macsec['security']['cipher'] + + # 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['ifname'], **conf) + i.update(macsec) + + if not is_systemd_service_running(systemd_service) or 'shutdown_required' in macsec: + call(f'systemctl reload-or-restart {systemd_service}') return None -- cgit v1.2.3 From 922871b4dc41f345d7ec1aae518ba91b6dfeb62c Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 4 Aug 2022 08:29:14 +0200 Subject: macsec: T4592: can not create two interfaces using the same source-interface (cherry picked from commit 993961f60ead2a18912eb577b1152463d4eb8b4e) --- src/conf_mode/interfaces-macsec.py | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/conf_mode') diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py index eac92f149..8076a27b6 100755 --- a/src/conf_mode/interfaces-macsec.py +++ b/src/conf_mode/interfaces-macsec.py @@ -22,6 +22,7 @@ from sys import exit from vyos.config import Config from vyos.configdict import get_interface_dict 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 @@ -65,6 +66,10 @@ def get_config(config=None): 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') + if tmp and tmp != ifname: macsec.update({'is_source_interface' : tmp}) + return macsec @@ -96,6 +101,12 @@ def verify(macsec): # gcm-aes-128 requires a 128bit long key - 64 characters (string) = 32byte = 256bit raise ConfigError('gcm-aes-128 requires a 256bit long key!') + if 'is_source_interface' in macsec: + tmp = macsec['is_source_interface'] + src_ifname = macsec['source_interface'] + raise ConfigError(f'Can not use source-interface "{src_ifname}", it already ' \ + f'belongs to interface "{tmp}"!') + if 'source_interface' in macsec: # MACsec adds a 40 byte overhead (32 byte MACsec + 8 bytes VLAN 802.1ad # and 802.1q) - we need to check the underlaying MTU if our configured -- cgit v1.2.3