Introduce an optional parameter to `ovs-appctl ovs/route/lookup` for matching on source IP address.
Signed-off-by: Dima Chumak <dchu...@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(-) diff --git a/Documentation/howto/userspace-tunneling.rst b/Documentation/howto/userspace-tunneling.rst index 8116e81e5a7d..e20a353c3a6c 100644 --- a/Documentation/howto/userspace-tunneling.rst +++ b/Documentation/howto/userspace-tunneling.rst @@ -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 ~~~ diff --git a/NEWS b/NEWS index 9b9f5e7360d9..3c4b4e67dda9 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,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 -------------------- diff --git a/lib/ovs-router.c b/lib/ovs-router.c index 51d69b5e8ffb..d98b354c20b7 100644 --- a/lib/ovs-router.c +++ b/lib/ovs-router.c @@ -933,30 +933,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); @@ -1102,7 +1129,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); diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man index c69ad4dfd8b5..aaf5552170ec 100644 --- a/ofproto/ofproto-tnl-unixctl.man +++ b/ofproto/ofproto-tnl-unixctl.man @@ -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. diff --git a/tests/system-route.at b/tests/system-route.at index 4f41647c9c5f..8bc075b661bc 100644 --- a/tests/system-route.at +++ b/tests/system-route.at @@ -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 -- 2.50.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev