Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

frrender: T6991: do not loose DHCP default route when no static route is defined #4270

Merged
merged 1 commit into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions python/vyos/frrender.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,17 +360,24 @@ def dict_helper_pim_defaults(pim, path):
static = conf.get_config_dict(static_cli_path, key_mangling=('-', '_'),
get_first_key=True,
no_tag_node_value_mangle=True)

# T3680 - get a list of all interfaces currently configured to use DHCP
tmp = get_dhcp_interfaces(conf)
if tmp: static.update({'dhcp' : tmp})
tmp = get_pppoe_interfaces(conf)
if tmp: static.update({'pppoe' : tmp})

dict.update({'static' : static})
elif conf.exists_effective(static_cli_path):
dict.update({'static' : {'deleted' : ''}})

# T3680 - get a list of all interfaces currently configured to use DHCP
tmp = get_dhcp_interfaces(conf)
if tmp:
if 'static' in dict:
dict['static'].update({'dhcp' : tmp})
else:
dict.update({'static' : {'dhcp' : tmp}})
tmp = get_pppoe_interfaces(conf)
if tmp:
if 'static' in dict:
dict['static'].update({'pppoe' : tmp})
else:
dict.update({'static' : {'pppoe' : tmp}})

# keep a re-usable list of dependent VRFs
dependent_vrfs_default = {}
if 'bgp' in dict:
Expand Down Expand Up @@ -534,6 +541,10 @@ def dict_helper_pim_defaults(pim, path):

dict.update({'vrf' : vrf})

if os.path.exists(frr_debug_enable):
import pprint
pprint.pprint(dict)

return dict

class FRRender:
Expand Down
51 changes: 50 additions & 1 deletion smoketest/scripts/cli/test_protocols_static.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,19 @@
# 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 time import sleep
from base_vyostest_shim import VyOSUnitTestSHIM

from vyos.configsession import ConfigSessionError
from vyos.template import is_ipv6
from vyos.template import get_dhcp_router
from vyos.utils.network import get_interface_config
from vyos.utils.network import get_vrf_tableid
from vyos.utils.process import process_named_running
from vyos.xml_ref import default_value

base_path = ['protocols', 'static']
vrf_path = ['protocols', 'vrf']
Expand Down Expand Up @@ -163,16 +168,18 @@ class TestProtocolsStatic(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
super(TestProtocolsStatic, cls).setUpClass()
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['vrf'])
cls.cli_set(cls, ['vrf', 'name', 'black', 'table', '43210'])

@classmethod
def tearDownClass(cls):
cls.cli_delete(cls, base_path)
cls.cli_delete(cls, ['vrf'])
super(TestProtocolsStatic, cls).tearDownClass()

def tearDown(self):
self.cli_delete(base_path)
self.cli_delete(['vrf'])
self.cli_commit()

v4route = self.getFRRconfig('ip route', end='')
Expand All @@ -181,6 +188,7 @@ def tearDown(self):
self.assertFalse(v6route)

def test_01_static(self):
self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
for route, route_config in routes.items():
route_type = 'route'
if is_ipv6(route):
Expand Down Expand Up @@ -315,6 +323,7 @@ def test_01_static(self):
self.assertIn(tmp, frrconfig)

def test_02_static_table(self):
self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
for table in tables:
for route, route_config in routes.items():
route_type = 'route'
Expand Down Expand Up @@ -409,6 +418,7 @@ def test_02_static_table(self):


def test_03_static_vrf(self):
self.cli_set(['vrf', 'name', 'black', 'table', '43210'])
# Create VRF instances and apply the static routes from above to FRR.
# Re-read the configured routes and match them if they are programmed
# properly. This also includes VRF leaking
Expand Down Expand Up @@ -567,5 +577,44 @@ def test_04_static_multicast(self):
else:
self.assertIn(tmp, frrconfig)

def test_05_dhcp_default_route(self):
# When running via vyos-build under the QEmu environment a local DHCP
# server is available. This test verifies that the default route is set.
# When not running under the VyOS QEMU environment, this test is skipped.
if not os.path.exists('/tmp/vyos.smoketests.hint'):
self.skipTest('Not running under VyOS CI/CD QEMU environment!')

interface = 'eth0'
interface_path = ['interfaces', 'ethernet', interface]
default_distance = default_value(interface_path + ['dhcp-options', 'default-route-distance'])
self.cli_set(interface_path + ['address', 'dhcp'])
self.cli_commit()

# Wait for dhclient to receive IP address and default gateway
sleep(5)

router = get_dhcp_router(interface)
frrconfig = self.getFRRconfig('')
self.assertIn(rf'ip route 0.0.0.0/0 {router} {interface} tag 210 {default_distance}', frrconfig)

# T6991: Default route is missing when there is no "protocols static"
# CLI node entry
self.cli_delete(base_path)
# We can trigger a FRR reconfiguration and config re-rendering when
# we simply disable IPv6 forwarding
self.cli_set(['system', 'ipv6', 'disable-forwarding'])
self.cli_commit()

# Re-check FRR configuration that default route is still present
frrconfig = self.getFRRconfig('')
self.assertIn(rf'ip route 0.0.0.0/0 {router} {interface} tag 210 {default_distance}', frrconfig)

self.cli_delete(interface_path + ['address'])
self.cli_commit()

# Wait for dhclient to stop
while process_named_running('dhclient', cmdline=interface, timeout=10):
sleep(0.250)

if __name__ == '__main__':
unittest.main(verbosity=2)
Loading