summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Poessinger <christian@poessinger.com>2020-07-26 11:16:13 +0200
committerChristian Poessinger <christian@poessinger.com>2020-07-26 15:07:27 +0200
commita156d2f1479affe4e7cfa56785e4d2d61a776cea (patch)
tree0da415f924fda0e0f29e4ec24dd4dc19fd0966ff
parent6b531e04474d7d976d7cee11e556c3fe3dc2b69f (diff)
downloadvyos-1x-a156d2f1479affe4e7cfa56785e4d2d61a776cea.tar.gz
vyos-1x-a156d2f1479affe4e7cfa56785e4d2d61a776cea.zip
vxlan: ifconfig: T2653: move to get_interface_dict()
The current VyOS CLI parser code written in Python contains a ton of duplicates which I can also hold myself accountable for - or maybe mainly me - depends on the angle of judge.
-rw-r--r--interface-definitions/interfaces-vxlan.xml.in1
-rw-r--r--python/vyos/ifconfig/vxlan.py20
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py253
3 files changed, 46 insertions, 228 deletions
diff --git a/interface-definitions/interfaces-vxlan.xml.in b/interface-definitions/interfaces-vxlan.xml.in
index bd3ab4022..8529f6885 100644
--- a/interface-definitions/interfaces-vxlan.xml.in
+++ b/interface-definitions/interfaces-vxlan.xml.in
@@ -93,6 +93,7 @@
<validator name="numeric" argument="--range 1-65535"/>
</constraint>
</properties>
+ <defaultValue>8472</defaultValue>
</leafNode>
<leafNode name="vni">
<properties>
diff --git a/python/vyos/ifconfig/vxlan.py b/python/vyos/ifconfig/vxlan.py
index 973b4ef05..0dddab7b7 100644
--- a/python/vyos/ifconfig/vxlan.py
+++ b/python/vyos/ifconfig/vxlan.py
@@ -47,8 +47,8 @@ class VXLANIf(Interface):
'port': 8472, # The Linux implementation of VXLAN pre-dates
# the IANA's selection of a standard destination port
'remote': '',
- 'src_address': '',
- 'src_interface': '',
+ 'source_address': '',
+ 'source_interface': '',
'vni': 0
}
definition = {
@@ -60,29 +60,29 @@ class VXLANIf(Interface):
}
}
options = Interface.options + \
- ['group', 'remote', 'src_interface', 'port', 'vni', 'src_address']
+ ['group', 'remote', 'source_interface', 'port', 'vni', 'source_address']
mapping = {
'ifname': 'add',
'vni': 'id',
'port': 'dstport',
- 'src_address': 'local',
- 'src_interface': 'dev',
+ 'source_address': 'local',
+ 'source_interface': 'dev',
}
def _create(self):
cmdline = ['ifname', 'type', 'vni', 'port']
- if self.config['src_address']:
- cmdline.append('src_address')
+ if self.config['source_address']:
+ cmdline.append('source_address')
if self.config['remote']:
cmdline.append('remote')
- if self.config['group'] or self.config['src_interface']:
- if self.config['group'] and self.config['src_interface']:
+ if self.config['group'] or self.config['source_interface']:
+ if self.config['group'] and self.config['source_interface']:
cmdline.append('group')
- cmdline.append('src_interface')
+ cmdline.append('source_interface')
else:
ifname = self.config['ifname']
raise ConfigError(
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index 39db814b4..47c0bdcb8 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
@@ -21,197 +21,61 @@ from copy import deepcopy
from netifaces import interfaces
from vyos.config import Config
+from vyos.configdict import get_interface_dict
+from vyos.configverify import verify_address
+from vyos.configverify import verify_bridge_delete
+from vyos.configverify import verify_source_interface
from vyos.ifconfig import VXLANIf, Interface
-from vyos.validate import is_member
from vyos import ConfigError
-
from vyos import airbag
airbag.enable()
-default_config_data = {
- 'address': [],
- 'deleted': False,
- 'description': '',
- 'disable': False,
- 'group': '',
- 'intf': '',
- 'ip_arp_cache_tmo': 30,
- 'ip_disable_arp_filter': 1,
- 'ip_enable_arp_accept': 0,
- 'ip_enable_arp_announce': 0,
- 'ip_enable_arp_ignore': 0,
- 'ip_proxy_arp': 0,
- 'ipv6_accept_ra': 1,
- 'ipv6_autoconf': 0,
- 'ipv6_eui64_prefix': [],
- 'ipv6_forwarding': 1,
- 'ipv6_dup_addr_detect': 1,
- 'is_bridge_member': False,
- 'source_address': '',
- 'source_interface': '',
- 'mtu': 1450,
- 'remote': '',
- 'remote_port': 8472, # The Linux implementation of VXLAN pre-dates
- # the IANA's selection of a standard destination port
- 'vni': ''
-}
-
def get_config():
- vxlan = 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()
+ base = ['interfaces', 'vxlan']
+ vxlan = get_interface_dict(conf, base)
- # determine tagNode instance
- if 'VYOS_TAGNODE_VALUE' not in os.environ:
- raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified')
-
- vxlan['intf'] = os.environ['VYOS_TAGNODE_VALUE']
-
- # check if interface is member if a bridge
- vxlan['is_bridge_member'] = is_member(conf, vxlan['intf'], 'bridge')
-
- # Check if interface has been removed
- if not conf.exists('interfaces vxlan ' + vxlan['intf']):
- vxlan['deleted'] = True
- return vxlan
-
- # set new configuration level
- conf.set_level('interfaces vxlan ' + vxlan['intf'])
-
- # retrieve configured interface addresses
- if conf.exists('address'):
- vxlan['address'] = conf.return_values('address')
-
- # retrieve interface description
- if conf.exists('description'):
- vxlan['description'] = conf.return_value('description')
-
- # Disable this interface
- if conf.exists('disable'):
- vxlan['disable'] = True
-
- # VXLAN multicast grou
- if conf.exists('group'):
- vxlan['group'] = conf.return_value('group')
-
- # ARP cache entry timeout in seconds
- if conf.exists('ip arp-cache-timeout'):
- vxlan['ip_arp_cache_tmo'] = int(conf.return_value('ip arp-cache-timeout'))
-
- # ARP filter configuration
- if conf.exists('ip disable-arp-filter'):
- vxlan['ip_disable_arp_filter'] = 0
-
- # ARP enable accept
- if conf.exists('ip enable-arp-accept'):
- vxlan['ip_enable_arp_accept'] = 1
-
- # ARP enable announce
- if conf.exists('ip enable-arp-announce'):
- vxlan['ip_enable_arp_announce'] = 1
-
- # ARP enable ignore
- if conf.exists('ip enable-arp-ignore'):
- vxlan['ip_enable_arp_ignore'] = 1
-
- # Enable proxy-arp on this interface
- if conf.exists('ip enable-proxy-arp'):
- vxlan['ip_proxy_arp'] = 1
-
- # Enable acquisition of IPv6 address using stateless autoconfig (SLAAC)
- if conf.exists('ipv6 address autoconf'):
- vxlan['ipv6_autoconf'] = 1
-
- # Get prefixes for IPv6 addressing based on MAC address (EUI-64)
- if conf.exists('ipv6 address eui64'):
- vxlan['ipv6_eui64_prefix'] = conf.return_values('ipv6 address eui64')
-
- # Remove the default link-local address if set.
- if not ( conf.exists('ipv6 address no-default-link-local')
- or vxlan['is_bridge_member'] ):
- # add the link-local by default to make IPv6 work
- vxlan['ipv6_eui64_prefix'].append('fe80::/64')
-
- # Disable IPv6 forwarding on this interface
- if conf.exists('ipv6 disable-forwarding'):
- vxlan['ipv6_forwarding'] = 0
-
- # IPv6 Duplicate Address Detection (DAD) tries
- if conf.exists('ipv6 dup-addr-detect-transmits'):
- vxlan['ipv6_dup_addr_detect'] = int(conf.return_value('ipv6 dup-addr-detect-transmits'))
-
- # to make IPv6 SLAAC and DHCPv6 work with forwarding=1,
- # accept_ra must be 2
- if vxlan['ipv6_autoconf'] or 'dhcpv6' in vxlan['address']:
- vxlan['ipv6_accept_ra'] = 2
-
- # VXLAN source address
- if conf.exists('source-address'):
- vxlan['source_address'] = conf.return_value('source-address')
-
- # VXLAN underlay interface
- if conf.exists('source-interface'):
- vxlan['source_interface'] = conf.return_value('source-interface')
-
- # Maximum Transmission Unit (MTU)
- if conf.exists('mtu'):
- vxlan['mtu'] = int(conf.return_value('mtu'))
-
- # Remote address of VXLAN tunnel
- if conf.exists('remote'):
- vxlan['remote'] = conf.return_value('remote')
-
- # Remote port of VXLAN tunnel
- if conf.exists('port'):
- vxlan['remote_port'] = int(conf.return_value('port'))
-
- # Virtual Network Identifier
- if conf.exists('vni'):
- vxlan['vni'] = conf.return_value('vni')
+ # VXLAN is "special" the default MTU is 1492 - update accordingly
+ # as the config_level is already st in get_interface_dict() - we can use []
+ tmp = conf.get_config_dict([], key_mangling=('-', '_'), get_first_key=True)
+ if 'mtu' not in tmp:
+ vxlan['mtu'] = '1450'
return vxlan
-
def verify(vxlan):
- if vxlan['deleted']:
- if vxlan['is_bridge_member']:
- raise ConfigError((
- f'Cannot delete interface "{vxlan["intf"]}" as it is a '
- f'member of bridge "{vxlan["is_bridge_member"]}"!'))
-
+ if 'deleted' in vxlan:
+ verify_bridge_delete(vxlan)
return None
- if vxlan['mtu'] < 1500:
+ if int(vxlan['mtu']) < 1500:
print('WARNING: RFC7348 recommends VXLAN tunnels preserve a 1500 byte MTU')
- if vxlan['group']:
- if not vxlan['source_interface']:
+ if 'group' in vxlan:
+ if 'source_interface' not in vxlan:
raise ConfigError('Multicast VXLAN requires an underlaying interface ')
- if not vxlan['source_interface'] in interfaces():
- raise ConfigError('VXLAN source interface does not exist')
+ verify_source_interface(vxlan)
- if not (vxlan['group'] or vxlan['remote'] or vxlan['source_address']):
+ if not any(tmp in ['group', 'remote', 'source_address'] for tmp in vxlan):
raise ConfigError('Group, remote or source-address must be configured')
- if not vxlan['vni']:
+ if 'vni' not in vxlan:
raise ConfigError('Must configure VNI for VXLAN')
- if vxlan['source_interface']:
+ if 'source_interface' in vxlan:
# VXLAN adds a 50 byte overhead - we need to check the underlaying MTU
# if our configured MTU is at least 50 bytes less
underlay_mtu = int(Interface(vxlan['source_interface']).get_mtu())
- if underlay_mtu < (vxlan['mtu'] + 50):
+ if underlay_mtu < (int(vxlan['mtu']) + 50):
raise ConfigError('VXLAN has a 50 byte overhead, underlaying device ' \
- 'MTU is to small ({})'.format(underlay_mtu))
-
- if ( vxlan['is_bridge_member']
- and ( vxlan['address']
- or vxlan['ipv6_eui64_prefix']
- or vxlan['ipv6_autoconf'] ) ):
- raise ConfigError((
- f'Cannot assign address to interface "{vxlan["intf"]}" '
- f'as it is a member of bridge "{vxlan["is_bridge_member"]}"!'))
+ f'MTU is to small ({underlay_mtu} bytes)')
+ verify_address(vxlan)
return None
@@ -221,73 +85,26 @@ def generate(vxlan):
def apply(vxlan):
# Check if the VXLAN interface already exists
- if vxlan['intf'] in interfaces():
- v = VXLANIf(vxlan['intf'])
+ if vxlan['ifname'] in interfaces():
+ v = VXLANIf(vxlan['ifname'])
# VXLAN is super picky and the tunnel always needs to be recreated,
# thus we can simply always delete it first.
v.remove()
- if not vxlan['deleted']:
+ if 'deleted' not in vxlan:
# VXLAN interface needs to be created on-block
# instead of passing a ton of arguments, I just use a dict
# that is managed by vyos.ifconfig
conf = deepcopy(VXLANIf.get_config())
# Assign VXLAN instance configuration parameters to config dict
- conf['vni'] = vxlan['vni']
- conf['group'] = vxlan['group']
- conf['src_address'] = vxlan['source_address']
- conf['src_interface'] = vxlan['source_interface']
- conf['remote'] = vxlan['remote']
- conf['port'] = vxlan['remote_port']
+ for tmp in ['vni', 'group', 'source_address', 'source_interface', 'remote', 'port']:
+ if tmp in vxlan:
+ conf[tmp] = vxlan[tmp]
# Finally create the new interface
- v = VXLANIf(vxlan['intf'], **conf)
- # update interface description used e.g. by SNMP
- v.set_alias(vxlan['description'])
- # Maximum Transfer Unit (MTU)
- v.set_mtu(vxlan['mtu'])
-
- # configure ARP cache timeout in milliseconds
- v.set_arp_cache_tmo(vxlan['ip_arp_cache_tmo'])
- # configure ARP filter configuration
- v.set_arp_filter(vxlan['ip_disable_arp_filter'])
- # configure ARP accept
- v.set_arp_accept(vxlan['ip_enable_arp_accept'])
- # configure ARP announce
- v.set_arp_announce(vxlan['ip_enable_arp_announce'])
- # configure ARP ignore
- v.set_arp_ignore(vxlan['ip_enable_arp_ignore'])
- # Enable proxy-arp on this interface
- v.set_proxy_arp(vxlan['ip_proxy_arp'])
- # IPv6 accept RA
- v.set_ipv6_accept_ra(vxlan['ipv6_accept_ra'])
- # IPv6 address autoconfiguration
- v.set_ipv6_autoconf(vxlan['ipv6_autoconf'])
- # IPv6 forwarding
- v.set_ipv6_forwarding(vxlan['ipv6_forwarding'])
- # IPv6 Duplicate Address Detection (DAD) tries
- v.set_ipv6_dad_messages(vxlan['ipv6_dup_addr_detect'])
-
- # Configure interface address(es) - no need to implicitly delete the
- # old addresses as they have already been removed by deleting the
- # interface above
- for addr in vxlan['address']:
- v.add_addr(addr)
-
- # IPv6 EUI-based addresses
- for addr in vxlan['ipv6_eui64_prefix']:
- v.add_ipv6_eui64_address(addr)
-
- # As the VXLAN interface is always disabled first when changing
- # parameters we will only re-enable the interface if it is not
- # administratively disabled
- if not vxlan['disable']:
- v.set_admin_state('up')
-
- # re-add ourselves to any bridge we might have fallen out of
- if vxlan['is_bridge_member']:
- v.add_to_bridge(vxlan['is_bridge_member'])
+ v = VXLANIf(vxlan['ifname'], **conf)
+ v.update(vxlan)
return None