Introduce an optional parameter to `ovs-appctl ovs/route/show` for printing non-default routing tables:
ovs-appctl ovs/route/show [table=all|id] Default usage is unchanged: ovs-appctl ovs/route/show Route Table: Cached: ::1/128 dev lo SRC ::1 Cached: 127.0.0.0/8 dev lo SRC 127.0.0.1 local Cached: 10.7.7.0/24 dev br-phy1 SRC 10.7.7.17 Cached: 0.0.0.0/0 dev eth1 GW 10.0.0.1 SRC 10.0.0.2 New usage with a specific table displays only the routes from that table: ovs-appctl ovs/route/show table=10 Route Table #10: Cached: 10.7.7.0/24 dev br-phy0 SRC 10.7.7.7 Special table 'all' displays all of the routes, the ones which are coming from a non-default table have additional field 'table' displayed: ovs-appctl ovs/route/show table=all Cached: 10.7.7.0/24 dev br-phy1 SRC 10.7.7.17 table 20 Cached: 10.7.7.0/24 dev br-phy0 SRC 10.7.7.7 table 10 Cached: ::1/128 dev lo SRC ::1 Cached: 127.0.0.0/8 dev lo SRC 127.0.0.1 local Cached: 10.7.7.0/24 dev br-phy1 SRC 10.7.7.17 Cached: 0.0.0.0/0 dev eth1 GW 10.0.0.1 SRC 10.0.0.2 Signed-off-by: Dima Chumak <dchu...@nvidia.com> --- Documentation/howto/userspace-tunneling.rst | 2 +- NEWS | 4 +- lib/ovs-router.c | 177 ++++++++++++-------- ofproto/ofproto-tnl-unixctl.man | 9 +- tests/ovs-router.at | 15 ++ 5 files changed, 136 insertions(+), 71 deletions(-) diff --git a/Documentation/howto/userspace-tunneling.rst b/Documentation/howto/userspace-tunneling.rst index 31d82fd5e57a..1dd34cd2f5e4 100644 --- a/Documentation/howto/userspace-tunneling.rst +++ b/Documentation/howto/userspace-tunneling.rst @@ -205,7 +205,7 @@ To add route:: To see all routes configured:: - $ ovs-appctl ovs/route/show + $ ovs-appctl ovs/route/show [table=ID|all] To delete route:: diff --git a/NEWS b/NEWS index 1dbe0ef31093..d0db019df4c5 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ 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. v3.6.0 - 18 Aug 2025 -------------------- diff --git a/lib/ovs-router.c b/lib/ovs-router.c index b6003a40a624..91f331847c99 100644 --- a/lib/ovs-router.c +++ b/lib/ovs-router.c @@ -626,37 +626,21 @@ ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED, } static void -ovs_router_show_json(struct json **routes) +ovs_router_show_json(struct json *json_routes, const struct classifier *cls, + uint32_t table) { - struct json **json_entries = NULL; + struct ds ds = DS_EMPTY_INITIALIZER; struct ovs_router_entry *rt; - struct classifier *cls_main; - struct ds ds; - int n_rules; - int i = 0; - cls_main = cls_find(CLS_MAIN); - if (!cls_main) { - goto out; - } - - n_rules = classifier_count(cls_main); - if (!n_rules) { - goto out; + if (!cls) { + return; } - json_entries = xmalloc(n_rules * sizeof *json_entries); - ds_init(&ds); - - CLS_FOR_EACH (rt, cr, cls_main) { + CLS_FOR_EACH (rt, cr, cls) { bool user = rt->priority != rt->plen && !rt->local; uint8_t plen = rt->plen; struct json *json, *nh; - if (i >= n_rules) { - break; - } - json = json_object_create(); nh = json_object_create(); @@ -664,6 +648,7 @@ ovs_router_show_json(struct json **routes) plen -= 96; } + json_object_put(json, "table", json_integer_create(table)); json_object_put(json, "user", json_boolean_create(user)); json_object_put(json, "local", json_boolean_create(rt->local)); json_object_put(json, "priority", json_integer_create(rt->priority)); @@ -689,59 +674,69 @@ ovs_router_show_json(struct json **routes) } json_object_put(json, "nexthops", json_array_create_1(nh)); - json_entries[i++] = json; + json_array_add(json_routes, json); } ds_destroy(&ds); +} -out: - *routes = json_array_create(json_entries, i); +static bool +is_standard_table(uint32_t table_id) +{ + return table_id == CLS_DEFAULT + || table_id == CLS_MAIN + || table_id == CLS_LOCAL; } static void -ovs_router_show_text(struct ds *ds) +ovs_router_show_text(struct ds *ds, const struct classifier *cls, + uint32_t table, bool show_header) { - struct classifier *std_cls[3]; struct ovs_router_entry *rt; - std_cls[0] = cls_find(CLS_LOCAL); - std_cls[1] = cls_find(CLS_MAIN); - std_cls[2] = cls_find(CLS_DEFAULT); + if (show_header) { + if (is_standard_table(table)) { + ds_put_format(ds, "Route Table:\n"); + } else { + ds_put_format(ds, "Route Table #%"PRIu32":\n", table); + } + } - ds_put_format(ds, "Route Table:\n"); - for (int i = 0; i < ARRAY_SIZE(std_cls); i++) { - if (!std_cls[i]) { - continue; + if (!cls) { + return; + } + + CLS_FOR_EACH (rt, cr, cls) { + uint8_t plen; + if (rt->priority == rt->plen || rt->local) { + ds_put_format(ds, "Cached: "); + } else { + ds_put_format(ds, "User: "); + } + ipv6_format_mapped(&rt->nw_addr, ds); + plen = rt->plen; + if (IN6_IS_ADDR_V4MAPPED(&rt->nw_addr)) { + plen -= 96; + } + ds_put_format(ds, "/%"PRIu8, plen); + if (rt->mark) { + ds_put_format(ds, " MARK %"PRIu32, rt->mark); } - CLS_FOR_EACH (rt, cr, std_cls[i]) { - uint8_t plen; - if (rt->priority == rt->plen || rt->local) { - ds_put_format(ds, "Cached: "); - } else { - ds_put_format(ds, "User: "); - } - ipv6_format_mapped(&rt->nw_addr, ds); - plen = rt->plen; - if (IN6_IS_ADDR_V4MAPPED(&rt->nw_addr)) { - plen -= 96; - } - ds_put_format(ds, "/%"PRIu8, plen); - if (rt->mark) { - ds_put_format(ds, " MARK %"PRIu32, rt->mark); - } - ds_put_format(ds, " dev %s", rt->output_netdev); - if (ipv6_addr_is_set(&rt->gw)) { - ds_put_format(ds, " GW "); - ipv6_format_mapped(&rt->gw, ds); - } - ds_put_format(ds, " SRC "); - ipv6_format_mapped(&rt->src_addr, ds); - if (rt->local) { - ds_put_format(ds, " local"); - } - ds_put_format(ds, "\n"); + ds_put_format(ds, " dev %s", rt->output_netdev); + if (ipv6_addr_is_set(&rt->gw)) { + ds_put_format(ds, " GW "); + ipv6_format_mapped(&rt->gw, ds); } + ds_put_format(ds, " SRC "); + ipv6_format_mapped(&rt->src_addr, ds); + if (rt->local) { + ds_put_format(ds, " local"); + } + if (!is_standard_table(table) && !show_header) { + ds_put_format(ds, " table %"PRIu32, table); + } + ds_put_format(ds, "\n"); } } @@ -749,15 +744,65 @@ static void ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED) { + struct ds ds = DS_EMPTY_INITIALIZER; + struct classifier *cls = NULL; + uint32_t table = CLS_MAIN; + + if (argc > 1) { + if (!strcmp(argv[1], "table=all")) { + table = CLS_ALL; + } else if (!ovs_scan(argv[1], "table=%"SCNu32, &table)) { + unixctl_command_reply_error(conn, "Invalid table format"); + return; + } + } + + if (table != CLS_ALL) { + cls = cls_find(table); + if (!cls) { + ds_put_format(&ds, "Table '%s' not found", argv[1]); + unixctl_command_reply_error(conn, ds_cstr_ro(&ds)); + ds_destroy(&ds); + return; + } + } + if (unixctl_command_get_output_format(conn) == UNIXCTL_OUTPUT_FMT_JSON) { - struct json *routes; + struct json *routes = NULL; + + routes = json_array_create_empty(); + + if (table == CLS_ALL) { + struct clsmap_node *node; + + CMAP_FOR_EACH (node, cmap_node, &clsmap) { + ovs_router_show_json(routes, &node->cls, node->table); + } + ovs_router_show_json(routes, cls_find(CLS_MAIN), CLS_MAIN); + } else if (is_standard_table(table)) { + ovs_router_show_json(routes, cls_find(CLS_LOCAL), CLS_LOCAL); + ovs_router_show_json(routes, cls_find(CLS_MAIN), CLS_MAIN); + ovs_router_show_json(routes, cls_find(CLS_DEFAULT), CLS_DEFAULT); + } else { + ovs_router_show_json(routes, cls, table); + } - ovs_router_show_json(&routes); unixctl_command_reply_json(conn, routes); } else { - struct ds ds = DS_EMPTY_INITIALIZER; + if (table == CLS_ALL) { + struct clsmap_node *node; - ovs_router_show_text(&ds); + CMAP_FOR_EACH (node, cmap_node, &clsmap) { + ovs_router_show_text(&ds, &node->cls, node->table, false); + } + } else if (is_standard_table(table)) { + ovs_router_show_text(&ds, cls_find(CLS_LOCAL), CLS_LOCAL, true); + ovs_router_show_text(&ds, cls_find(CLS_MAIN), CLS_MAIN, false); + ovs_router_show_text(&ds, cls_find(CLS_DEFAULT), CLS_DEFAULT, + false); + } else { + ovs_router_show_text(&ds, cls, table, true); + } unixctl_command_reply(conn, ds_cstr(&ds)); ds_destroy(&ds); } @@ -930,7 +975,7 @@ ovs_router_init(void) "ip/plen dev [gw] " "[pkt_mark=mark] [src=src_ip]", 2, 5, ovs_router_add, NULL); - unixctl_command_register("ovs/route/show", "", 0, 0, + unixctl_command_register("ovs/route/show", "[table=all|id]", 0, 1, ovs_router_show, NULL); unixctl_command_register("ovs/route/del", "ip/plen " "[pkt_mark=mark]", 1, 2, ovs_router_del, diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man index 245d2030bdc4..657f1d077d70 100644 --- a/ofproto/ofproto-tnl-unixctl.man +++ b/ofproto/ofproto-tnl-unixctl.man @@ -7,9 +7,12 @@ Adds \fIip\fR/\fIplen\fR route to vswitchd routing table. \fIoutput_bridge\fR needs to be OVS bridge name. This command is useful if OVS cached routes does not look right. . -.IP "\fBovs/route/show\fR" -Print all routes in OVS routing table, This includes routes cached -from system routing table and user configured routes. +.IP "\fBovs/route/show\fR [\fBtable\fR=\fBall\fR|\fIid\fR]" +Print routes in OVS routing table. This includes routes cached +from system routing table and user configured routes. By default, the contents +of all the default tables (local, main, default) is displayed, unless requested +otherwise with \fItable\fR parameter. In this case the 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. diff --git a/tests/ovs-router.at b/tests/ovs-router.at index b86d0a1cd37c..4e5e26688b14 100644 --- a/tests/ovs-router.at +++ b/tests/ovs-router.at @@ -30,6 +30,17 @@ User: 2.2.2.3/32 MARK 1 dev br0 SRC 2.2.2.2 ]) AT_CHECK([ovs-appctl --format=json --pretty ovs/route/show], [0], [dnl [[ + { + "dst": "2.2.2.2", + "local": true, + "nexthops": [ + { + "dev": "br0"}], + "prefix": 32, + "prefsrc": "2.2.2.2", + "priority": 192, + "table": 255, + "user": false}, { "dst": "2.2.2.3", "local": false, @@ -40,6 +51,7 @@ AT_CHECK([ovs-appctl --format=json --pretty ovs/route/show], [0], [dnl "prefix": 32, "prefsrc": "2.2.2.2", "priority": 160, + "table": 254, "user": true}, { "dst": "2.2.2.0", @@ -50,6 +62,7 @@ AT_CHECK([ovs-appctl --format=json --pretty ovs/route/show], [0], [dnl "prefix": 24, "prefsrc": "2.2.2.2", "priority": 120, + "table": 254, "user": false}, { "dst": "1.1.1.0", @@ -61,6 +74,7 @@ AT_CHECK([ovs-appctl --format=json --pretty ovs/route/show], [0], [dnl "prefix": 24, "prefsrc": "2.2.2.2", "priority": 152, + "table": 254, "user": true}, { "dst": "1.1.2.0", @@ -73,6 +87,7 @@ AT_CHECK([ovs-appctl --format=json --pretty ovs/route/show], [0], [dnl "prefix": 24, "prefsrc": "2.2.2.2", "priority": 152, + "table": 254, "user": true}]] ]) OVS_VSWITCHD_STOP -- 2.50.1 _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev