| Message ID | 20250723131253.3704827-5-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 |
On 7/23/25 3:12 PM, Dima Chumak via dev wrote: > Introduce an optional parameter to `ovs-appctl ovs/route/show` for > printing non-default routing tables: > > ovs-appctl ovs/route/show [table=ID|all] > > 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 <dchumak@nvidia.com> > --- > Documentation/howto/userspace-tunneling.rst | 2 +- > NEWS | 2 + > lib/ovs-router.c | 180 ++++++++++++++------ > ofproto/ofproto-tnl-unixctl.man | 9 +- > tests/ovs-router.at | 4 + > 5 files changed, 142 insertions(+), 55 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 b5d565ecc73f..97554be8e6b4 100644 > --- a/NEWS > +++ b/NEWS > @@ -24,6 +24,8 @@ v3.6.0 - xx xxx xxxx > core file size. > - ovs-appctl: > * Added JSON output support to the 'ovs/route/show' command. > + * 'ovs/route/show': added new option, table=[ID|all], to list routes from > + a specific OVS table or all routes from all tables. We branched for 3.6 on July 16th. These NEWS entries should go into the Post-v3.6.0 section. > - 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 2addc7b43d07..eaf688467389 100644 > --- a/lib/ovs-router.c > +++ b/lib/ovs-router.c > @@ -642,22 +642,15 @@ 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_entries, const struct classifier *cls, > + uint32_t table) > { > - int n_rules = classifier_count(&cls_main); > - struct json **json_entries = NULL; > + int n_rules = classifier_count(cls); > + struct ds ds = DS_EMPTY_INITIALIZER; > struct ovs_router_entry *rt; > - struct ds ds; > int i = 0; > > - if (!n_rules) { > - goto out; > - } > - > - 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; > @@ -673,6 +666,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)); > @@ -702,48 +696,53 @@ ovs_router_show_json(struct json **routes) > } > > ds_destroy(&ds); > - > -out: > - *routes = json_array_create(json_entries, i); > } > > 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[] = { &cls_local, &cls_main, &cls_default }; > struct ovs_router_entry *rt; > > - ds_put_format(ds, "Route Table:\n"); > - for (int i = 0; i < ARRAY_SIZE(std_cls); i++) { > - 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); > - } > + if (show_header) { > + if (route_table_is_standard_id(table)) { > + ds_put_format(ds, "Route Table:\n"); > + } else { > + ds_put_format(ds, "Route Table #%u:\n", table); PRIu32 > + } > + } > > - 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"); > + 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); > + } > + > + 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 (!route_table_is_standard_id(table) && !show_header) { > + ds_put_format(ds, " table %u", table); PRIu32 > + } > + ds_put_format(ds, "\n"); > } > } > > @@ -751,15 +750,94 @@ 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 = &cls_main; > + uint32_t table = CLS_MAIN; > + > + if (argc > 1) { > + if (!strcmp(argv[1], "table=all")) { > + table = CLS_ALL; > + } else if (!ovs_scan(argv[1], "table=%"SCNi32, &table)) { SCNu32 ? > + unixctl_command_reply_error(conn, "Invalid table format"); > + return; > + } > + } > + > + if (table != CLS_ALL) { > + cls = cls_find(table); > + if (!cls) { > + ds_put_format(&ds, "Invalid param, table '%s' not found", argv[1]); Please, don't shorten the words in user-visible text, but also the "Invalid param" part seems unnecessary. > + 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, **json_entries = NULL; > + struct json **cls_entries; > + size_t num_routes = 0; > + > + if (table == CLS_ALL) { > + struct clsmap_node *node; > + > + ovs_mutex_lock(&mutex); > + > + HMAP_FOR_EACH (node, hash_node, &clsmap) { > + num_routes += node->cls.n_rules; > + } > > - ovs_router_show_json(&routes); > + num_routes += cls_main.n_rules; > + json_entries = xzalloc(num_routes * sizeof *json_entries); > + cls_entries = json_entries; > + > + HMAP_FOR_EACH (node, hash_node, &clsmap) { > + ovs_router_show_json(cls_entries, &node->cls, node->table); We have so many allocation inside, so it doesn't really matter if we save a couple reallocs by counting the exact number of elements beforehand. We should just create an empty json array and pass it into ovs_router_show_json(), where we can use json_array_add(). It will be much easier to understand what's going on here without manual allocations and the pointer arithmetic. > + cls_entries += node->cls.n_rules; > + } > + ovs_router_show_json(cls_entries, &cls_main, CLS_MAIN); > + > + ovs_mutex_unlock(&mutex); > + } else if (route_table_is_standard_id(table)) { > + num_routes += cls_local.n_rules + cls_main.n_rules + > + cls_default.n_rules; > + json_entries = xzalloc(num_routes * sizeof *json_entries); > + cls_entries = json_entries; > + > + ovs_router_show_json(cls_entries, &cls_local, CLS_LOCAL); > + cls_entries += cls_local.n_rules; > + ovs_router_show_json(cls_entries, &cls_main, CLS_MAIN); > + cls_entries += cls_main.n_rules; > + ovs_router_show_json(cls_entries, &cls_default, CLS_DEFAULT); > + } else { > + if (cls->n_rules) { > + num_routes = cls->n_rules; > + json_entries = xmalloc(num_routes * sizeof *json_entries); > + ovs_router_show_json(json_entries, cls, table); > + } > + } > + > + routes = json_array_create(json_entries, num_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); > + ovs_router_show_text(&ds, &cls_local, CLS_LOCAL, false); > + ovs_mutex_lock(&mutex); > + HMAP_FOR_EACH (node, hash_node, &clsmap) { > + ovs_router_show_text(&ds, &node->cls, node->table, false); > + } > + ovs_mutex_unlock(&mutex); > + ovs_router_show_text(&ds, &cls_main, CLS_MAIN, false); > + ovs_router_show_text(&ds, &cls_default, CLS_DEFAULT, false); > + } else if (route_table_is_standard_id(table)) { > + ovs_router_show_text(&ds, &cls_local, CLS_LOCAL, true); > + ovs_router_show_text(&ds, &cls_main, CLS_MAIN, false); > + ovs_router_show_text(&ds, &cls_default, CLS_DEFAULT, false); > + } else { > + ovs_router_show_text(&ds, cls, table, true); > + } > unixctl_command_reply(conn, ds_cstr(&ds)); > ds_destroy(&ds); > } > @@ -935,7 +1013,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=ID|all]", 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 a801cfdccc5c..b9e4d99b2bf8 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 [table=\fIID|all\fB]\fR" The '|' should not be italic. For some reson all the commands in this file do not close the original bold after the command name ends while they should... > +Print routes in OVS routing table. This includes routes cached > +from system routing table and user configured routes. By default, the contents > +of the main routing table is displayed, unless requested otherwise with s/main table/all the default tables (local, main, default)/ > +\fItable\fR parameter. In this case the contents of a specific table ID or of > +all routing tables is printed. > . > .IP "\fBovs/route/del ip/plen [pkt_mark=mark]\fR" > Delete ip/plen route from OVS routing table. > diff --git a/tests/ovs-router.at b/tests/ovs-router.at > index 641b780a582a..dac096cc1aec 100644 > --- a/tests/ovs-router.at > +++ b/tests/ovs-router.at > @@ -39,6 +39,7 @@ AT_CHECK([ovs-appctl --format=json --pretty ovs/route/show], [0], [dnl > "prefix": 24, > "prefsrc": "2.2.2.2", > "priority": 184, > + "table": 254, > "user": false}, > { > "dst": "1.1.1.0", > @@ -50,6 +51,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", > @@ -62,6 +64,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": "2.2.2.3", > @@ -73,6 +76,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}]] > ]) > OVS_VSWITCHD_STOP
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 b5d565ecc73f..97554be8e6b4 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,8 @@ v3.6.0 - xx xxx xxxx core file size. - ovs-appctl: * Added JSON output support to the 'ovs/route/show' command. + * 'ovs/route/show': added new option, table=[ID|all], to list routes from + a specific OVS table or all routes from all tables. - 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 2addc7b43d07..eaf688467389 100644 --- a/lib/ovs-router.c +++ b/lib/ovs-router.c @@ -642,22 +642,15 @@ 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_entries, const struct classifier *cls, + uint32_t table) { - int n_rules = classifier_count(&cls_main); - struct json **json_entries = NULL; + int n_rules = classifier_count(cls); + struct ds ds = DS_EMPTY_INITIALIZER; struct ovs_router_entry *rt; - struct ds ds; int i = 0; - if (!n_rules) { - goto out; - } - - 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; @@ -673,6 +666,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)); @@ -702,48 +696,53 @@ ovs_router_show_json(struct json **routes) } ds_destroy(&ds); - -out: - *routes = json_array_create(json_entries, i); } 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[] = { &cls_local, &cls_main, &cls_default }; struct ovs_router_entry *rt; - ds_put_format(ds, "Route Table:\n"); - for (int i = 0; i < ARRAY_SIZE(std_cls); i++) { - 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); - } + if (show_header) { + if (route_table_is_standard_id(table)) { + ds_put_format(ds, "Route Table:\n"); + } else { + ds_put_format(ds, "Route Table #%u:\n", table); + } + } - 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"); + 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); + } + + 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 (!route_table_is_standard_id(table) && !show_header) { + ds_put_format(ds, " table %u", table); + } + ds_put_format(ds, "\n"); } } @@ -751,15 +750,94 @@ 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 = &cls_main; + uint32_t table = CLS_MAIN; + + if (argc > 1) { + if (!strcmp(argv[1], "table=all")) { + table = CLS_ALL; + } else if (!ovs_scan(argv[1], "table=%"SCNi32, &table)) { + unixctl_command_reply_error(conn, "Invalid table format"); + return; + } + } + + if (table != CLS_ALL) { + cls = cls_find(table); + if (!cls) { + ds_put_format(&ds, "Invalid param, 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, **json_entries = NULL; + struct json **cls_entries; + size_t num_routes = 0; + + if (table == CLS_ALL) { + struct clsmap_node *node; + + ovs_mutex_lock(&mutex); + + HMAP_FOR_EACH (node, hash_node, &clsmap) { + num_routes += node->cls.n_rules; + } - ovs_router_show_json(&routes); + num_routes += cls_main.n_rules; + json_entries = xzalloc(num_routes * sizeof *json_entries); + cls_entries = json_entries; + + HMAP_FOR_EACH (node, hash_node, &clsmap) { + ovs_router_show_json(cls_entries, &node->cls, node->table); + cls_entries += node->cls.n_rules; + } + ovs_router_show_json(cls_entries, &cls_main, CLS_MAIN); + + ovs_mutex_unlock(&mutex); + } else if (route_table_is_standard_id(table)) { + num_routes += cls_local.n_rules + cls_main.n_rules + + cls_default.n_rules; + json_entries = xzalloc(num_routes * sizeof *json_entries); + cls_entries = json_entries; + + ovs_router_show_json(cls_entries, &cls_local, CLS_LOCAL); + cls_entries += cls_local.n_rules; + ovs_router_show_json(cls_entries, &cls_main, CLS_MAIN); + cls_entries += cls_main.n_rules; + ovs_router_show_json(cls_entries, &cls_default, CLS_DEFAULT); + } else { + if (cls->n_rules) { + num_routes = cls->n_rules; + json_entries = xmalloc(num_routes * sizeof *json_entries); + ovs_router_show_json(json_entries, cls, table); + } + } + + routes = json_array_create(json_entries, num_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); + ovs_router_show_text(&ds, &cls_local, CLS_LOCAL, false); + ovs_mutex_lock(&mutex); + HMAP_FOR_EACH (node, hash_node, &clsmap) { + ovs_router_show_text(&ds, &node->cls, node->table, false); + } + ovs_mutex_unlock(&mutex); + ovs_router_show_text(&ds, &cls_main, CLS_MAIN, false); + ovs_router_show_text(&ds, &cls_default, CLS_DEFAULT, false); + } else if (route_table_is_standard_id(table)) { + ovs_router_show_text(&ds, &cls_local, CLS_LOCAL, true); + ovs_router_show_text(&ds, &cls_main, CLS_MAIN, false); + ovs_router_show_text(&ds, &cls_default, CLS_DEFAULT, false); + } else { + ovs_router_show_text(&ds, cls, table, true); + } unixctl_command_reply(conn, ds_cstr(&ds)); ds_destroy(&ds); } @@ -935,7 +1013,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=ID|all]", 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 a801cfdccc5c..b9e4d99b2bf8 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 [table=\fIID|all\fB]\fR" +Print routes in OVS routing table. This includes routes cached +from system routing table and user configured routes. By default, the contents +of the main routing table 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 ip/plen [pkt_mark=mark]\fR" Delete ip/plen route from OVS routing table. diff --git a/tests/ovs-router.at b/tests/ovs-router.at index 641b780a582a..dac096cc1aec 100644 --- a/tests/ovs-router.at +++ b/tests/ovs-router.at @@ -39,6 +39,7 @@ AT_CHECK([ovs-appctl --format=json --pretty ovs/route/show], [0], [dnl "prefix": 24, "prefsrc": "2.2.2.2", "priority": 184, + "table": 254, "user": false}, { "dst": "1.1.1.0", @@ -50,6 +51,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", @@ -62,6 +64,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": "2.2.2.3", @@ -73,6 +76,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}]] ]) OVS_VSWITCHD_STOP
Introduce an optional parameter to `ovs-appctl ovs/route/show` for printing non-default routing tables: ovs-appctl ovs/route/show [table=ID|all] 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 <dchumak@nvidia.com> --- Documentation/howto/userspace-tunneling.rst | 2 +- NEWS | 2 + lib/ovs-router.c | 180 ++++++++++++++------ ofproto/ofproto-tnl-unixctl.man | 9 +- tests/ovs-router.at | 4 + 5 files changed, 142 insertions(+), 55 deletions(-)