summaryrefslogtreecommitdiff
path: root/src/conf_mode/policy-local-route.py
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2023-12-30 23:25:20 +0100
committerChristian Breunig <christian@breunig.cc>2024-01-01 09:25:32 +0100
commitc9eaafd9f808aba8d29be73054e11d37577e539a (patch)
treeaeccfda0a305cf6aca41630900e75bd32961a911 /src/conf_mode/policy-local-route.py
parent2078253176046ea4d07e69caeb7932ea439b5614 (diff)
downloadvyos-1x-c9eaafd9f808aba8d29be73054e11d37577e539a.tar.gz
vyos-1x-c9eaafd9f808aba8d29be73054e11d37577e539a.zip
T5474: establish common file name pattern for XML conf mode commands
We will use _ as CLI level divider. The XML definition filename and also the Python helper should match the CLI node. Example: set interfaces ethernet -> interfaces_ethernet.xml.in set interfaces bond -> interfaces_bond.xml.in set service dhcp-server -> service_dhcp-server-xml.in (cherry picked from commit 4ef110fd2c501b718344c72d495ad7e16d2bd465)
Diffstat (limited to 'src/conf_mode/policy-local-route.py')
-rwxr-xr-xsrc/conf_mode/policy-local-route.py315
1 files changed, 0 insertions, 315 deletions
diff --git a/src/conf_mode/policy-local-route.py b/src/conf_mode/policy-local-route.py
deleted file mode 100755
index 91e4fce2c..000000000
--- a/src/conf_mode/policy-local-route.py
+++ /dev/null
@@ -1,315 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020-2023 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/>.
-
-import os
-
-from itertools import product
-from sys import exit
-
-from netifaces import interfaces
-from vyos.config import Config
-from vyos.configdict import dict_merge
-from vyos.configdict import node_changed
-from vyos.configdict import leaf_node_changed
-from vyos.template import render
-from vyos.utils.process import call
-from vyos import ConfigError
-from vyos import airbag
-airbag.enable()
-
-
-def get_config(config=None):
-
- if config:
- conf = config
- else:
- conf = Config()
- base = ['policy']
-
- pbr = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
-
- 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', 'address'])
- src_port = leaf_node_changed(conf, base_rule + [rule, 'source', 'port'])
- fwmk = leaf_node_changed(conf, base_rule + [rule, 'fwmark'])
- iif = leaf_node_changed(conf, base_rule + [rule, 'inbound-interface'])
- dst = leaf_node_changed(conf, base_rule + [rule, 'destination', 'address'])
- dst_port = leaf_node_changed(conf, base_rule + [rule, 'destination', 'port'])
- table = leaf_node_changed(conf, base_rule + [rule, 'set', 'table'])
- proto = leaf_node_changed(conf, base_rule + [rule, 'protocol'])
- rule_def = {}
- if src:
- rule_def = dict_merge({'source': {'address': src}}, rule_def)
- if src_port:
- rule_def = dict_merge({'source': {'port': src_port}}, rule_def)
- if fwmk:
- rule_def = dict_merge({'fwmark' : fwmk}, rule_def)
- if iif:
- rule_def = dict_merge({'inbound_interface' : iif}, rule_def)
- if dst:
- rule_def = dict_merge({'destination': {'address': dst}}, rule_def)
- if dst_port:
- rule_def = dict_merge({'destination': {'port': dst_port}}, rule_def)
- if table:
- rule_def = dict_merge({'table' : table}, rule_def)
- if proto:
- rule_def = dict_merge({'protocol' : proto}, rule_def)
- dict = dict_merge({dict_id : {rule : rule_def}}, dict)
- pbr.update(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, rule_config in pbr[route]['rule'].items():
- src = leaf_node_changed(conf, base_rule + [rule, 'source', 'address'])
- src_port = leaf_node_changed(conf, base_rule + [rule, 'source', 'port'])
- fwmk = leaf_node_changed(conf, base_rule + [rule, 'fwmark'])
- iif = leaf_node_changed(conf, base_rule + [rule, 'inbound-interface'])
- dst = leaf_node_changed(conf, base_rule + [rule, 'destination', 'address'])
- dst_port = leaf_node_changed(conf, base_rule + [rule, 'destination', 'port'])
- table = leaf_node_changed(conf, base_rule + [rule, 'set', 'table'])
- proto = leaf_node_changed(conf, base_rule + [rule, 'protocol'])
- # keep track of changes in configuration
- # otherwise we might remove an existing node although nothing else has changed
- changed = False
-
- rule_def = {}
- # src is None if there are no changes to src
- if src is None:
- # if src hasn't changed, include it in the removal selector
- # if a new selector is added, we have to remove all previous rules without this selector
- # to make sure we remove all previous rules with this source(s), it will be included
- if 'source' in rule_config:
- if 'address' in rule_config['source']:
- rule_def = dict_merge({'source': {'address': rule_config['source']['address']}}, rule_def)
- else:
- # if src is not None, it's previous content will be returned
- # this can be an empty array if it's just being set, or the previous value
- # either way, something has to be changed and we only want to remove previous values
- changed = True
- # set the old value for removal if it's not empty
- if len(src) > 0:
- rule_def = dict_merge({'source': {'address': src}}, rule_def)
-
- # source port
- if src_port is None:
- if 'source' in rule_config:
- if 'port' in rule_config['source']:
- tmp = rule_config['source']['port']
- if isinstance(tmp, str):
- tmp = [tmp]
- rule_def = dict_merge({'source': {'port': tmp}}, rule_def)
- else:
- changed = True
- if len(src_port) > 0:
- rule_def = dict_merge({'source': {'port': src_port}}, rule_def)
-
- # fwmark
- if fwmk is None:
- if 'fwmark' in rule_config:
- tmp = rule_config['fwmark']
- if isinstance(tmp, str):
- tmp = [tmp]
- rule_def = dict_merge({'fwmark': tmp}, rule_def)
- else:
- changed = True
- if len(fwmk) > 0:
- rule_def = dict_merge({'fwmark' : fwmk}, rule_def)
-
- # inbound-interface
- if iif is None:
- if 'inbound_interface' in rule_config:
- rule_def = dict_merge({'inbound_interface': rule_config['inbound_interface']}, rule_def)
- else:
- changed = True
- if len(iif) > 0:
- rule_def = dict_merge({'inbound_interface' : iif}, rule_def)
-
- # destination address
- if dst is None:
- if 'destination' in rule_config:
- if 'address' in rule_config['destination']:
- rule_def = dict_merge({'destination': {'address': rule_config['destination']['address']}}, rule_def)
- else:
- changed = True
- if len(dst) > 0:
- rule_def = dict_merge({'destination': {'address': dst}}, rule_def)
-
- # destination port
- if dst_port is None:
- if 'destination' in rule_config:
- if 'port' in rule_config['destination']:
- tmp = rule_config['destination']['port']
- if isinstance(tmp, str):
- tmp = [tmp]
- rule_def = dict_merge({'destination': {'port': tmp}}, rule_def)
- else:
- changed = True
- if len(dst_port) > 0:
- rule_def = dict_merge({'destination': {'port': dst_port}}, rule_def)
-
- # table
- if table is None:
- if 'set' in rule_config and 'table' in rule_config['set']:
- rule_def = dict_merge({'table': [rule_config['set']['table']]}, rule_def)
- else:
- changed = True
- if len(table) > 0:
- rule_def = dict_merge({'table' : table}, rule_def)
-
- # protocol
- if proto is None:
- if 'protocol' in rule_config:
- tmp = rule_config['protocol']
- if isinstance(tmp, str):
- tmp = [tmp]
- rule_def = dict_merge({'protocol': tmp}, rule_def)
- else:
- changed = True
- if len(proto) > 0:
- rule_def = dict_merge({'protocol' : proto}, rule_def)
-
- if changed:
- dict = dict_merge({dict_id : {rule : rule_def}}, dict)
- pbr.update(dict)
-
- return pbr
-
-def verify(pbr):
- # bail out early - looks like removal from running config
- if not pbr:
- return None
-
- 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] and
- 'inbound_interface' not in pbr_route['rule'][rule] and
- 'protocol' not in pbr_route['rule'][rule]
- ):
- raise ConfigError('Source or destination address or fwmark or inbound-interface or protocol is required!')
-
- if 'set' not in pbr_route['rule'][rule] or 'table' not in pbr_route['rule'][rule]['set']:
- raise ConfigError('Table set is required!')
-
- if 'inbound_interface' in pbr_route['rule'][rule]:
- interface = pbr_route['rule'][rule]['inbound_interface']
- if interface not in interfaces():
- raise ConfigError(f'Interface "{interface}" does not exist')
-
- return None
-
-def generate(pbr):
- if not pbr:
- return None
-
- return None
-
-def apply(pbr):
- if not pbr:
- return None
-
- # Delete old rule if needed
- 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():
- source = rule_config.get('source', {}).get('address', [''])
- source_port = rule_config.get('source', {}).get('port', [''])
- destination = rule_config.get('destination', {}).get('address', [''])
- destination_port = rule_config.get('destination', {}).get('port', [''])
- fwmark = rule_config.get('fwmark', [''])
- inbound_interface = rule_config.get('inbound_interface', [''])
- protocol = rule_config.get('protocol', [''])
- table = rule_config.get('table', [''])
-
- for src, dst, src_port, dst_port, fwmk, iif, proto, table in product(
- source, destination, source_port, destination_port,
- fwmark, inbound_interface, protocol, table):
- f_src = '' if src == '' else f' from {src} '
- f_src_port = '' if src_port == '' else f' sport {src_port} '
- f_dst = '' if dst == '' else f' to {dst} '
- f_dst_port = '' if dst_port == '' else f' dport {dst_port} '
- f_fwmk = '' if fwmk == '' else f' fwmark {fwmk} '
- f_iif = '' if iif == '' else f' iif {iif} '
- f_proto = '' if proto == '' else f' ipproto {proto} '
- f_table = '' if table == '' else f' lookup {table} '
-
- call(f'ip{v6} rule del prio {rule} {f_src}{f_dst}{f_proto}{f_src_port}{f_dst_port}{f_fwmk}{f_iif}{f_table}')
-
- # Generate new config
- 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'].get('table', '')
- source = rule_config.get('source', {}).get('address', ['all'])
- source_port = rule_config.get('source', {}).get('port', '')
- destination = rule_config.get('destination', {}).get('address', ['all'])
- destination_port = rule_config.get('destination', {}).get('port', '')
- fwmark = rule_config.get('fwmark', '')
- inbound_interface = rule_config.get('inbound_interface', '')
- protocol = rule_config.get('protocol', '')
-
- for src in source:
- f_src = f' from {src} ' if src else ''
- for dst in destination:
- f_dst = f' to {dst} ' if dst else ''
- f_src_port = f' sport {source_port} ' if source_port else ''
- f_dst_port = f' dport {destination_port} ' if destination_port else ''
- f_fwmk = f' fwmark {fwmark} ' if fwmark else ''
- f_iif = f' iif {inbound_interface} ' if inbound_interface else ''
- f_proto = f' ipproto {protocol} ' if protocol else ''
-
- call(f'ip{v6} rule add prio {rule}{f_src}{f_dst}{f_proto}{f_src_port}{f_dst_port}{f_fwmk}{f_iif} lookup {table}')
-
- return None
-
-if __name__ == '__main__':
- try:
- c = get_config()
- verify(c)
- generate(c)
- apply(c)
- except ConfigError as e:
- print(e)
- exit(1)