diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/completion/qos/list_traffic_match_group.py | 35 | ||||
| -rwxr-xr-x | src/conf_mode/qos.py | 77 | 
2 files changed, 107 insertions, 5 deletions
| diff --git a/src/completion/qos/list_traffic_match_group.py b/src/completion/qos/list_traffic_match_group.py new file mode 100644 index 000000000..015d7ada9 --- /dev/null +++ b/src/completion/qos/list_traffic_match_group.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 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 +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. + +from vyos.config import Config + + +def get_qos_traffic_match_group(): +    config = Config() +    base = ['qos', 'traffic-match-group'] +    conf = config.get_config_dict(base, key_mangling=('-', '_')) +    groups = [] + +    for group in conf.get('traffic_match_group', []): +        groups.append(group) + +    return groups + + +if __name__ == "__main__": +    groups = get_qos_traffic_match_group() +    print(" ".join(groups)) + diff --git a/src/conf_mode/qos.py b/src/conf_mode/qos.py index 8a590cbc6..45248fb4a 100755 --- a/src/conf_mode/qos.py +++ b/src/conf_mode/qos.py @@ -17,6 +17,7 @@  from sys import exit  from netifaces import interfaces +from vyos.base import Warning  from vyos.config import Config  from vyos.configdep import set_dependents  from vyos.configdep import call_dependents @@ -89,6 +90,36 @@ def _clean_conf_dict(conf):          return conf +def _get_group_filters(config: dict, group_name: str, visited=None) -> dict: +    filters = dict() +    if not visited: +        visited = [group_name, ] +    else: +        if group_name in visited: +            return filters +        visited.append(group_name) + +    for filter, filter_config in config.get(group_name, {}).items(): +        if filter == 'match': +            for match, match_config in filter_config.items(): +               filters[f'{group_name}-{match}'] = match_config +        elif filter == 'match_group': +            for group in filter_config: +                filters.update(_get_group_filters(config, group, visited)) + +    return filters + + +def _get_group_match(config:dict, group_name:str) -> dict: +    match = dict() +    for key, val in _get_group_filters(config, group_name).items(): +        # delete duplicate matches +        if val not in match.values(): +            match[key] = val + +    return match + +  def get_config(config=None):      if config:          conf = config @@ -135,11 +166,27 @@ def get_config(config=None):      qos = conf.merge_defaults(qos, recursive=True) +    if 'traffic_match_group' in qos: +        for group, group_config in qos['traffic_match_group'].items(): +            if 'match_group' in group_config: +                qos['traffic_match_group'][group]['match'] = _get_group_match(qos['traffic_match_group'], group) +      for policy in qos.get('policy', []):          for p_name, p_config in qos['policy'][policy].items():              # cleanup empty match config              if 'class' in p_config:                  for cls, cls_config in p_config['class'].items(): +                    if 'match_group' in cls_config: +                        # merge group match to match +                        for group in cls_config['match_group']: +                            for match, match_conf in qos['traffic_match_group'].get(group, {'match': {}})['match'].items(): +                                if 'match' not in cls_config: +                                    cls_config['match'] = dict() +                                if match in cls_config['match']: +                                    cls_config['match'][f'{group}-{match}'] = match_conf +                                else: +                                    cls_config['match'][match] = match_conf +                      if 'match' in cls_config:                          cls_config['match'] = _clean_conf_dict(cls_config['match'])                          if cls_config['match'] == {}: @@ -147,6 +194,22 @@ def get_config(config=None):      return qos + +def _verify_match(cls_config: dict) -> None: +    if 'match' in cls_config: +        for match, match_config in cls_config['match'].items(): +            if {'ip', 'ipv6'} <= set(match_config): +                raise ConfigError( +                    f'Can not use both IPv6 and IPv4 in one match ({match})!') + + +def _verify_match_group_exist(cls_config, qos): +    if 'match_group' in cls_config: +        for group in cls_config['match_group']: +            if 'traffic_match_group' not in qos or group not in qos['traffic_match_group']: +                Warning(f'Match group "{group}" does not exist!') + +  def verify(qos):      if not qos or 'interface' not in qos:          return None @@ -174,11 +237,8 @@ def verify(qos):                          # bandwidth is not mandatory for priority-queue - that is why this is on the exception list                          if 'bandwidth' not in cls_config and policy_type not in ['priority_queue', 'round_robin', 'shaper_hfsc']:                              raise ConfigError(f'Bandwidth must be defined for policy "{policy}" class "{cls}"!') -                    if 'match' in cls_config: -                        for match, match_config in cls_config['match'].items(): -                            if {'ip', 'ipv6'} <= set(match_config): -                                 raise ConfigError(f'Can not use both IPv6 and IPv4 in one match ({match})!') - +                        _verify_match(cls_config) +                        _verify_match_group_exist(cls_config, qos)                  if policy_type in ['random_detect']:                      if 'precedence' in policy_config:                          for precedence, precedence_config in policy_config['precedence'].items(): @@ -216,8 +276,14 @@ def verify(qos):              if direction not in tmp:                  raise ConfigError(f'Selected QoS policy on interface "{interface}" only supports "{tmp}"!') +    if 'traffic_match_group' in qos: +        for group, group_config in qos['traffic_match_group'].items(): +            _verify_match(group_config) +            _verify_match_group_exist(group_config, qos) +      return None +  def generate(qos):      if not qos or 'interface' not in qos:          return None @@ -254,6 +320,7 @@ def apply(qos):      return None +  if __name__ == '__main__':      try:          c = get_config() | 
