@@ -218,7 +218,7 @@ To delete route::
To look up and display the route for a destination::
- $ ovs-appctl ovs/route/lookup <IP address>
+ $ ovs-appctl ovs/route/lookup <IP address> [src=IP]
ARP
~~~
@@ -23,6 +23,8 @@ Post-v3.6.0
* Added a new sub-command, ovs/route/rule/show, to list OVS router rules.
* 'ovs/route/add' and 'ovs/route/del': added new option, table=ID, to
add/delete a route from a specific OVS table.
+ * 'ovs/route/lookup': added new option, src=IP, to perform lookup with
+ a specific source IP address.
v3.6.0 - 18 Aug 2025
@@ -934,30 +934,57 @@ static void
ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc,
const char *argv[], void *aux OVS_UNUSED)
{
- struct in6_addr gw, src = in6addr_any;
+ struct in6_addr gw, src6 = in6addr_any;
+ char src6_s[IPV6_SCAN_LEN + 1];
char iface[IFNAMSIZ];
struct in6_addr ip6;
unsigned int plen;
uint32_t mark = 0;
+ ovs_be32 src = 0;
+ bool is_ipv6;
ovs_be32 ip;
+ int i;
if (scan_ipv4_route(argv[1], &ip, &plen) && plen == 32) {
in6_addr_set_mapped_ipv4(&ip6, ip);
- } else if (!(scan_ipv6_route(argv[1], &ip6, &plen) && plen == 128)) {
- unixctl_command_reply_error(conn, "Invalid parameters");
+ is_ipv6 = false;
+ } else if (scan_ipv6_route(argv[1], &ip6, &plen) && plen == 128) {
+ is_ipv6 = true;
+ } else {
+ unixctl_command_reply_error(conn, "Invalid 'ip/plen' parameter");
return;
}
- if (argc > 2) {
- if (!ovs_scan(argv[2], "pkt_mark=%"SCNi32, &mark)) {
- unixctl_command_reply_error(conn, "Invalid pkt_mark");
- return;
+
+ /* Parse optional parameters. */
+ for (i = 2; i < argc; i++) {
+ if (ovs_scan(argv[i], "pkt_mark=%"SCNu32, &mark)) {
+ continue;
+ }
+
+ if (is_ipv6) {
+ if (ovs_scan(argv[i], "src="IPV6_SCAN_FMT, src6_s) &&
+ ipv6_parse(src6_s, &src6)) {
+ continue;
+ }
+ } else {
+ if (ovs_scan(argv[i], "src="IP_SCAN_FMT, IP_SCAN_ARGS(&src))) {
+ continue;
+ }
}
+
+ unixctl_command_reply_error(conn, "Invalid pkt_mark or src");
+ return;
+ }
+
+ if (src) {
+ in6_addr_set_mapped_ipv4(&src6, src);
}
- if (ovs_router_lookup(mark, &ip6, iface, &src, &gw)) {
+
+ if (ovs_router_lookup(mark, &ip6, iface, &src6, &gw)) {
struct ds ds = DS_EMPTY_INITIALIZER;
ds_put_format(&ds, "src ");
- ipv6_format_mapped(&src, &ds);
+ ipv6_format_mapped(&src6, &ds);
ds_put_format(&ds, "\ngateway ");
ipv6_format_mapped(&gw, &ds);
ds_put_format(&ds, "\ndev %s\n", iface);
@@ -1118,7 +1145,7 @@ ovs_router_init(void)
"[pkt_mark=mark] [table=id]", 1, 3,
ovs_router_del, NULL);
unixctl_command_register("ovs/route/lookup", "ip_addr "
- "[pkt_mark=mark]", 1, 2,
+ "[pkt_mark=mark] [src=src_ip]", 1, 3,
ovs_router_lookup_cmd, NULL);
unixctl_command_register("ovs/route/rule/show", "", 0, 0,
ovs_router_rules_show, NULL);
@@ -23,6 +23,12 @@ Delete ip/plen route from OVS routing table. The standard routing table is used
by default, or a specific custom table when ID is provided via \fItable\fR
parameter.
.
+.IP "\fBovs/route/lookup\fR \fIip_addr\fR [\fBpkt_mark\fR=\fImark\fR] \
+[\fBsrc\fR=\fIsrc_ip\fR]"
+Perform route lookup for specified destination IP address in OVS routing tables
+and print the matching route information. The lookup may be more selective when
+additional parameters are used: \fIpkt_mark\fR and \fIsrc\fR.
+.
.IP "\fBovs/route/rule/show\fR"
Print routing rules in OVS. This includes routing rules cached from the system
routing policy database and user configured routing rules.
@@ -457,3 +457,57 @@ ovs-appctl: ovs-vswitchd: server returned an error
OVS_TRAFFIC_VSWITCHD_STOP
AT_CLEANUP
+
+dnl Checks that OVS performs route lookup according to rules with src match.
+AT_SETUP([ovs-route - route lookup + rules])
+AT_KEYWORDS([route])
+OVS_TRAFFIC_VSWITCHD_START()
+
+dnl Create tap ports.
+on_exit 'ip link del p1-route'
+on_exit 'ip link del p2-route'
+AT_CHECK([ip tuntap add name p1-route mode tap])
+AT_CHECK([ip tuntap add name p2-route mode tap])
+AT_CHECK([ip link set p1-route up])
+AT_CHECK([ip link set p2-route up])
+
+dnl Add ip addresses, they need to be from same subnet so that the main router
+dnl table in OVS contains only one of the routes.
+AT_CHECK([ip addr add 10.0.0.11/24 dev p1-route], [0], [stdout])
+AT_CHECK([ip addr add 10.0.0.12/24 dev p2-route], [0], [stdout])
+dnl Give the main thread a chance to act.
+AT_CHECK([ovs-appctl revalidator/wait])
+dnl Check that OVS learn only one of the routes to the subnet.
+AT_CHECK([ovs-appctl ovs/route/show | grep -F '10.0.0.0/24' | grep -q 'p1-route'], [1])
+AT_CHECK([ovs-appctl ovs/route/show | grep -F '10.0.0.0/24' | grep -q 'p2-route'])
+dnl Check that OVS lookup returns p2-route even for srouce IP of p1-route
+dnl internface.
+AT_CHECK([ovs-appctl ovs/route/lookup 10.0.0.10 src=10.0.0.11], [0], [src 10.0.0.11
+gateway ::
+dev p2-route
+])
+
+dnl Add rule to use a custom routing table for source IP of p1-route.
+on_exit 'ip route flush table 42'
+AT_CHECK([ip route add 10.0.0.0/24 dev p1-route table 42])
+AT_CHECK([ip route show table 42 | grep 'p1-route' | grep -Fq '10.0.0.0/24'])
+on_exit 'ip rule del from 10.0.0.11 lookup 42'
+AT_CHECK([ip rule add from 10.0.0.11 lookup 42])
+AT_CHECK([ip rule show | grep -q 'from 10.0.0.11 lookup 42'])
+dnl Give the main thread a chance to act.
+AT_CHECK([ovs-appctl revalidator/wait])
+dnl Check that OVS uses custom table for lookup with source IP of p1-route
+dnl internface and returns the correct p1-route.
+AT_CHECK([ovs-appctl ovs/route/lookup 10.0.0.10 src=10.0.0.11], [0], [src 10.0.0.11
+gateway ::
+dev p1-route
+])
+dnl Check that OVS uses main table for lookup with other source IP that doesn't
+dnl match the rule.
+AT_CHECK([ovs-appctl ovs/route/lookup 10.0.0.10 src=10.0.0.12], [0], [src 10.0.0.12
+gateway ::
+dev p2-route
+])
+
+OVS_TRAFFIC_VSWITCHD_STOP
+AT_CLEANUP
Introduce an optional parameter to `ovs-appctl ovs/route/lookup` for matching on source IP address. Signed-off-by: Dima Chumak <dchumak@nvidia.com> --- Documentation/howto/userspace-tunneling.rst | 2 +- NEWS | 2 + lib/ovs-router.c | 47 ++++++++++++++---- ofproto/ofproto-tnl-unixctl.man | 6 +++ tests/system-route.at | 54 +++++++++++++++++++++ 5 files changed, 100 insertions(+), 11 deletions(-)