diff options
| author | Christian Breunig <christian@breunig.cc> | 2026-09-24 19:06:31 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-09-24 19:06:31 +0200 |
| commit | 990fa1569d3087842d8ff407d8c2ba4ead1d847e (patch) | |
| tree | 92597a1458c9c6de94917f88ec9cb8aaf403fbec /src | |
| parent | e0ca5c66796337dd992d6572019ea6f4edb475dc (diff) | |
| parent | 4fd9ad0ac3a79aba079b10f58ec897847eb271d5 (diff) | |
| download | vyos-1x-990fa1569d3087842d8ff407d8c2ba4ead1d847e.tar.gz vyos-1x-990fa1569d3087842d8ff407d8c2ba4ead1d847e.zip | |
Merge pull request #5484 from haakonnore/feat/T9319-vxlan-gbp
vxlan: T9319: add VXLAN-GBP support
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/interfaces_vxlan.py | 63 |
1 files changed, 61 insertions, 2 deletions
diff --git a/src/conf_mode/interfaces_vxlan.py b/src/conf_mode/interfaces_vxlan.py index f3d9f3c76..10ae89d4c 100755 --- a/src/conf_mode/interfaces_vxlan.py +++ b/src/conf_mode/interfaces_vxlan.py @@ -37,10 +37,13 @@ from vyos.ifconfig import VXLANIf from vyos.template import is_ipv6 from vyos.utils.dict import dict_search from vyos.utils.network import interface_exists +from vyos.xml_ref import default_value from vyos import ConfigError from vyos import airbag airbag.enable() +base = ['interfaces', 'vxlan'] + def get_config(config=None): """ Retrieve CLI config as dictionary. Dictionary can never be empty, as at least @@ -50,13 +53,12 @@ def get_config(config=None): conf = config else: conf = Config() - base = ['interfaces', 'vxlan'] ifname, vxlan = get_interface_dict(conf, base) # VXLAN interfaces are picky and require recreation if certain parameters # change. But a VXLAN interface should - of course - not be re-created if # it's description or IP address is adjusted. Feels somehow logic doesn't it? - for cli_option in ['parameters', 'gpe', 'group', 'port', 'remote', + for cli_option in ['parameters', 'gbp', 'gpe', 'group', 'port', 'remote', 'source-address', 'source-interface', 'vni']: if is_node_changed(conf, base + [ifname, cli_option]): vxlan.update({'rebuild_required': {}}) @@ -96,6 +98,27 @@ def get_config(config=None): return vxlan + +def vxlan_socket_families(config): + # External mode opens both IPv4 and IPv6 sockets. + if dict_search('parameters.external', config) is not None: + return {4, 6} + addresses = [config.get('source_address', ''), config.get('group', '')] + addresses.extend(config.get('remote', [])) + if any(is_ipv6(address) for address in addresses if address): + return {6} + return {4} + + +def vxlan_underlay_vrf(config): + # The socket binds to the source interface's VRF, not the overlay VRF. + # A source interface that does not exist yet cannot bind the socket. + source = config.get('source_interface') + if source and interface_exists(source): + return Interface(source).get_vrf() or '' + return '' + + def verify(vxlan): if 'deleted' in vxlan: verify_bridge_delete(vxlan) @@ -143,6 +166,42 @@ def verify(vxlan): f'CLI option is used and "vni-filter" is unset. '\ f'Additional tunnels: {other_tunnels}') + if 'gbp' in vxlan and 'gpe' in vxlan: + raise ConfigError('VXLAN-GBP and VXLAN-GPE cannot be used together') + + if 'gbp' in vxlan and dict_search('parameters.external', vxlan) is not None: + Warning( + 'In external mode VXLAN-GBP uses tunnel metadata instead of ' + 'the packet mark; firewall mark matching will not see the ' + 'received group policy ID.' + ) + + # Different GBP flags cannot share a socket. Separate address families or + # underlay VRFs can reuse a UDP port without sharing that socket. + families = vxlan_socket_families(vxlan) + default_port = default_value(base + ['vxlan0', 'port']) + for tunnel, tunnel_config in vxlan.get('other_tunnels', {}).items(): + if ( + ('gbp' in tunnel_config and 'gbp' in vxlan) + or ('gbp' not in tunnel_config and 'gbp' not in vxlan) + ): + continue + # other_tunnels carries no defaults; use the XML default port. + if tunnel_config.get('port', default_port) != vxlan['port']: + continue + if not families & vxlan_socket_families(tunnel_config): + continue + vrf = vxlan_underlay_vrf(vxlan) + other_vrf = vxlan_underlay_vrf(tunnel_config) + # An unbound socket also conflicts with sockets bound to a VRF. + if vrf and other_vrf and vrf != other_vrf: + continue + raise ConfigError( + f'VXLAN interface "{tunnel}" shares UDP port ' + f'{vxlan["port"]} but has a different "gbp" setting; ' + 'use matching GBP settings or a different UDP port.' + ) + if 'gpe' in vxlan and dict_search('parameters.external', vxlan) is None: raise ConfigError( f'VXLAN-GPE is only supported when "external" ' f'CLI option is used.' |
