From 710616f8c43e6535acb2fe8160fb3712e7c1b2bf Mon Sep 17 00:00:00 2001 From: Joachim Wiberg Date: Thu, 24 Oct 2024 07:01:57 +0200 Subject: [PATCH] doc,test: clarify relationship between DHCP option 3 and 121 Signed-off-by: Joachim Wiberg --- doc/networking.md | 14 +++++--- test/case/infix_dhcp/dhcp_routes/Readme.adoc | 27 ++++++++++------ test/case/infix_dhcp/dhcp_routes/test.py | 34 ++++++++++++-------- 3 files changed, 48 insertions(+), 27 deletions(-) diff --git a/doc/networking.md b/doc/networking.md index f6ac9426..6a0a8d01 100644 --- a/doc/networking.md +++ b/doc/networking.md @@ -585,6 +585,9 @@ Multiple address assignment methods are available: | link-local | infix-ip | Auto-assignment of IPv4 address in 169.254.x.x/16 range | | dhcp | infix-dhcp-client | Assignment of IPv4 address by DHCP server, e.g., *10.0.1.1/24* | +> **Note:** DHCP address method is only available for *LAN* interfaces +> (Ethernet, virtual Ethernet (veth), bridge, link aggregates, etc.) + Supported DHCP (request) options, configurability (Cfg) and defaults, are listed below. Configurable options can be disabled on a per client interface basis, some options, like `clientid` and option 81, are @@ -616,8 +619,10 @@ client is not enabled, any NTP servers provided by the DHCP server will be ignored. For details on how to enable the NTP client, see the [NTP Client Configuration](system.md#ntp-client-configuration) section. -> **Note:** DHCP address method is only available for *LAN* interfaces -> (Ethernet, virtual Ethernet (veth), bridge, link aggregates, etc.) +> **Note:** as per [RFC3442][4], if the DHCP server returns both a +> Classless Static Routes option (121) and Router option (3), the +> DHCP client *must* ignore the latter. + ### IPv6 Address Assignment @@ -1059,7 +1064,7 @@ This CLI example show the IPv6 routing table. #### Route Preference -The operating system leverages FRRouting ([Frr][4]) as routing engine +The operating system leverages FRRouting ([Frr][0]) as routing engine for both static and dynamic routing. Even routes injected from a DHCP client, and IPv4 link-local (IPv4) routes, are injected into Frr to let it weigh all routes before installing them into the kernel routing table @@ -1113,7 +1118,8 @@ currently supported, namely `ipv4` and `ipv6`. [1]: https://www.rfc-editor.org/rfc/rfc8343 [2]: https://www.rfc-editor.org/rfc/rfc8344 [3]: https://www.rfc-editor.org/rfc/rfc8981 -[4]: https://frrouting.org/ +[4]: https://www.rfc-editor.org/rfc/rfc3442 +[0]: https://frrouting.org/ [^1]: Please note, link aggregates are not yet supported in Infix. [^2]: Link-local IPv6 addresses are implicitly enabled when enabling diff --git a/test/case/infix_dhcp/dhcp_routes/Readme.adoc b/test/case/infix_dhcp/dhcp_routes/Readme.adoc index 9b7224df..007ad217 100644 --- a/test/case/infix_dhcp/dhcp_routes/Readme.adoc +++ b/test/case/infix_dhcp/dhcp_routes/Readme.adoc @@ -1,12 +1,18 @@ === DHCP option 121 vs option 3 ==== Description -Verify DHCP option 121 (static routes) is used over option 3 and that the -routes exist in the operational datastore. +Verify that DHCP option 121 (classless static routes) is used over the +older option 3 (default gateway) in the DHCP client, when both are sent +by the server, see RFC3442. Use the routing RIB in the operational +datastore to verify. -Installing unrelated routes from a DHCP server should not affect already -existing routes. To verify this, a canary route is set up in the client -before initiating DHCP. This canary route does not need to be reachable -before a DHCP lease has been acquired. +Installing routes from a DHCP server should not affect already existing +(static) routes. To verify this, a static canary route (20.0.0.0/24 via +192.168.0.2) is installed before starting the DHCP client. As a twist, +this canary route has a next-hop (192.168.0.2) which is not reachable +until a DHCP lease has been acquired. + +The DHCP server is set up to hand out both a default router (option 3) +via 192.168.0.1 and a default route (option 121) via 192.168.0.254. ==== Topology ifdef::topdoc[] @@ -21,10 +27,11 @@ image::topology.svg[DHCP option 121 vs option 3 topology] endif::testgroup[] endif::topdoc[] ==== Test sequence -. Setting up client -. Verify 'client' has a route to 10.0.0.0/24 via 192.168.0.254 -. Verify 'client' has a default route via 192.168.0.254 -. Verify 'client' has a route to 20.0.0.0/24 via 192.168.0.2 +. Setting up canary route, 20.0.0.0/24 via 192.168.0.2 +. Enabling DHCP client, allow option 3 and 121 +. Verify 'client' has a route 10.0.0.0/24 via 192.168.0.254 (option 121) +. Verify 'client' has default route via 192.168.0.254 (not use option 3) +. Verify 'client' still has canary route to 20.0.0.0/24 via 192.168.0.2 <<< diff --git a/test/case/infix_dhcp/dhcp_routes/test.py b/test/case/infix_dhcp/dhcp_routes/test.py index e4592ff6..394f9a8e 100755 --- a/test/case/infix_dhcp/dhcp_routes/test.py +++ b/test/case/infix_dhcp/dhcp_routes/test.py @@ -1,14 +1,19 @@ #!/usr/bin/env python3 -""" -DHCP option 121 vs option 3 +"""DHCP option 121 vs option 3 + +Verify that DHCP option 121 (classless static routes) is used over the +older option 3 (default gateway) in the DHCP client, when both are sent +by the server, see RFC3442. Use the routing RIB in the operational +datastore to verify. -Verify DHCP option 121 (static routes) is used over option 3 and that the -routes exist in the operational datastore. +Installing routes from a DHCP server should not affect already existing +(static) routes. To verify this, a static canary route (20.0.0.0/24 via +192.168.0.2) is installed before starting the DHCP client. As a twist, +this canary route has a next-hop (192.168.0.2) which is not reachable +until a DHCP lease has been acquired. -Installing unrelated routes from a DHCP server should not affect already -existing routes. To verify this, a canary route is set up in the client -before initiating DHCP. This canary route does not need to be reachable -before a DHCP lease has been acquired. +The DHCP server is set up to hand out both a default router (option 3) +via 192.168.0.1 and a default route (option 121) via 192.168.0.254. """ import infamy @@ -22,11 +27,10 @@ CANARY = '20.0.0.0/24' CANHOP = '192.168.0.2' - with test.step("Setting up client"): + with test.step("Setting up canary route, 20.0.0.0/24 via 192.168.0.2"): env = infamy.Env() client = env.attach("client", "mgmt") _, host = env.ltop.xlate("host", "data") - _, port = env.ltop.xlate("client", "data") # Install canary route to smoke out any regressions in # how the DHCP client installs routes in the kernel FIB @@ -52,6 +56,9 @@ } }) + with test.step("Enabling DHCP client, allow option 3 and 121"): + _, port = env.ltop.xlate("client", "data") + client.put_config_dict("infix-dhcp-client", { "dhcp-client": { "client-if": [{ @@ -66,17 +73,18 @@ with infamy.IsolatedMacVlan(host) as netns: netns.addip("192.168.0.1") + print(f"Start DHCP server {ROUTER} with option 3 and 121") with infamy.dhcp.Server(netns, prefix=PREFIX, router=ROUTER): - with test.step("Verify 'client' has a route to 10.0.0.0/24 via 192.168.0.254"): + with test.step("Verify 'client' has a route 10.0.0.0/24 via 192.168.0.254 (option 121)"): print("Verify client use classless routes, option 121") until(lambda: route.ipv4_route_exist(client, PREFIX, ROUTER)) - with test.step("Verify 'client' has a default route via 192.168.0.254"): + with test.step("Verify 'client' has default route via 192.168.0.254 (not use option 3)"): print("Verify client did *not* use option 3") if route.ipv4_route_exist(client, "0.0.0.0/0", ROUTER): test.fail() - with test.step("Verify 'client' has a route to 20.0.0.0/24 via 192.168.0.2"): + with test.step("Verify 'client' still has canary route to 20.0.0.0/24 via 192.168.0.2"): until(lambda: route.ipv4_route_exist(client, CANARY, CANHOP, pref=250))