| Message ID | 20251027124259.3395209-9-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: > Introduce an optional parameter to `ovs-appctl ovs/route/show` for > adding/deleting user routes in non-default routing tables. > > A table with ID doesn't have to exist before adding a route, OVS will > create a new table if it is missing and will add a user route there. > Though, to effect route lookup such table has to be referenced by a > routing rule. > > Signed-off-by: Dima Chumak <dchumak@nvidia.com> > --- > Documentation/howto/userspace-tunneling.rst | 5 +- > NEWS | 2 + > lib/ovs-router.c | 62 ++++++++++++++++----- > ofproto/ofproto-tnl-unixctl.man | 14 +++-- > 4 files changed, 64 insertions(+), 19 deletions(-) > > diff --git a/Documentation/howto/userspace-tunneling.rst b/Documentation/howto/userspace-tunneling.rst > index c7c6464520a6..8116e81e5a7d 100644 > --- a/Documentation/howto/userspace-tunneling.rst > +++ b/Documentation/howto/userspace-tunneling.rst > @@ -201,7 +201,8 @@ Tunnel routing table > > To add route:: > > - $ ovs-appctl ovs/route/add <IP address>/<prefix length> <output-bridge-name> <gw> > + $ ovs-appctl ovs/route/add <IP address>/<prefix length> > + <output-bridge-name> <gw> [table=ID] > > To see all routes configured:: > > @@ -213,7 +214,7 @@ To see all router rules configured:: > > To delete route:: > > - $ ovs-appctl ovs/route/del <IP address>/<prefix length> > + $ ovs-appctl ovs/route/del <IP address>/<prefix length> [table=ID] > > To look up and display the route for a destination:: > > diff --git a/NEWS b/NEWS > index 8ce1a08da6b7..d183d6caad5a 100644 > --- a/NEWS > +++ b/NEWS > @@ -21,6 +21,8 @@ Post-v3.6.0 > * '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. > + * 'ovs/route/add' and 'ovs/route/del': added new option, table=ID, to > + add/delete a route from a specific OVS table. nit: 'OVS table' may be a little ambiguous as there are OpenFlow tables and maybe some other tables. It's clear that we're talking about routing tables, so it may be better to omit the 'OVS' here. > > > v3.6.0 - 18 Aug 2025 > diff --git a/lib/ovs-router.c b/lib/ovs-router.c > index d67a098ba48f..a6486c48b7e2 100644 > --- a/lib/ovs-router.c > +++ b/lib/ovs-router.c > @@ -461,7 +461,7 @@ rt_entry_delete__(const struct cls_rule *cr, struct classifier *cls) > } > > static bool > -rt_entry_delete(uint32_t mark, uint8_t priority, > +rt_entry_delete(struct classifier *cls, uint32_t mark, uint8_t priority, > const struct in6_addr *ip6_dst, uint8_t plen) > { > struct classifier *cls_main = cls_find(CLS_MAIN); > @@ -479,10 +479,10 @@ rt_entry_delete(uint32_t mark, uint8_t priority, > cls_rule_init(&rule, &match, priority); > > /* Find the exact rule. */ > - cr = classifier_find_rule_exactly(cls_main, &rule, OVS_VERSION_MAX); > + cr = classifier_find_rule_exactly(cls, &rule, OVS_VERSION_MAX); > if (cr) { > ovs_mutex_lock(&mutex); > - rt_entry_delete__(cr, cls_main); > + rt_entry_delete__(cr, cls); > ovs_mutex_unlock(&mutex); > > res = true; > @@ -521,6 +521,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, > struct in6_addr src6 = in6addr_any; > struct in6_addr gw6 = in6addr_any; > char src6_s[IPV6_SCAN_LEN + 1]; > + uint32_t table = CLS_MAIN; > struct in6_addr ip6; > uint32_t mark = 0; > unsigned int plen; > @@ -545,7 +546,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, > > /* Parse optional parameters. */ > for (i = 3; i < argc; i++) { > - if (ovs_scan(argv[i], "pkt_mark=%"SCNi32, &mark)) { > + if (ovs_scan(argv[i], "pkt_mark=%"SCNu32, &mark)) { > continue; > } > > @@ -566,6 +567,13 @@ ovs_router_add(struct unixctl_conn *conn, int argc, > } > } > > + if (ovs_scan(argv[i], "table=%"SCNu32, &table)) { > + continue; > + } else if (ovs_scan(argv[i], "table=")) { > + unixctl_command_reply_error(conn, "Invalid table format"); > + return; > + } > + > unixctl_command_reply_error(conn, > "Invalid pkt_mark, IP gateway or src_ip"); > return; > @@ -578,7 +586,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, > in6_addr_set_mapped_ipv4(&src6, src); > } > > - err = ovs_router_insert__(CLS_MAIN, mark, plen + 32, true, &ip6, plen, > + err = ovs_router_insert__(table, mark, plen + 32, true, &ip6, plen, > argv[2], &gw6, &src6); > if (err) { > unixctl_command_reply_error(conn, "Error while inserting route."); > @@ -591,10 +599,13 @@ static void > ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED, > const char *argv[], void *aux OVS_UNUSED) > { > + struct classifier *cls = cls_find(CLS_MAIN); > struct in6_addr ip6; > uint32_t mark = 0; > unsigned int plen; > + uint32_t table; > ovs_be32 ip; > + int i; > > if (scan_ipv4_route(argv[1], &ip, &plen)) { > in6_addr_set_mapped_ipv4(&ip6, ip); > @@ -603,14 +614,39 @@ ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED, > unixctl_command_reply_error(conn, "Invalid parameters"); > return; > } > - if (argc > 2) { > - if (!ovs_scan(argv[2], "pkt_mark=%"SCNi32, &mark)) { > - unixctl_command_reply_error(conn, "Invalid pkt_mark"); > + > + /* Parse optional parameters. */ > + for (i = 2; i < argc; i++) { > + if (ovs_scan(argv[i], "pkt_mark=%"SCNu32, &mark)) { > + continue; > + } > + > + if (ovs_scan(argv[i], "table=%"SCNu32, &table)) { > + cls = cls_find(table); > + if (!cls) { > + struct ds ds = DS_EMPTY_INITIALIZER; > + > + ds_put_format(&ds, "Table %s not found", argv[i]); > + unixctl_command_reply_error(conn, ds_cstr_ro(&ds)); > + ds_destroy(&ds); > + return; > + } > + continue; > + } else if (ovs_scan(argv[i], "table=")) { > + unixctl_command_reply_error(conn, "Invalid table format"); > return; > } > + > + unixctl_command_reply_error(conn, "Invalid pkt_mark or table"); > + return; > + } > + > + if (!cls) { > + unixctl_command_reply_error(conn, "Table not found"); > + return; > } > > - if (rt_entry_delete(mark, plen + 32, &ip6, plen)) { > + if (rt_entry_delete(cls, mark, plen + 32, &ip6, plen)) { > unixctl_command_reply(conn, "OK"); > seq_change(tnl_conf_seq); > } else { > @@ -1074,13 +1110,13 @@ ovs_router_init(void) > fatal_signal_add_hook(ovs_router_flush_handler, NULL, NULL, true); > unixctl_command_register("ovs/route/add", > "ip/plen dev [gw] " > - "[pkt_mark=mark] [src=src_ip]", > - 2, 5, ovs_router_add, NULL); > + "[pkt_mark=mark] [src=src_ip] [table=id]", > + 2, 6, ovs_router_add, NULL); > 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, > - NULL); > + "[pkt_mark=mark] [table=id]", 1, 3, > + ovs_router_del, NULL); > unixctl_command_register("ovs/route/lookup", "ip_addr " > "[pkt_mark=mark]", 1, 2, > ovs_router_lookup_cmd, NULL); > diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man > index b62063dcdae0..9cab99e6ffa7 100644 > --- a/ofproto/ofproto-tnl-unixctl.man > +++ b/ofproto/ofproto-tnl-unixctl.man > @@ -2,10 +2,13 @@ > These commands query and modify OVS tunnel components. > . > .IP "\fBovs/route/add\fR \fIip\fR/\fIplen\fR \fIoutput_bridge\fR \ > -[\fIgw\fR] [\fBpkt_mark\fR=\fImark\fR] [\fBsrc\fR=\fIsrc_ip\fR]" > +[\fIgw\fR] [\fBpkt_mark\fR=\fImark\fR] [\fBsrc\fR=\fIsrc_ip\fR] \ > +[\fBtable\fR=\fIid\fR]" > 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. > +routes does not look right. A non-standard table ID can be specified, in which > +case the route is added to that routing table. The table is created if it > +doesn't exist. > . > .IP "\fBovs/route/show\fR [\fBtable\fR=\fBall\fR|\fIid\fR]" > Print routes in OVS routing table. This includes routes cached from > @@ -14,8 +17,11 @@ 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. > +.IP "\fBovs/route/del\fR \fIip\fR/\fIplen\fR [\fBpkt_mark\fR=\fImark\fR] \ > +[\fBtable\fR=\fIid\fR]" > +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/rule/show\fR" > Print routing rules in OVS. This includes routing rules cached from the system
diff --git a/Documentation/howto/userspace-tunneling.rst b/Documentation/howto/userspace-tunneling.rst index c7c6464520a6..8116e81e5a7d 100644 --- a/Documentation/howto/userspace-tunneling.rst +++ b/Documentation/howto/userspace-tunneling.rst @@ -201,7 +201,8 @@ Tunnel routing table To add route:: - $ ovs-appctl ovs/route/add <IP address>/<prefix length> <output-bridge-name> <gw> + $ ovs-appctl ovs/route/add <IP address>/<prefix length> + <output-bridge-name> <gw> [table=ID] To see all routes configured:: @@ -213,7 +214,7 @@ To see all router rules configured:: To delete route:: - $ ovs-appctl ovs/route/del <IP address>/<prefix length> + $ ovs-appctl ovs/route/del <IP address>/<prefix length> [table=ID] To look up and display the route for a destination:: diff --git a/NEWS b/NEWS index 8ce1a08da6b7..d183d6caad5a 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,8 @@ Post-v3.6.0 * '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. + * 'ovs/route/add' and 'ovs/route/del': added new option, table=ID, to + add/delete a route from a specific OVS table. v3.6.0 - 18 Aug 2025 diff --git a/lib/ovs-router.c b/lib/ovs-router.c index d67a098ba48f..a6486c48b7e2 100644 --- a/lib/ovs-router.c +++ b/lib/ovs-router.c @@ -461,7 +461,7 @@ rt_entry_delete__(const struct cls_rule *cr, struct classifier *cls) } static bool -rt_entry_delete(uint32_t mark, uint8_t priority, +rt_entry_delete(struct classifier *cls, uint32_t mark, uint8_t priority, const struct in6_addr *ip6_dst, uint8_t plen) { struct classifier *cls_main = cls_find(CLS_MAIN); @@ -479,10 +479,10 @@ rt_entry_delete(uint32_t mark, uint8_t priority, cls_rule_init(&rule, &match, priority); /* Find the exact rule. */ - cr = classifier_find_rule_exactly(cls_main, &rule, OVS_VERSION_MAX); + cr = classifier_find_rule_exactly(cls, &rule, OVS_VERSION_MAX); if (cr) { ovs_mutex_lock(&mutex); - rt_entry_delete__(cr, cls_main); + rt_entry_delete__(cr, cls); ovs_mutex_unlock(&mutex); res = true; @@ -521,6 +521,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, struct in6_addr src6 = in6addr_any; struct in6_addr gw6 = in6addr_any; char src6_s[IPV6_SCAN_LEN + 1]; + uint32_t table = CLS_MAIN; struct in6_addr ip6; uint32_t mark = 0; unsigned int plen; @@ -545,7 +546,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, /* Parse optional parameters. */ for (i = 3; i < argc; i++) { - if (ovs_scan(argv[i], "pkt_mark=%"SCNi32, &mark)) { + if (ovs_scan(argv[i], "pkt_mark=%"SCNu32, &mark)) { continue; } @@ -566,6 +567,13 @@ ovs_router_add(struct unixctl_conn *conn, int argc, } } + if (ovs_scan(argv[i], "table=%"SCNu32, &table)) { + continue; + } else if (ovs_scan(argv[i], "table=")) { + unixctl_command_reply_error(conn, "Invalid table format"); + return; + } + unixctl_command_reply_error(conn, "Invalid pkt_mark, IP gateway or src_ip"); return; @@ -578,7 +586,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc, in6_addr_set_mapped_ipv4(&src6, src); } - err = ovs_router_insert__(CLS_MAIN, mark, plen + 32, true, &ip6, plen, + err = ovs_router_insert__(table, mark, plen + 32, true, &ip6, plen, argv[2], &gw6, &src6); if (err) { unixctl_command_reply_error(conn, "Error while inserting route."); @@ -591,10 +599,13 @@ static void ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED, const char *argv[], void *aux OVS_UNUSED) { + struct classifier *cls = cls_find(CLS_MAIN); struct in6_addr ip6; uint32_t mark = 0; unsigned int plen; + uint32_t table; ovs_be32 ip; + int i; if (scan_ipv4_route(argv[1], &ip, &plen)) { in6_addr_set_mapped_ipv4(&ip6, ip); @@ -603,14 +614,39 @@ ovs_router_del(struct unixctl_conn *conn, int argc OVS_UNUSED, unixctl_command_reply_error(conn, "Invalid parameters"); return; } - if (argc > 2) { - if (!ovs_scan(argv[2], "pkt_mark=%"SCNi32, &mark)) { - unixctl_command_reply_error(conn, "Invalid pkt_mark"); + + /* Parse optional parameters. */ + for (i = 2; i < argc; i++) { + if (ovs_scan(argv[i], "pkt_mark=%"SCNu32, &mark)) { + continue; + } + + if (ovs_scan(argv[i], "table=%"SCNu32, &table)) { + cls = cls_find(table); + if (!cls) { + struct ds ds = DS_EMPTY_INITIALIZER; + + ds_put_format(&ds, "Table %s not found", argv[i]); + unixctl_command_reply_error(conn, ds_cstr_ro(&ds)); + ds_destroy(&ds); + return; + } + continue; + } else if (ovs_scan(argv[i], "table=")) { + unixctl_command_reply_error(conn, "Invalid table format"); return; } + + unixctl_command_reply_error(conn, "Invalid pkt_mark or table"); + return; + } + + if (!cls) { + unixctl_command_reply_error(conn, "Table not found"); + return; } - if (rt_entry_delete(mark, plen + 32, &ip6, plen)) { + if (rt_entry_delete(cls, mark, plen + 32, &ip6, plen)) { unixctl_command_reply(conn, "OK"); seq_change(tnl_conf_seq); } else { @@ -1074,13 +1110,13 @@ ovs_router_init(void) fatal_signal_add_hook(ovs_router_flush_handler, NULL, NULL, true); unixctl_command_register("ovs/route/add", "ip/plen dev [gw] " - "[pkt_mark=mark] [src=src_ip]", - 2, 5, ovs_router_add, NULL); + "[pkt_mark=mark] [src=src_ip] [table=id]", + 2, 6, ovs_router_add, NULL); 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, - NULL); + "[pkt_mark=mark] [table=id]", 1, 3, + ovs_router_del, NULL); unixctl_command_register("ovs/route/lookup", "ip_addr " "[pkt_mark=mark]", 1, 2, ovs_router_lookup_cmd, NULL); diff --git a/ofproto/ofproto-tnl-unixctl.man b/ofproto/ofproto-tnl-unixctl.man index b62063dcdae0..9cab99e6ffa7 100644 --- a/ofproto/ofproto-tnl-unixctl.man +++ b/ofproto/ofproto-tnl-unixctl.man @@ -2,10 +2,13 @@ These commands query and modify OVS tunnel components. . .IP "\fBovs/route/add\fR \fIip\fR/\fIplen\fR \fIoutput_bridge\fR \ -[\fIgw\fR] [\fBpkt_mark\fR=\fImark\fR] [\fBsrc\fR=\fIsrc_ip\fR]" +[\fIgw\fR] [\fBpkt_mark\fR=\fImark\fR] [\fBsrc\fR=\fIsrc_ip\fR] \ +[\fBtable\fR=\fIid\fR]" 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. +routes does not look right. A non-standard table ID can be specified, in which +case the route is added to that routing table. The table is created if it +doesn't exist. . .IP "\fBovs/route/show\fR [\fBtable\fR=\fBall\fR|\fIid\fR]" Print routes in OVS routing table. This includes routes cached from @@ -14,8 +17,11 @@ 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. +.IP "\fBovs/route/del\fR \fIip\fR/\fIplen\fR [\fBpkt_mark\fR=\fImark\fR] \ +[\fBtable\fR=\fIid\fR]" +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/rule/show\fR" Print routing rules in OVS. This includes routing rules cached from the system
Introduce an optional parameter to `ovs-appctl ovs/route/show` for adding/deleting user routes in non-default routing tables. A table with ID doesn't have to exist before adding a route, OVS will create a new table if it is missing and will add a user route there. Though, to effect route lookup such table has to be referenced by a routing rule. Signed-off-by: Dima Chumak <dchumak@nvidia.com> --- Documentation/howto/userspace-tunneling.rst | 5 +- NEWS | 2 + lib/ovs-router.c | 62 ++++++++++++++++----- ofproto/ofproto-tnl-unixctl.man | 14 +++-- 4 files changed, 64 insertions(+), 19 deletions(-)