diff options
-rw-r--r-- | interface-definitions/system-ip.xml.in | 3 | ||||
-rwxr-xr-x | smoketest/scripts/cli/test_system_ip.py | 79 | ||||
-rwxr-xr-x | src/conf_mode/system-ip.py | 79 |
3 files changed, 119 insertions, 42 deletions
diff --git a/interface-definitions/system-ip.xml.in b/interface-definitions/system-ip.xml.in index 14b3b8a07..0bd461042 100644 --- a/interface-definitions/system-ip.xml.in +++ b/interface-definitions/system-ip.xml.in @@ -15,7 +15,7 @@ <children> <leafNode name="table-size"> <properties> - <help>Maximum number of entries to keep in the ARP cache</help> + <help>Maximum number of entries to keep in the ARP cache (default: 8192)</help> <completionHelp> <list>1024 2048 4096 8192 16384 32768</list> </completionHelp> @@ -23,6 +23,7 @@ <regex>(1024|2048|4096|8192|16384|32768)</regex> </constraint> </properties> + <defaultValue>8192</defaultValue> </leafNode> </children> </node> diff --git a/smoketest/scripts/cli/test_system_ip.py b/smoketest/scripts/cli/test_system_ip.py new file mode 100755 index 000000000..4fcaaa465 --- /dev/null +++ b/smoketest/scripts/cli/test_system_ip.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2020 Francois Mertz fireboxled@gmail.com +# +# 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.util import read_file + +base_path = ['system', 'ip'] + +class TestSystemIP(unittest.TestCase): + def setUp(self): + self.session = ConfigSession(os.getpid()) + + def tearDown(self): + self.session.delete(base_path) + self.session.commit() + del self.session + + def test_system_ip_forwarding(self): + """ Test if IPv4 forwarding can be disabled globally, default is '1' + which means forwearding enabled """ + all_forwarding = '/proc/sys/net/ipv4/conf/all/forwarding' + self.assertEqual(read_file(all_forwarding), '1') + + self.session.set(base_path + ['disable-forwarding']) + self.session.commit() + + self.assertEqual(read_file(all_forwarding), '0') + + def test_system_ip_multipath(self): + """ test IPv4 multipathing options, options default to off -> '0' """ + use_neigh = '/proc/sys/net/ipv4/fib_multipath_use_neigh' + hash_policy = '/proc/sys/net/ipv4/fib_multipath_hash_policy' + + self.assertEqual(read_file(use_neigh), '0') + self.assertEqual(read_file(hash_policy), '0') + + self.session.set(base_path + ['multipath', 'ignore-unreachable-nexthops']) + self.session.set(base_path + ['multipath', 'layer4-hashing']) + self.session.commit() + + self.assertEqual(read_file(use_neigh), '1') + self.assertEqual(read_file(hash_policy), '1') + + def test_system_ip_arp_table_size(self): + """ Maximum number of entries to keep in the ARP cache, the default is 8k """ + + gc_thresh3 = '/proc/sys/net/ipv4/neigh/default/gc_thresh3' + gc_thresh2 = '/proc/sys/net/ipv4/neigh/default/gc_thresh2' + gc_thresh1 = '/proc/sys/net/ipv4/neigh/default/gc_thresh1' + self.assertEqual(read_file(gc_thresh3), '8192') + self.assertEqual(read_file(gc_thresh2), '4096') + self.assertEqual(read_file(gc_thresh1), '1024') + + for size in [1024, 2048, 4096, 8192, 16384, 32768]: + self.session.set(base_path + ['arp', 'table-size', str(size)]) + self.session.commit() + + self.assertEqual(read_file(gc_thresh3), str(size)) + self.assertEqual(read_file(gc_thresh2), str(size // 2)) + self.assertEqual(read_file(gc_thresh1), str(size // 8)) + +if __name__ == '__main__': + unittest.main() diff --git a/src/conf_mode/system-ip.py b/src/conf_mode/system-ip.py index 64c9e6d05..190a0daca 100755 --- a/src/conf_mode/system-ip.py +++ b/src/conf_mode/system-ip.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019 VyOS maintainers and contributors +# Copyright (C) 2019-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 @@ -14,68 +14,65 @@ # 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 copy import deepcopy + from vyos.config import Config -from vyos import ConfigError +from vyos.configdict import dict_merge from vyos.util import call - +from vyos.util import dict_search +from vyos.xml import defaults +from vyos import ConfigError from vyos import airbag airbag.enable() -default_config_data = { - 'arp_table': 8192, - 'ipv4_forward': '1', - 'mp_unreach_nexthop': '0', - 'mp_layer4_hashing': '0' -} - def sysctl(name, value): - call('sysctl -wq {}={}'.format(name, value)) + call(f'sysctl -wq {name}={value}') def get_config(config=None): - ip_opt = deepcopy(default_config_data) if config: conf = config else: conf = Config() - conf.set_level('system ip') - if conf.exists(''): - if conf.exists('arp table-size'): - ip_opt['arp_table'] = int(conf.return_value('arp table-size')) - - if conf.exists('disable-forwarding'): - ip_opt['ipv4_forward'] = '0' + base = ['system', 'ip'] - if conf.exists('multipath ignore-unreachable-nexthops'): - ip_opt['mp_unreach_nexthop'] = '1' + opt = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True) + # We have gathered the dict representation of the CLI, but there are default + # options which we need to update into the dictionary retrived. + default_values = defaults(base) + opt = dict_merge(default_values, opt) - if conf.exists('multipath layer4-hashing'): - ip_opt['mp_layer4_hashing'] = '1' + return opt - return ip_opt - -def verify(ip_opt): +def verify(opt): pass -def generate(ip_opt): +def generate(opt): pass -def apply(ip_opt): - # apply ARP threshold values - sysctl('net.ipv4.neigh.default.gc_thresh3', ip_opt['arp_table']) - sysctl('net.ipv4.neigh.default.gc_thresh2', ip_opt['arp_table'] // 2) - sysctl('net.ipv4.neigh.default.gc_thresh1', ip_opt['arp_table'] // 8) +def apply(opt): + size = int(dict_search('arp.table_size', opt)) + if size: + # apply ARP threshold values + sysctl('net.ipv4.neigh.default.gc_thresh3', str(size)) + sysctl('net.ipv4.neigh.default.gc_thresh2', str(size // 2)) + sysctl('net.ipv4.neigh.default.gc_thresh1', str(size // 8)) # enable/disable IPv4 forwarding - with open('/proc/sys/net/ipv4/conf/all/forwarding', 'w') as f: - f.write(ip_opt['ipv4_forward']) - - # configure multipath - sysctl('net.ipv4.fib_multipath_use_neigh', ip_opt['mp_unreach_nexthop']) - sysctl('net.ipv4.fib_multipath_hash_policy', ip_opt['mp_layer4_hashing']) + tmp = '1' + if 'disable_forwarding' in opt: + tmp = '0' + sysctl('net.ipv4.conf.all.forwarding', tmp) + + tmp = '0' + # configure multipath - dict_search() returns an empty dict if key was found + if isinstance(dict_search('multipath.ignore_unreachable_nexthops', opt), dict): + tmp = '1' + sysctl('net.ipv4.fib_multipath_use_neigh', tmp) + + tmp = '0' + if isinstance(dict_search('multipath.ignore_unreachable_nexthops', opt), dict): + tmp = '1' + sysctl('net.ipv4.fib_multipath_hash_policy', tmp) if __name__ == '__main__': try: |