diff options
| author | Christian Breunig <christian@breunig.cc> | 2023-11-22 10:37:00 +0100 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-11-22 10:37:00 +0100 | 
| commit | 00a28fe512ccb56f4ca57d18c2613ac47242a66d (patch) | |
| tree | 40908852df55d95dd1528ef8d7a36c9c626fdd45 /src | |
| parent | af08c30063fb1c68cbf1ca6cae3588efdef34b7d (diff) | |
| parent | 35f6033d21053fa420e837f157cd9377a4ccd26a (diff) | |
| download | vyos-1x-00a28fe512ccb56f4ca57d18c2613ac47242a66d.tar.gz vyos-1x-00a28fe512ccb56f4ca57d18c2613ac47242a66d.zip | |
Merge pull request #2499 from c-po/t5753-vxlan-vnifilter
vxlan: T5753: add support for VNI filtering
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/interfaces-vxlan.py | 35 | ||||
| -rwxr-xr-x | src/op_mode/bridge.py | 29 | 
2 files changed, 58 insertions, 6 deletions
| diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py index 6bf3227d5..4251e611b 100755 --- a/src/conf_mode/interfaces-vxlan.py +++ b/src/conf_mode/interfaces-vxlan.py @@ -60,8 +60,14 @@ def get_config(config=None):              vxlan.update({'rebuild_required': {}})              break +    # When dealing with VNI filtering we need to know what VNI was actually removed, +    # so build up a dict matching the vlan_to_vni structure but with removed values.      tmp = node_changed(conf, base + [ifname, 'vlan-to-vni'], recursive=True) -    if tmp: vxlan.update({'vlan_to_vni_removed': tmp}) +    if tmp: +        vxlan.update({'vlan_to_vni_removed': {}}) +        for vlan in tmp: +            vni = leaf_node_changed(conf, base + [ifname, 'vlan-to-vni', vlan, 'vni']) +            vxlan['vlan_to_vni_removed'].update({vlan : {'vni' : vni[0]}})      # We need to verify that no other VXLAN tunnel is configured when external      # mode is in use - Linux Kernel limitation @@ -98,14 +104,31 @@ def verify(vxlan):      if 'vni' not in vxlan and dict_search('parameters.external', vxlan) == None:          raise ConfigError('Must either configure VXLAN "vni" or use "external" CLI option!') -    if dict_search('parameters.external', vxlan): +    if dict_search('parameters.external', vxlan) != None:          if 'vni' in vxlan:              raise ConfigError('Can not specify both "external" and "VNI"!')          if 'other_tunnels' in vxlan: -            other_tunnels = ', '.join(vxlan['other_tunnels']) -            raise ConfigError(f'Only one VXLAN tunnel is supported when "external" '\ -                              f'CLI option is used. Additional tunnels: {other_tunnels}') +            # When multiple VXLAN interfaces are defined and "external" is used, +            # all VXLAN interfaces need to have vni-filter enabled! +            # See Linux Kernel commit f9c4bb0b245cee35ef66f75bf409c9573d934cf9 +            other_vni_filter = False +            for tunnel, tunnel_config in vxlan['other_tunnels'].items(): +                if dict_search('parameters.vni_filter', tunnel_config) != None: +                    other_vni_filter = True +                    break +            # eqivalent of the C foo ? 'a' : 'b' statement +            vni_filter = True and (dict_search('parameters.vni_filter', vxlan) != None) or False +            # If either one is enabled, so must be the other. Both can be off and both can be on +            if (vni_filter and not other_vni_filter) or (not vni_filter and other_vni_filter): +                raise ConfigError(f'Using multiple VXLAN interfaces with "external" '\ +                    'requires all VXLAN interfaces to have "vni-filter" configured!') + +            if not vni_filter and not other_vni_filter: +                other_tunnels = ', '.join(vxlan['other_tunnels']) +                raise ConfigError(f'Only one VXLAN tunnel is supported when "external" '\ +                                f'CLI option is used and "vni-filter" is unset. '\ +                                f'Additional tunnels: {other_tunnels}')      if 'gpe' in vxlan and 'external' not in vxlan:          raise ConfigError(f'VXLAN-GPE is only supported when "external" '\ @@ -165,7 +188,7 @@ def verify(vxlan):                  raise ConfigError(f'VNI "{vni}" is already assigned to a different VLAN!')              vnis_used.append(vni) -    if dict_search('parameters.neighbor_suppress', vxlan): +    if dict_search('parameters.neighbor_suppress', vxlan) != None:          if 'is_bridge_member' not in vxlan:              raise ConfigError('Neighbor suppression requires that VXLAN interface '\                                'is member of a bridge interface!') diff --git a/src/op_mode/bridge.py b/src/op_mode/bridge.py index 185db4f20..412a4eba8 100755 --- a/src/op_mode/bridge.py +++ b/src/op_mode/bridge.py @@ -56,6 +56,13 @@ def _get_raw_data_vlan(tunnel:bool=False):      data_dict = json.loads(json_data)      return data_dict +def _get_raw_data_vni() -> dict: +    """ +    :returns dict +    """ +    json_data = cmd(f'bridge --json vni show') +    data_dict = json.loads(json_data) +    return data_dict  def _get_raw_data_fdb(bridge):      """Get MAC-address for the bridge brX @@ -165,6 +172,22 @@ def _get_formatted_output_vlan_tunnel(data):      output = tabulate(data_entries, headers)      return output +def _get_formatted_output_vni(data): +    data_entries = [] +    for entry in data: +        interface = entry.get('ifname') +        vlans = entry.get('vnis') +        for vlan_entry in vlans: +            vlan = vlan_entry.get('vni') +            if vlan_entry.get('vniEnd'): +                vlan_end = vlan_entry.get('vniEnd') +                vlan = f'{vlan}-{vlan_end}' +            data_entries.append([interface, vlan]) + +    headers = ["Interface", "VNI"] +    output = tabulate(data_entries, headers) +    return output +  def _get_formatted_output_fdb(data):      data_entries = []      for entry in data: @@ -228,6 +251,12 @@ def show_vlan(raw: bool, tunnel: typing.Optional[bool]):          else:              return _get_formatted_output_vlan(bridge_vlan) +def show_vni(raw: bool): +    bridge_vni = _get_raw_data_vni() +    if raw: +        return bridge_vni +    else: +        return _get_formatted_output_vni(bridge_vni)  def show_fdb(raw: bool, interface: str):      fdb_data = _get_raw_data_fdb(interface) | 
