diff options
author | Henning Surmeier <me@hensur.de> | 2022-01-08 12:44:12 +0100 |
---|---|---|
committer | Henning Surmeier <me@hensur.de> | 2022-02-14 21:43:53 +0100 |
commit | e11a7ff1b2817cc8f4b595171fe82a43a209ebc2 (patch) | |
tree | d0460f227348cc59452ab9d12a75f8e8a0e7b0f7 /src | |
parent | 3ecdcc69401bddaa4b07fe024da149d6edb5da2d (diff) | |
download | vyos-1x-e11a7ff1b2817cc8f4b595171fe82a43a209ebc2.tar.gz vyos-1x-e11a7ff1b2817cc8f4b595171fe82a43a209ebc2.zip |
backport: policy: T4151: Add policy ipv6-local-route
Adds support for `ip -6 rule` policy based routing.
Also, extends the existing ipv4 implemenation with a
`destination` key, which is translated as
`ip rule add to x.x.x.x/x` rules.
https://phabricator.vyos.net/T4151
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/policy-local-route.py | 118 |
1 files changed, 86 insertions, 32 deletions
diff --git a/src/conf_mode/policy-local-route.py b/src/conf_mode/policy-local-route.py index 013f22665..97ee6a785 100755 --- a/src/conf_mode/policy-local-route.py +++ b/src/conf_mode/policy-local-route.py @@ -35,25 +35,53 @@ def get_config(config=None): conf = config else: conf = Config() - base = ['policy', 'local-route'] + base = ['policy'] + pbr = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) - # delete policy local-route - dict = {} - tmp = node_changed(conf, ['policy', 'local-route', 'rule'], key_mangling=('-', '_')) - if tmp: - for rule in (tmp or []): - src = leaf_node_changed(conf, ['policy', 'local-route', 'rule', rule, 'source']) - if src: - dict = dict_merge({'rule_remove' : {rule : {'source' : src}}}, dict) + for route in ['local_route', 'local_route6']: + dict_id = 'rule_remove' if route == 'local_route' else 'rule6_remove' + route_key = 'local-route' if route == 'local_route' else 'local-route6' + base_rule = base + [route_key, 'rule'] + + # delete policy local-route + dict = {} + tmp = node_changed(conf, base_rule, key_mangling=('-', '_')) + if tmp: + for rule in (tmp or []): + src = leaf_node_changed(conf, base_rule + [rule, 'source']) + fwmk = leaf_node_changed(conf, base_rule + [rule, 'fwmark']) + dst = leaf_node_changed(conf, base_rule + [rule, 'destination']) + rule_def = {} + if src: + rule_def = dict_merge({'source' : src}, rule_def) + if fwmk: + rule_def = dict_merge({'fwmark' : fwmk}, rule_def) + if dst: + rule_def = dict_merge({'destination' : dst}, rule_def) + dict = dict_merge({dict_id : {rule : rule_def}}, dict) pbr.update(dict) - # delete policy local-route rule x source x.x.x.x - if 'rule' in pbr: - for rule in pbr['rule']: - src = leaf_node_changed(conf, ['policy', 'local-route', 'rule', rule, 'source']) - if src: - dict = dict_merge({'rule_remove' : {rule : {'source' : src}}}, dict) + if not route in pbr: + continue + + # delete policy local-route rule x source x.x.x.x + # delete policy local-route rule x fwmark x + # delete policy local-route rule x destination x.x.x.x + if 'rule' in pbr[route]: + for rule in pbr[route]['rule']: + src = leaf_node_changed(conf, base_rule + [rule, 'source']) + fwmk = leaf_node_changed(conf, base_rule + [rule, 'fwmark']) + dst = leaf_node_changed(conf, base_rule + [rule, 'destination']) + + rule_def = {} + if src: + rule_def = dict_merge({'source' : src}, rule_def) + if fwmk: + rule_def = dict_merge({'fwmark' : fwmk}, rule_def) + if dst: + rule_def = dict_merge({'destination' : dst}, rule_def) + dict = dict_merge({dict_id : {rule : rule_def}}, dict) pbr.update(dict) return pbr @@ -63,13 +91,18 @@ def verify(pbr): if not pbr: return None - if 'rule' in pbr: - for rule in pbr['rule']: - if 'source' not in pbr['rule'][rule]: - raise ConfigError('Source address required!') - else: - if 'set' not in pbr['rule'][rule] or 'table' not in pbr['rule'][rule]['set']: - raise ConfigError('Table set is required!') + for route in ['local_route', 'local_route6']: + if not route in pbr: + continue + + pbr_route = pbr[route] + if 'rule' in pbr_route: + for rule in pbr_route['rule']: + if 'source' not in pbr_route['rule'][rule] and 'destination' not in pbr_route['rule'][rule] and 'fwmark' not in pbr_route['rule'][rule]: + raise ConfigError('Source or destination address or fwmark is required!') + else: + if 'set' not in pbr_route['rule'][rule] or 'table' not in pbr_route['rule'][rule]['set']: + raise ConfigError('Table set is required!') return None @@ -84,18 +117,39 @@ def apply(pbr): return None # Delete old rule if needed - if 'rule_remove' in pbr: - for rule in pbr['rule_remove']: - for src in pbr['rule_remove'][rule]['source']: - call(f'ip rule del prio {rule} from {src}') + for rule_rm in ['rule_remove', 'rule6_remove']: + if rule_rm in pbr: + v6 = " -6" if rule_rm == 'rule6_remove' else "" + for rule, rule_config in pbr[rule_rm].items(): + for src in (rule_config['source'] or ['']): + f_src = '' if src == '' else f' from {src} ' + for dst in (rule_config['destination'] or ['']): + f_dst = '' if dst == '' else f' to {dst} ' + for fwmk in (rule_config['fwmark'] or ['']): + f_fwmk = '' if fwmk == '' else f' fwmark {fwmk} ' + call(f'ip{v6} rule del prio {rule} {f_src}{f_dst}{f_fwmk}') # Generate new config - if 'rule' in pbr: - for rule in pbr['rule']: - table = pbr['rule'][rule]['set']['table'] - if pbr['rule'][rule]['source']: - for src in pbr['rule'][rule]['source']: - call(f'ip rule add prio {rule} from {src} lookup {table}') + for route in ['local_route', 'local_route6']: + if not route in pbr: + continue + + v6 = " -6" if route == 'local_route6' else "" + + pbr_route = pbr[route] + if 'rule' in pbr_route: + for rule, rule_config in pbr_route['rule'].items(): + table = rule_config['set']['table'] + + for src in (rule_config['source'] or ['all']): + f_src = '' if src == '' else f' from {src} ' + for dst in (rule_config['destination'] or ['all']): + f_dst = '' if dst == '' else f' to {dst} ' + f_fwmk = '' + if 'fwmark' in rule_config: + fwmk = rule_config['fwmark'] + f_fwmk = f' fwmark {fwmk} ' + call(f'ip{v6} rule add prio {rule} {f_src}{f_dst}{f_fwmk} lookup {table}') return None |