| Message ID | 20251027124259.3395209-7-dchumak@nvidia.com |
|---|---|
| State | Changes Requested |
| Delegated to: | Ilya Maximets |
| Headers | show |
| Series | ovs-router: Multi-table routing infrastructure. | expand |
| Context | Check | Description |
|---|---|---|
| ovsrobot/apply-robot | success | apply and check: success |
| ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
| ovsrobot/github-robot-_Build_and_Test | success | github build: passed |
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 <dchumak@nvidia.com> > --- > 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
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 + 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
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 <dchumak@nvidia.com> --- 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(+)