summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/templates/macsec/wpa_supplicant.conf.tmpl21
-rw-r--r--interface-definitions/interfaces-macsec.xml.in1
-rw-r--r--python/vyos/configdict.py2
-rw-r--r--python/vyos/configverify.py19
-rw-r--r--python/vyos/ifconfig/interface.py3
-rwxr-xr-xsrc/conf_mode/interfaces-dummy.py12
-rwxr-xr-xsrc/conf_mode/interfaces-loopback.py10
-rwxr-xr-xsrc/conf_mode/interfaces-macsec.py209
8 files changed, 101 insertions, 176 deletions
diff --git a/data/templates/macsec/wpa_supplicant.conf.tmpl b/data/templates/macsec/wpa_supplicant.conf.tmpl
index a614d23f5..1731bf160 100644
--- a/data/templates/macsec/wpa_supplicant.conf.tmpl
+++ b/data/templates/macsec/wpa_supplicant.conf.tmpl
@@ -45,9 +45,10 @@ network={
# - the key server has decided to enable MACsec
# 0: Encrypt traffic (default)
# 1: Integrity only
- macsec_integ_only={{ '0' if security_encrypt else '1' }}
+ macsec_integ_only={{ '0' if security is defined and security.encrypt is defined else '1' }}
-{% if security_encrypt %}
+{% if security is defined %}
+{% if security.encrypt is defined %}
# mka_cak, mka_ckn, and mka_priority: IEEE 802.1X/MACsec pre-shared key mode
# This allows to configure MACsec with a pre-shared key using a (CAK,CKN) pair.
# In this mode, instances of wpa_supplicant can act as MACsec peers. The peer
@@ -56,21 +57,22 @@ network={
# hex-string (32 hex-digits) or a 32-byte (256-bit) hex-string (64 hex-digits)
# mka_ckn (CKN = CAK Name) takes a 1..32-bytes (8..256 bit) hex-string
# (2..64 hex-digits)
- mka_cak={{ security_mka_cak }}
- mka_ckn={{ security_mka_ckn }}
+ mka_cak={{ security.mka.cak }}
+ mka_ckn={{ security.mka.ckn }}
# mka_priority (Priority of MKA Actor) is in 0..255 range with 255 being
# default priority
- mka_priority={{ security_mka_priority }}
-{% endif %}
-{% if security_replay_window %}
+ mka_priority={{ security.mka.priority }}
+{% endif %}
+
+{% if security.replay_window is defined %}
# macsec_replay_protect: IEEE 802.1X/MACsec replay protection
# This setting applies only when MACsec is in use, i.e.,
# - macsec_policy is enabled
# - the key server has decided to enable MACsec
# 0: Replay protection disabled (default)
# 1: Replay protection enabled
- macsec_replay_protect={{ '1' if security_replay_window else '0' }}
+ macsec_replay_protect=1
# macsec_replay_window: IEEE 802.1X/MACsec replay protection window
# This determines a window in which replay is tolerated, to allow receipt
@@ -80,7 +82,8 @@ network={
# - the key server has decided to enable MACsec
# 0: No replay window, strict check (default)
# 1..2^32-1: number of packets that could be misordered
- macsec_replay_window={{ security_replay_window }}
+ macsec_replay_window={{ security.replay_window }}
+{% endif %}
{% endif %}
}
diff --git a/interface-definitions/interfaces-macsec.xml.in b/interface-definitions/interfaces-macsec.xml.in
index 36605ab59..dfef387d2 100644
--- a/interface-definitions/interfaces-macsec.xml.in
+++ b/interface-definitions/interfaces-macsec.xml.in
@@ -83,6 +83,7 @@
<validator name="numeric" argument="--range 0-255" />
</constraint>
</properties>
+ <defaultValue>255</defaultValue>
</leafNode>
</children>
</node>
diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py
index 074dc0131..0dc7578d8 100644
--- a/python/vyos/configdict.py
+++ b/python/vyos/configdict.py
@@ -96,6 +96,8 @@ def dict_merge(source, destination):
for key, value in source.items():
if key not in tmp.keys():
tmp[key] = value
+ elif isinstance(source[key], dict):
+ tmp[key] = dict_merge(source[key], tmp[key])
return tmp
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index 64eb80728..e2fffeca7 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -21,14 +21,14 @@
# NOTE: imports should be as local as possible to the function which
# makes use of it!
+from vyos import ConfigError
+
def verify_bridge_vrf(config):
"""
Common helper function used by interface implementations to
perform recurring validation of VRF configuration
"""
from netifaces import interfaces
- from vyos import ConfigError
-
if 'vrf' in config.keys():
if config['vrf'] not in interfaces():
raise ConfigError('VRF "{vrf}" does not exist'.format(**config))
@@ -45,8 +45,6 @@ def verify_bridge_address(config):
perform recurring validation of IP address assignmenr
when interface also is part of a bridge.
"""
- from vyos import ConfigError
-
if {'is_bridge_member', 'address'} <= set(config):
raise ConfigError(
f'Cannot assign address to interface "{ifname}" as it is a '
@@ -59,9 +57,18 @@ def verify_bridge_delete(config):
perform recurring validation of IP address assignmenr
when interface also is part of a bridge.
"""
- from vyos import ConfigError
-
if 'is_bridge_member' in config.keys():
raise ConfigError(
'Interface "{ifname}" cannot be deleted as it is a '
'member of bridge "{is_bridge_member}"!'.format(**config))
+
+
+def verify_source_interface(config):
+ """
+ Common helper function used by interface implementations to
+ perform recurring validation of the existence of a source-interface
+ required by e.g. peth/MACvlan, MACsec ...
+ """
+ if not 'source_interface' in config.keys():
+ raise ConfigError('Physical source-interface required for '
+ 'interface "{ifname}"'.format(**config))
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index a9af6ffdf..1819ffc82 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -796,6 +796,3 @@ class Interface(Control):
# Interface administrative state
state = 'down' if 'disable' in config.keys() else 'up'
self.set_admin_state(state)
-
- import pprint
- pprint.pprint(config)
diff --git a/src/conf_mode/interfaces-dummy.py b/src/conf_mode/interfaces-dummy.py
index 676211428..a8093ffa5 100755
--- a/src/conf_mode/interfaces-dummy.py
+++ b/src/conf_mode/interfaces-dummy.py
@@ -41,6 +41,10 @@ def get_config():
base = ['interfaces', 'dummy', ifname]
dummy = conf.get_config_dict(base, key_mangling=('-', '_'))
+ # Check if interface has been removed
+ if dummy == {}:
+ dummy.update({'deleted' : ''})
+
# store interface instance name in dictionary
dummy.update({'ifname': ifname})
@@ -50,14 +54,10 @@ def get_config():
tmp = {'is_bridge_member' : bridge}
dummy.update(tmp)
- # Check if interface has been removed
- tmp = {'deleted' : not conf.exists(base)}
- dummy.update(tmp)
-
return dummy
def verify(dummy):
- if dummy['deleted']:
+ if 'deleted' in dummy.keys():
verify_bridge_delete(dummy)
return None
@@ -73,7 +73,7 @@ def apply(dummy):
d = DummyIf(dummy['ifname'])
# Remove dummy interface
- if dummy['deleted']:
+ if 'deleted' in dummy.keys():
d.remove()
else:
d.update(dummy)
diff --git a/src/conf_mode/interfaces-loopback.py b/src/conf_mode/interfaces-loopback.py
index 32e683c07..7c3d8663d 100755
--- a/src/conf_mode/interfaces-loopback.py
+++ b/src/conf_mode/interfaces-loopback.py
@@ -36,13 +36,13 @@ def get_config():
base = ['interfaces', 'loopback', ifname]
loopback = conf.get_config_dict(base, key_mangling=('-', '_'))
+ # Check if interface has been removed
+ if loopback == {}:
+ loopback.update({'deleted' : ''})
+
# store interface instance name in dictionary
loopback.update({'ifname': ifname})
- # Check if interface has been removed
- tmp = {'deleted' : not conf.exists(base)}
- loopback.update(tmp)
-
return loopback
def verify(loopback):
@@ -53,7 +53,7 @@ def generate(loopback):
def apply(loopback):
l = LoopbackIf(loopback['ifname'])
- if loopback['deleted']:
+ if 'deleted' in loopback.keys():
l.remove()
else:
l.update(loopback)
diff --git a/src/conf_mode/interfaces-macsec.py b/src/conf_mode/interfaces-macsec.py
index a8966148f..ca5c32eeb 100755
--- a/src/conf_mode/interfaces-macsec.py
+++ b/src/conf_mode/interfaces-macsec.py
@@ -18,177 +18,111 @@ import os
from copy import deepcopy
from sys import exit
-from netifaces import interfaces
from vyos.config import Config
-from vyos.configdict import list_diff
+from vyos.configdict import dict_merge
from vyos.ifconfig import MACsecIf
from vyos.template import render
from vyos.util import call
from vyos.validate import is_member
+from vyos.configverify import verify_bridge_vrf
+from vyos.configverify import verify_bridge_address
+from vyos.configverify import verify_bridge_delete
+from vyos.configverify import verify_source_interface
+from vyos.xml import defaults
from vyos import ConfigError
-
from vyos import airbag
airbag.enable()
-default_config_data = {
- 'address': [],
- 'address_remove': [],
- 'deleted': False,
- 'description': '',
- 'disable': False,
- 'security_cipher': '',
- 'security_encrypt': False,
- 'security_mka_cak': '',
- 'security_mka_ckn': '',
- 'security_mka_priority': '255',
- 'security_replay_window': '',
- 'intf': '',
- 'source_interface': '',
- 'is_bridge_member': False,
- 'vrf': ''
-}
+# XXX: workaround for https://phabricator.vyos.net/T2656
+default = {'security' : {'mka' : {'priority' : '255'}}}
# XXX: wpa_supplicant works on the source interface
wpa_suppl_conf = '/run/wpa_supplicant/{source_interface}.conf'
-
def get_config():
- macsec = deepcopy(default_config_data)
+ """ Retrive CLI config as dictionary. Dictionary can never be empty,
+ as at least the interface name will be added or a deleted flag """
conf = Config()
# determine tagNode instance
if 'VYOS_TAGNODE_VALUE' not in os.environ:
raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified')
- macsec['intf'] = os.environ['VYOS_TAGNODE_VALUE']
- base_path = ['interfaces', 'macsec', macsec['intf']]
+ # retrieve interface default values
+ base = ['interfaces', 'macsec']
+ #default_values = defaults(base)
- # check if we are a member of any bridge
- macsec['is_bridge_member'] = is_member(conf, macsec['intf'], 'bridge')
+ ifname = os.environ['VYOS_TAGNODE_VALUE']
+ base = base + [ifname]
+ macsec = conf.get_config_dict(base, key_mangling=('-', '_'))
# Check if interface has been removed
- if not conf.exists(base_path):
- macsec['deleted'] = True
- # When stopping wpa_supplicant we need to stop it via the physical
- # interface - thus we need to retrieve ir from the effective config
- if conf.exists_effective(base_path + ['source-interface']):
- macsec['source_interface'] = conf.return_effective_value(
- base_path + ['source-interface'])
-
- return macsec
-
- # set new configuration level
- conf.set_level(base_path)
-
- # retrieve configured interface addresses
- if conf.exists(['address']):
- macsec['address'] = conf.return_values(['address'])
-
- # retrieve interface description
- if conf.exists(['description']):
- macsec['description'] = conf.return_value(['description'])
-
- # Disable this interface
- if conf.exists(['disable']):
- macsec['disable'] = True
-
- # retrieve interface cipher
- if conf.exists(['security', 'cipher']):
- macsec['security_cipher'] = conf.return_value(['security', 'cipher'])
-
- # Enable optional MACsec encryption
- if conf.exists(['security', 'encrypt']):
- macsec['security_encrypt'] = True
-
- # Secure Connectivity Association Key
- if conf.exists(['security', 'mka', 'cak']):
- macsec['security_mka_cak'] = conf.return_value(
- ['security', 'mka', 'cak'])
-
- # Secure Connectivity Association Name
- if conf.exists(['security', 'mka', 'ckn']):
- macsec['security_mka_ckn'] = conf.return_value(
- ['security', 'mka', 'ckn'])
-
- # MACsec Key Agreement protocol (MKA) actor priority
- if conf.exists(['security', 'mka', 'priority']):
- macsec['security_mka_priority'] = conf.return_value(
- ['security', 'mka', 'priority'])
-
- # IEEE 802.1X/MACsec replay protection
- if conf.exists(['security', 'replay-window']):
- macsec['security_replay_window'] = conf.return_value(
- ['security', 'replay-window'])
-
- # Physical interface
- if conf.exists(['source-interface']):
- macsec['source_interface'] = conf.return_value(['source-interface'])
-
- # Determine interface addresses (currently effective) - to determine which
- # address is no longer valid and needs to be removed from the interface
- eff_addr = conf.return_effective_values(['address'])
- act_addr = conf.return_values(['address'])
- macsec['address_remove'] = list_diff(eff_addr, act_addr)
-
- # retrieve VRF instance
- if conf.exists(['vrf']):
- macsec['vrf'] = conf.return_value(['vrf'])
+ if macsec == {}:
+ tmp = {
+ 'deleted' : '',
+ 'source_interface' : conf.return_effective_value(
+ base + ['source-interface'])
+ }
+ macsec.update(tmp)
+
+ # We have gathered the dict representation of the CLI, but there are
+ # default options which we need to update into the dictionary
+ # retrived.
+ macsec = dict_merge(default, macsec)
+
+ # Add interface instance name into dictionary
+ macsec.update({'ifname': ifname})
+
+ # Check if we are a member of any bridge
+ bridge = is_member(conf, ifname, 'bridge')
+ if bridge:
+ tmp = {'is_bridge_member' : bridge}
+ macsec.update(tmp)
return macsec
def verify(macsec):
- if macsec['deleted']:
- if macsec['is_bridge_member']:
- raise ConfigError(
- 'Interface "{intf}" cannot be deleted as it is a '
- 'member of bridge "{is_bridge_member}"!'.format(**macsec))
-
+ if 'deleted' in macsec.keys():
+ verify_bridge_delete(macsec)
return None
- if not macsec['source_interface']:
- raise ConfigError('Physical source interface must be set for '
- 'MACsec "{intf}"'.format(**macsec))
+ verify_source_interface(macsec)
+ verify_bridge_vrf(macsec)
+ verify_bridge_address(macsec)
- if not macsec['security_cipher']:
+ if not (('security' in macsec.keys()) and
+ ('cipher' in macsec['security'].keys())):
raise ConfigError(
- 'Cipher suite must be set for MACsec "{intf}"'.format(**macsec))
+ 'Cipher suite must be set for MACsec "{ifname}"'.format(**macsec))
- if macsec['security_encrypt']:
- if not (macsec['security_mka_cak'] and macsec['security_mka_ckn']):
- raise ConfigError(
- 'MACsec security keys mandartory when encryption is enabled')
+ if (('security' in macsec.keys()) and
+ ('encrypt' in macsec['security'].keys())):
+ tmp = macsec.get('security')
- if macsec['vrf']:
- if macsec['vrf'] not in interfaces():
- raise ConfigError('VRF "{vrf}" does not exist'.format(**macsec))
-
- if macsec['is_bridge_member']:
- raise ConfigError('Interface "{intf}" cannot be member of VRF '
- '"{vrf}" and bridge "{is_bridge_member}" at '
- 'the same time!'.format(**macsec))
-
- if macsec['is_bridge_member'] and macsec['address']:
- raise ConfigError(
- 'Cannot assign address to interface "{intf}" as it is'
- 'a member of bridge "{is_bridge_member}"!'.format(**macsec))
+ if not (('mka' in tmp.keys()) and
+ ('cak' in tmp['mka'].keys()) and
+ ('ckn' in tmp['mka'].keys())):
+ raise ConfigError('Missing mandatory MACsec security '
+ 'keys as encryption is enabled!')
return None
def generate(macsec):
render(wpa_suppl_conf.format(**macsec),
- 'macsec/wpa_supplicant.conf.tmpl', macsec, permission=0o640)
+ 'macsec/wpa_supplicant.conf.tmpl', macsec)
return None
def apply(macsec):
# Remove macsec interface
- if macsec['deleted']:
+ if 'deleted' in macsec.keys():
call('systemctl stop wpa_supplicant-macsec@{source_interface}'
.format(**macsec))
- MACsecIf(macsec['intf']).remove()
+
+ MACsecIf(macsec['ifname']).remove()
# delete configuration on interface removal
if os.path.isfile(wpa_suppl_conf.format(**macsec)):
@@ -198,35 +132,16 @@ def apply(macsec):
# MACsec interfaces require a configuration when they are added using
# iproute2. This static method will provide the configuration
# dictionary used by this class.
- conf = deepcopy(MACsecIf.get_config())
- # Assign MACsec instance configuration parameters to config dict
+ # XXX: subject of removal after completing T2653
+ conf = deepcopy(MACsecIf.get_config())
conf['source_interface'] = macsec['source_interface']
- conf['security_cipher'] = macsec['security_cipher']
+ 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['intf'], **conf)
-
- # update interface description used e.g. within SNMP
- i.set_alias(macsec['description'])
-
- # Configure interface address(es)
- # - not longer required addresses get removed first
- # - newly addresses will be added second
- for addr in macsec['address_remove']:
- i.del_addr(addr)
- for addr in macsec['address']:
- i.add_addr(addr)
-
- # assign/remove VRF (ONLY when not a member of a bridge,
- # otherwise 'nomaster' removes it from it)
- if not macsec['is_bridge_member']:
- i.set_vrf(macsec['vrf'])
-
- # Interface is administratively down by default, enable if desired
- if not macsec['disable']:
- i.set_admin_state('up')
+ i = MACsecIf(macsec['ifname'], **conf)
+ i.update(macsec)
call('systemctl restart wpa_supplicant-macsec@{source_interface}'
.format(**macsec))