On 10/27/25 1:42 PM, Dima Chumak via dev wrote:
> Add a new command `ovs-appctl ovs/route/rule/show` for printing OVS
> internal routing rules database:
>
> ovs-appctl ovs/route/rule/show
> 32763: from 7.7.7.17 lookup 20
> 32764: from all lookup 15
> 32765: from 7.7.7.7 lookup 10
>
> The rules are sorted from the highest priority being the first to the
> lowest being the last one.
>
> Signed-off-by: Dima Chumak <[email protected]>
> ---
> Documentation/howto/userspace-tunneling.rst | 4 +
> NEWS | 1 +
> lib/ovs-router.c | 95 +++++++++++++++++++++
> ofproto/ofproto-tnl-unixctl.man | 4 +
> tests/ovs-router.at | 16 ++++
> 5 files changed, 120 insertions(+)
>
> diff --git a/Documentation/howto/userspace-tunneling.rst
> b/Documentation/howto/userspace-tunneling.rst
> index 1dd34cd2f5e4..c7c6464520a6 100644
> --- a/Documentation/howto/userspace-tunneling.rst
> +++ b/Documentation/howto/userspace-tunneling.rst
> @@ -207,6 +207,10 @@ To see all routes configured::
>
> $ ovs-appctl ovs/route/show [table=ID|all]
>
> +To see all router rules configured::
> +
> + $ ovs-appctl ovs/route/rule/show
As per comments for the patch 02/11, may need to add [-6] argument.
> +
> To delete route::
>
> $ ovs-appctl ovs/route/del <IP address>/<prefix length>
> diff --git a/NEWS b/NEWS
> index c86b3921ae05..8ce1a08da6b7 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -20,6 +20,7 @@ Post-v3.6.0
> - ovs-appctl:
> * 'ovs/route/show': added new option, table=[ID|all], to list routes
> from
> a specific OVS table or all routes from all tables.
> + * Added a new sub-command, ovs/route/rule/show, to list OVS router
> rules.
>
>
> v3.6.0 - 18 Aug 2025
> diff --git a/lib/ovs-router.c b/lib/ovs-router.c
> index 6ace71497d1e..d67a098ba48f 100644
> --- a/lib/ovs-router.c
> +++ b/lib/ovs-router.c
> @@ -801,6 +801,99 @@ ovs_router_show(struct unixctl_conn *conn, int argc
> OVS_UNUSED,
> }
> }
>
> +static void
> +ovs_router_rules_show_json(struct json *rule_entries)
> +{
> + struct router_rule *rule;
> + struct ds ds;
> +
> + PVECTOR_FOR_EACH (rule, &rules) {
> + struct json *entry = json_object_create();
> +
> + json_object_put(entry, "priority", json_integer_create(rule->prio));
> + json_object_put(entry, "invert", json_boolean_create(rule->invert));
> + json_object_put(entry, "ipv4", json_boolean_create(rule->ipv4));
> + json_object_put(entry, "src-prefix",
> + json_integer_create(rule->src_prefix));
> + json_object_put(entry, "lookup",
> + json_integer_create(rule->lookup_table));
> +
> + if (rule->src_prefix) {
> + ds_init(&ds);
> + ipv6_format_mapped(&rule->from_addr, &ds);
> + json_object_put_string(entry, "from", ds_cstr_ro(&ds));
> + ds_destroy(&ds);
> + } else {
> + json_object_put_string(entry, "from", "all");
> + }
> +
> + json_array_add(rule_entries, entry);
> + }
> +}
> +
> +static char *
> +standard_table_name(uint32_t table)
> +{
> + switch (table) {
> + case CLS_DEFAULT:
> + return "default";
> + case CLS_MAIN:
> + return "main";
> + case CLS_LOCAL:
> + return "local";
> + }
> +
> + return NULL;
> +}
> +
> +static void
> +ovs_router_rules_show_text(struct ds *ds)
> +{
> + struct router_rule *rule;
> +
> + PVECTOR_FOR_EACH (rule, &rules) {
> + ds_put_format(ds, "%"PRIu32": ", rule->prio);
> + if (rule->invert) {
> + ds_put_format(ds, "not ");
> + }
> + ds_put_format(ds, "from ");
> + if (rule->src_prefix) {
> + ipv6_format_mapped(&rule->from_addr, ds);
> + if (!((IN6_IS_ADDR_V4MAPPED(&rule->from_addr) &&
> + rule->src_prefix == 32) || rule->src_prefix == 128)) {
> + ds_put_format(ds, "/%"PRIu8" ", rule->src_prefix);
> + }
> + } else {
> + ds_put_cstr(ds, "all");
> + }
> + ds_put_format(ds, " ");
> + if (is_standard_table(rule->lookup_table)) {
> + ds_put_format(ds, "lookup %s\n",
> + standard_table_name(rule->lookup_table));
> + } else {
> + ds_put_format(ds, "lookup %"PRIu32"\n", rule->lookup_table);
> + }
> + }
> +}
> +
> +static void
> +ovs_router_rules_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> + const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
> +{
> + if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) {
> + struct json *entries = json_array_create_empty();
> +
> + ovs_router_rules_show_json(entries);
> + unixctl_command_reply_json(conn, entries);
> + } else {
> + struct ds ds = DS_EMPTY_INITIALIZER;
> +
> + ovs_router_rules_show_text(&ds);
> + unixctl_command_reply(conn, ds_cstr(&ds));
> + ds_destroy(&ds);
> + }
> +}
> +
> static void
> ovs_router_lookup_cmd(struct unixctl_conn *conn, int argc,
> const char *argv[], void *aux OVS_UNUSED)
> @@ -991,6 +1084,8 @@ ovs_router_init(void)
> unixctl_command_register("ovs/route/lookup", "ip_addr "
> "[pkt_mark=mark]", 1, 2,
> ovs_router_lookup_cmd, NULL);
> + unixctl_command_register("ovs/route/rule/show", "", 0, 0,
> + ovs_router_rules_show, NULL);
> ovsthread_once_done(&once);
> }
> }
> diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man
> index 409507257e6b..b62063dcdae0 100644
> --- a/ofproto/ofproto-tnl-unixctl.man
> +++ b/ofproto/ofproto-tnl-unixctl.man
> @@ -17,6 +17,10 @@ contents of a specific table ID or of all routing tables
> is printed.
> .IP "\fBovs/route/del\fR \fIip\fR/\fIplen\fR [\fBpkt_mark\fR=\fImark\fR]"
> Delete ip/plen route from OVS routing table.
> .
> +.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.
> +.
> .IP "\fBtnl/neigh/show\fR"
> .IP "\fBtnl/arp/show\fR"
> OVS builds ARP cache by snooping are messages. This command shows
> diff --git a/tests/ovs-router.at b/tests/ovs-router.at
> index 5837ff24bb34..b8df18eba65b 100644
> --- a/tests/ovs-router.at
> +++ b/tests/ovs-router.at
> @@ -240,3 +240,19 @@ User: 2001:db8:babe::/64 dev br0 GW 2001:db8:cafe::2 SRC
> 2001:db8:cafe::1
>
> OVS_VSWITCHD_STOP
> AT_CLEANUP
> +
> +AT_SETUP([appctl - route/rule/show])
> +AT_KEYWORDS([ovs_router])
> +OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=dummy])
> +AT_CHECK([ovs-appctl netdev-dummy/ip4addr br0 192.0.2.1/24], [0], [OK
> +])
> +
> +dnl Check standard rules exist.
> +AT_CHECK([ovs-appctl ovs/route/rule/show], [0], [dnl
> +0: from all lookup local
> +32766: from all lookup main
> +32767: from all lookup default
> +])
> +
> +OVS_VSWITCHD_STOP
> +AT_CLEANUP
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev