Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
policy-conf: T439: Add policy local-route PBR
- Loading branch information
1 parent
4dc9321
commit 7606fa6
Showing
5 changed files
with
240 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<?xml version="1.0"?> | ||
<!-- Policy local-route --> | ||
<interfaceDefinition> | ||
<node name="policy"> | ||
<children> | ||
<node name="local-route" owner="${vyos_conf_scripts_dir}/policy-local-route.py"> | ||
<properties> | ||
<help>IPv4 policy route of local traffic</help> | ||
</properties> | ||
<children> | ||
<tagNode name="rule"> | ||
<properties> | ||
<help>Policy local-route rule set number</help> | ||
<valueHelp> | ||
<!-- table main with prio 32766 --> | ||
<format><1-32765></format> | ||
<description>Local-route rule number (1-219)</description> | ||
</valueHelp> | ||
<constraint> | ||
<validator name="numeric" argument="--range 1-32765"/> | ||
</constraint> | ||
</properties> | ||
<children> | ||
<node name="set"> | ||
<properties> | ||
<help>Packet modifications</help> | ||
</properties> | ||
<children> | ||
<leafNode name="table"> | ||
<properties> | ||
<help>Routing table to forward packet with</help> | ||
<valueHelp> | ||
<format><1-200></format> | ||
<description>Table number</description> | ||
</valueHelp> | ||
<completionHelp> | ||
<list>main</list> | ||
</completionHelp> | ||
</properties> | ||
</leafNode> | ||
</children> | ||
</node> | ||
<leafNode name="source"> | ||
<properties> | ||
<help>Source address or prefix</help> | ||
<valueHelp> | ||
<format>ipv4</format> | ||
<description>Address to match against</description> | ||
</valueHelp> | ||
<valueHelp> | ||
<format>ipv4net</format> | ||
<description>Prefix to match against</description> | ||
</valueHelp> | ||
<constraint> | ||
<validator name="ipv4-address"/> | ||
<validator name="ip-prefix"/> | ||
</constraint> | ||
<multi/> | ||
</properties> | ||
</leafNode> | ||
</children> | ||
</tagNode> | ||
</children> | ||
</node> | ||
</children> | ||
</node> | ||
</interfaceDefinition> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Copyright (C) 2020 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 | ||
import unittest | ||
|
||
from vyos.configsession import ConfigSession | ||
from vyos.configsession import ConfigSessionError | ||
from vyos.util import cmd | ||
from vyos.util import process_named_running | ||
|
||
class PolicyLocalRouteTest(unittest.TestCase): | ||
def setUp(self): | ||
self.session = ConfigSession(os.getpid()) | ||
self._sources = ['203.0.113.1', '203.0.113.2'] | ||
|
||
def tearDown(self): | ||
# Delete all policies | ||
self.session.delete(['policy', 'local-route']) | ||
self.session.commit() | ||
del self.session | ||
|
||
# Test set table for some sources | ||
def test_table_id(self): | ||
base = ['policy', 'local-route'] | ||
rule = '50' | ||
table = '23' | ||
for src in self._sources: | ||
self.session.set(base + ['rule', rule, 'set', 'table', table]) | ||
self.session.set(base + ['rule', rule, 'source', src]) | ||
|
||
self.session.commit() | ||
|
||
# Check generated configuration | ||
|
||
# Expected values | ||
original = """ | ||
50: from 203.0.113.1 lookup 23 | ||
50: from 203.0.113.2 lookup 23 | ||
""" | ||
tmp = cmd('ip rule show prio 50') | ||
original = original.split() | ||
tmp = tmp.split() | ||
|
||
self.assertEqual(tmp, original) | ||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# Copyright (C) 2020 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 sys import exit | ||
|
||
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.util 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', 'local-route'] | ||
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']) | ||
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) | ||
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) | ||
pbr.update(dict) | ||
|
||
return pbr | ||
|
||
def verify(pbr): | ||
# bail out early - looks like removal from running config | ||
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!') | ||
|
||
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 | ||
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}') | ||
|
||
# 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}') | ||
|
||
return None | ||
|
||
if __name__ == '__main__': | ||
try: | ||
c = get_config() | ||
verify(c) | ||
generate(c) | ||
apply(c) | ||
except ConfigError as e: | ||
print(e) | ||
exit(1) |