On 7/23/25 3:12 PM, Dima Chumak via dev wrote: > 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 | 5 ++ > tests/system-route.at | 54 +++++++++++++++++++++ > 5 files changed, 99 insertions(+), 11 deletions(-) > > diff --git a/Documentation/howto/userspace-tunneling.rst > b/Documentation/howto/userspace-tunneling.rst > index 1c7e551e0726..5bebbce69e4a 100644 > --- a/Documentation/howto/userspace-tunneling.rst > +++ b/Documentation/howto/userspace-tunneling.rst > @@ -217,7 +217,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 c8f4592a6e2f..a58baa0a8365 100644 > --- a/NEWS > +++ b/NEWS > @@ -29,6 +29,8 @@ v3.6.0 - xx xxx xxxx > * Added a new sub-command, ovs/router/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. > - ovs-vsctl: > * Now exits with error code 160 (ERROR_BAD_ARGUMENTS) on Windows and > 65 (EX_DATAERR) on other platforms if it fails while waiting for > diff --git a/lib/ovs-router.c b/lib/ovs-router.c > index ba4c43ab1d2e..a3df5c6fc2cc 100644 > --- a/lib/ovs-router.c > +++ b/lib/ovs-router.c > @@ -978,30 +978,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=%"SCNi32, &mark)) {
SNCu32 > + 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); > @@ -1150,7 +1177,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 654f405109e6..8e48c0e809ac 100644 > --- a/ofproto/ofproto-tnl-unixctl.man > +++ b/ofproto/ofproto-tnl-unixctl.man > @@ -21,6 +21,11 @@ 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 \fIip_addr\fB [pkt_mark=\fImark\fB] > [src=\fIIP\fB]\fR" Should likely be src=src_ip instead of src=IP, otherwise it's hard to tell the arguments apart in the description. Names are also inconsistent througout the patch. > +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 09b2861443cb..7efb50cfbc23 100644 > --- a/tests/system-route.at > +++ b/tests/system-route.at > @@ -412,3 +412,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([test `ovs-appctl ovs/route/show | grep -F '10.0.0.0/24' | grep -c > 'p1-route'` -eq 0]) Use 'grep -q' instead of the test with the [1] as an expected exit code. > +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 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev