mirror of
https://github.com/linux-system-roles/network.git
synced 2026-01-23 02:15:17 +00:00
feat: Add the support for the optional route source parameter in nm provider
Enhancement: Add the optional route source parameter for the nm provider Reason: In a scenario where you have a machine with multiple public IP addresses, typically due to a multi-WAN setup, the src parameter in the context of routes allows you to specify which source IP address should be used when sending packets via a specific route. This is crucial when you want to ensure that outbound traffic uses a specific IP address tied to a particular network interface, especially when dealing with multiple WAN connections. Result: Adding support for the src parameter in routes results in a more powerful and flexible network configuration capability, especially important in environments with multiple network interfaces or multiple IP addresses, it provides better control over traffic routing. Resolves: https://issues.redhat.com/browse/RHEL-3252 Signed-off-by: Wen Liang <liangwen12year@gmail.com>
This commit is contained in:
parent
098e5e1efb
commit
8195188d29
5 changed files with 84 additions and 4 deletions
|
|
@ -596,10 +596,11 @@ The IP configuration supports the following options:
|
|||
|
||||
Static route configuration can be specified via a list of routes given in the
|
||||
`route` option. The default value is an empty list. Each route is a dictionary with
|
||||
the following entries: `gateway`, `metric`, `network`, `prefix`, `table` and `type`.
|
||||
`network` and `prefix` specify the destination network. `table` supports both the
|
||||
numeric table and named table. In order to specify the named table, the users have to
|
||||
ensure the named table is properly defined in `/etc/iproute2/rt_tables` or
|
||||
the following entries: `gateway`, `metric`, `network`, `prefix`, `src`, `table` and
|
||||
`type`. `network` and `prefix` specify the destination network. `src` specifies the
|
||||
source IP address for a route. `table` supports both the numeric table and named
|
||||
table. In order to specify the named table, the users have to ensure the named table
|
||||
is properly defined in `/etc/iproute2/rt_tables` or
|
||||
`/etc/iproute2/rt_tables.d/*.conf`. The optional `type` key supports the values
|
||||
`blackhole`, `prohibit`, and `unreachable`.
|
||||
See [man 8 ip-route](https://man7.org/linux/man-pages/man8/ip-route.8.html#DESCRIPTION)
|
||||
|
|
|
|||
|
|
@ -1263,6 +1263,10 @@ class NMUtil:
|
|||
NM.IPRoute.set_attribute(
|
||||
new_route, "table", Util.GLib().Variant.new_uint32(r["table"])
|
||||
)
|
||||
if r["src"]:
|
||||
NM.IPRoute.set_attribute(
|
||||
new_route, "src", Util.GLib().Variant.new_string(r["src"])
|
||||
)
|
||||
|
||||
if r["family"] == socket.AF_INET:
|
||||
s_ip4.add_route(new_route)
|
||||
|
|
|
|||
|
|
@ -680,6 +680,9 @@ class ArgValidatorIPRoute(ArgValidatorDict):
|
|||
enum_values=["blackhole", "prohibit", "unreachable"],
|
||||
),
|
||||
ArgValidatorRouteTable("table"),
|
||||
ArgValidatorIP(
|
||||
"src", family=family, default_value=None, plain_address=False
|
||||
),
|
||||
],
|
||||
default_value=None,
|
||||
)
|
||||
|
|
@ -716,6 +719,16 @@ class ArgValidatorIPRoute(ArgValidatorDict):
|
|||
elif not Util.addr_family_valid_prefix(family, prefix):
|
||||
raise ValidationError(name, "invalid prefix %s in '%s'" % (prefix, value))
|
||||
|
||||
src = result["src"]
|
||||
if src is not None:
|
||||
if family != src["family"]:
|
||||
raise ValidationError(
|
||||
name,
|
||||
"conflicting address family between network and src "
|
||||
"address {0}".format(src["address"]),
|
||||
)
|
||||
result["src"] = src["address"]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
|
@ -2627,6 +2640,12 @@ class ArgValidator_ListConnections(ArgValidatorList):
|
|||
idx,
|
||||
"type is not supported by initscripts",
|
||||
)
|
||||
if route["src"] is not None:
|
||||
raise ValidationError.from_connection(
|
||||
idx,
|
||||
"configuring the route source is not supported by initscripts",
|
||||
)
|
||||
|
||||
if connection["ip"]["routing_rule"]:
|
||||
if mode == self.VALIDATE_ONE_MODE_INITSCRIPTS:
|
||||
raise ValidationError.from_connection(
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@
|
|||
gateway: 198.51.100.6
|
||||
metric: 4
|
||||
table: 30200
|
||||
- network: 192.0.2.64
|
||||
prefix: 26
|
||||
gateway: 198.51.100.8
|
||||
metric: 50
|
||||
table: 30200
|
||||
src: 198.51.100.3
|
||||
|
||||
- name: Get the routes from the route table 30200
|
||||
command: ip route show table 30200
|
||||
|
|
@ -65,6 +71,9 @@
|
|||
that:
|
||||
- route_table_30200.stdout is search("198.51.100.64/26 via
|
||||
198.51.100.6 dev ethtest0 proto static metric 4")
|
||||
- route_table_30200.stdout is search("192.0.2.64/26 via
|
||||
198.51.100.8 dev ethtest0 proto static src 198.51.100.3
|
||||
metric 50")
|
||||
msg: "the route table 30200 does not exist or does not contain the
|
||||
specified route"
|
||||
|
||||
|
|
@ -111,6 +120,12 @@
|
|||
gateway: 198.51.100.6
|
||||
metric: 4
|
||||
table: custom
|
||||
- network: 192.0.2.64
|
||||
prefix: 26
|
||||
gateway: 198.51.100.8
|
||||
metric: 50
|
||||
table: custom
|
||||
src: 198.51.100.3
|
||||
|
||||
- name: Get the routes from the named route table 'custom'
|
||||
command: ip route show table custom
|
||||
|
|
@ -126,6 +141,9 @@
|
|||
198.51.100.1 dev ethtest0 proto static metric 2")
|
||||
- route_table_custom.stdout is search("198.51.100.64/26 via
|
||||
198.51.100.6 dev ethtest0 proto static metric 4")
|
||||
- route_table_custom.stdout is search("192.0.2.64/26 via
|
||||
198.51.100.8 dev ethtest0 proto static src 198.51.100.3
|
||||
metric 50")
|
||||
msg: "the named route table 'custom' does not exist or does not contain
|
||||
the specified route"
|
||||
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": int(r.get_metric()),
|
||||
"type": r.get_attribute("type"),
|
||||
"table": r.get_attribute("table"),
|
||||
"src": r.get_attribute("src"),
|
||||
}
|
||||
for r in route_list_new
|
||||
]
|
||||
|
|
@ -295,6 +296,12 @@ class TestValidator(Python26CompatTestCase):
|
|||
"table",
|
||||
Util.GLib().Variant.new_uint32(r["table"]),
|
||||
)
|
||||
if r["src"]:
|
||||
NM.IPRoute.set_attribute(
|
||||
new_route,
|
||||
"src",
|
||||
Util.GLib().Variant.new_uint32(r["src"]),
|
||||
)
|
||||
if r["family"] == socket.AF_INET:
|
||||
s4.add_route(new_route)
|
||||
else:
|
||||
|
|
@ -1144,6 +1151,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
}
|
||||
],
|
||||
"routing_rule": [],
|
||||
|
|
@ -1485,6 +1493,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
}
|
||||
],
|
||||
"routing_rule": [],
|
||||
|
|
@ -1635,6 +1644,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
}
|
||||
],
|
||||
"routing_rule": [],
|
||||
|
|
@ -1698,6 +1708,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
}
|
||||
],
|
||||
"routing_rule": [],
|
||||
|
|
@ -2661,6 +2672,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": 545,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
},
|
||||
{
|
||||
"family": socket.AF_INET,
|
||||
|
|
@ -2670,6 +2682,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
},
|
||||
],
|
||||
"routing_rule": [],
|
||||
|
|
@ -2767,6 +2780,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": 545,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
},
|
||||
{
|
||||
"family": socket.AF_INET,
|
||||
|
|
@ -2776,6 +2790,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
},
|
||||
{
|
||||
"family": socket.AF_INET6,
|
||||
|
|
@ -2785,6 +2800,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
},
|
||||
],
|
||||
"routing_rule": [],
|
||||
|
|
@ -2923,6 +2939,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": 545,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
},
|
||||
{
|
||||
"family": socket.AF_INET,
|
||||
|
|
@ -2932,6 +2949,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
},
|
||||
{
|
||||
"family": socket.AF_INET6,
|
||||
|
|
@ -2941,6 +2959,7 @@ class TestValidator(Python26CompatTestCase):
|
|||
"metric": -1,
|
||||
"type": None,
|
||||
"table": None,
|
||||
"src": None,
|
||||
},
|
||||
],
|
||||
"routing_rule": [],
|
||||
|
|
@ -5001,6 +5020,25 @@ class TestValidatorRouteTable(Python26CompatTestCase):
|
|||
self.test_connections,
|
||||
)
|
||||
|
||||
def test_route_with_source_address(self):
|
||||
"""
|
||||
Test setting the route with src address specified
|
||||
"""
|
||||
self.test_connections[0]["ip"]["route"][0]["src"] = "2001:db8::2"
|
||||
self.assertRaisesRegex(
|
||||
ValidationError,
|
||||
"conflicting address family between network and src "
|
||||
"address {0}".format(
|
||||
self.test_connections[0]["ip"]["route"][0]["src"],
|
||||
),
|
||||
self.validator.validate,
|
||||
self.test_connections,
|
||||
)
|
||||
|
||||
self.test_connections[0]["ip"]["route"][0]["src"] = "198.51.100.3"
|
||||
result = self.validator.validate(self.test_connections)
|
||||
self.assertEqual(result[0]["ip"]["route"][0]["src"], "198.51.100.3")
|
||||
|
||||
|
||||
class TestValidatorRoutingRules(Python26CompatTestCase):
|
||||
def setUp(self):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue