On 22/04/2025 16:37, Roi Dayan wrote:
> From: Dima Chumak <dchu...@nvidia.com>
>
> The 'ovs/route/show' command now supports machine-readable JSON output
> in addition to the plain-text output for humans.
> Align the keys to match ip route output so also update the command
> help output from mask to mask.
>
> An example json output would be:
>
> ovs-appctl --format json --pretty ovs/route/show
> [
> {
> "local": false,
> "dst": "::1",
> "dev": "lo",
> "mask": 128,
> "priority": 128,
> "prefsrc": "::1"},
> {
> "local": true,
> "dst": "10.237.157.103",
> "dev": "eth1",
> "mask": 128,
> "priority": 192,
> "prefsrc": "10.237.157.103"},
> {
> "local": true,
> "dst": "fe80::42:67ff:fe28:188",
> "dev": "docker0",
> "mask": 128,
> "priority": 192,
> "prefsrc": "fe80::42:67ff:fe28:188"},
> {
> "gw": "192.168.121.1",
> "local": false,
> "dst": "0.0.0.0",
> "dev": "eth0",
> "mask": 96,
> "priority": 96,
> "prefsrc": "192.168.121.203"}]
>
> Signed-off-by: Dima Chumak <dchu...@nvidia.com>
> Reviewed-by: Roi Dayan <r...@nvidia.com>
> ---
>
> Notes:
> v2
> - Don't prefix boolean with "is_". Use key "local" instead of "is_local".
> - Add "user" key.
> - Use ds_clear() in the loop and ds_destroy() outside the loop to avoid
> repeated malloc/free.
> - Align json keys to ip route command output.
>
> lib/ovs-router.c | 113 +++++++++++++++++++++++++++++++++++---------
> tests/ovs-router.at | 35 ++++++++++++++
> 2 files changed, 126 insertions(+), 22 deletions(-)
>
> diff --git a/lib/ovs-router.c b/lib/ovs-router.c
> index d955a3a543b8..11827bf3c72b 100644
> --- a/lib/ovs-router.c
> +++ b/lib/ovs-router.c
> @@ -36,6 +36,7 @@
> #include "dpif.h"
> #include "fatal-signal.h"
> #include "openvswitch/dynamic-string.h"
> +#include "openvswitch/json.h"
> #include "netdev.h"
> #include "packets.h"
> #include "seq.h"
> @@ -429,7 +430,7 @@ ovs_router_add(struct unixctl_conn *conn, int argc,
> is_ipv6 = true;
> } else {
> unixctl_command_reply_error(conn,
> - "Invalid 'ip/plen' parameter");
> + "Invalid 'ip/mask' parameter");
> return;
> }
>
> @@ -509,44 +510,112 @@ ovs_router_del(struct unixctl_conn *conn, int argc
> OVS_UNUSED,
> }
>
> static void
> -ovs_router_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> - const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
> +ovs_router_show_json(struct json **routes)
> {
> + struct json **json_entries = NULL;
> struct ovs_router_entry *rt;
> - struct ds ds = DS_EMPTY_INITIALIZER;
> + struct ds ds;
> + int i = 0;
>
> - ds_put_format(&ds, "Route Table:\n");
> - CLS_FOR_EACH(rt, cr, &cls) {
> + if (!cls.n_rules) {
> + goto out;
> + }
> +
> + json_entries = xmalloc(cls.n_rules * sizeof *json_entries);
> +
> + CLS_FOR_EACH (rt, cr, &cls) {
> + bool user = rt->priority != rt->plen && !rt->local;
> + struct json *json = json_object_create();
> +
> + 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));
> + json_object_put(json, "mask", json_integer_create(rt->plen));
> + json_object_put_string(json, "dev", rt->output_netdev);
> +
> + ds_init(&ds);
> + ipv6_format_mapped(&rt->nw_addr, &ds);
> + json_object_put_string(json, "dst", ds_cstr_ro(&ds));
> + ds_clear(&ds);
> +
> + ds_init(&ds);
> + ipv6_format_mapped(&rt->src_addr, &ds);
> + json_object_put_string(json, "prefsrc", ds_cstr_ro(&ds));
> + ds_clear(&ds);
> +
> + if (rt->mark) {
> + json_object_put(json, "mark", json_integer_create(rt->mark));
> + }
> +
> + if (ipv6_addr_is_set(&rt->gw)) {
> + ds_init(&ds);
> + ipv6_format_mapped(&rt->gw, &ds);
> + json_object_put_string(json, "gw", ds_cstr_ro(&ds));
> + ds_clear(&ds);
> + }
> +
> + json_entries[i++] = json;
> + }
> +
> + ds_destroy(&ds);
> +
> +out:
> + *routes = json_array_create(json_entries, i);
> +}
> +
> +static void
> +ovs_router_show_text(struct ds *ds)
> +{
> + struct ovs_router_entry *rt;
> +
> + ds_put_format(ds, "Route Table:\n");
> + CLS_FOR_EACH (rt, cr, &cls) {
> uint8_t plen;
> if (rt->priority == rt->plen || rt->local) {
> - ds_put_format(&ds, "Cached: ");
> + ds_put_format(ds, "Cached: ");
> } else {
> - ds_put_format(&ds, "User: ");
> + ds_put_format(ds, "User: ");
> }
> - ipv6_format_mapped(&rt->nw_addr, &ds);
> + 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);
> + ds_put_format(ds, "/%"PRIu8, plen);
> if (rt->mark) {
> - ds_put_format(&ds, " MARK %"PRIu32, rt->mark);
> + ds_put_format(ds, " MARK %"PRIu32, rt->mark);
> }
>
> - ds_put_format(&ds, " dev %s", rt->output_netdev);
> + 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, " GW ");
> + ipv6_format_mapped(&rt->gw, ds);
> }
> - ds_put_format(&ds, " SRC ");
> - ipv6_format_mapped(&rt->src_addr, &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, " local");
> }
> - ds_put_format(&ds, "\n");
> + ds_put_format(ds, "\n");
> + }
> +}
> +
> +static void
> +ovs_router_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 *routes;
> +
> + ovs_router_show_json(&routes);
> + unixctl_command_reply_json(conn, routes);
> + } else {
> + struct ds ds = DS_EMPTY_INITIALIZER;
> +
> + ovs_router_show_text(&ds);
> + unixctl_command_reply(conn, ds_cstr(&ds));
> + ds_destroy(&ds);
> }
> - unixctl_command_reply(conn, ds_cstr(&ds));
> - ds_destroy(&ds);
> }
>
> static void
> @@ -619,12 +688,12 @@ ovs_router_init(void)
> fatal_signal_add_hook(ovs_router_flush_handler, NULL, NULL, true);
> classifier_init(&cls, NULL);
> unixctl_command_register("ovs/route/add",
> - "ip/plen output_netdev [gw] "
> + "ip/mask dev [gw] "
> "[pkt_mark=mark] [src=src_ip]",
> 2, 5, ovs_router_add, NULL);
> unixctl_command_register("ovs/route/show", "", 0, 0,
> ovs_router_show, NULL);
> - unixctl_command_register("ovs/route/del", "ip/plen "
> + unixctl_command_register("ovs/route/del", "ip/mask "
> "[pkt_mark=mark]", 1, 2, ovs_router_del,
> NULL);
> unixctl_command_register("ovs/route/lookup", "ip_addr "
> diff --git a/tests/ovs-router.at b/tests/ovs-router.at
> index b3314b3dff0d..13a38eb55055 100644
> --- a/tests/ovs-router.at
> +++ b/tests/ovs-router.at
> @@ -28,6 +28,41 @@ User: 1.1.1.0/24 dev br0 GW 2.2.2.10 SRC 2.2.2.2
> User: 1.1.2.0/24 MARK 2 dev br0 GW 2.2.2.10 SRC 2.2.2.2
> 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
> +[[
> + {
> + "is_local": true,
> + "nw_addr": "2.2.2.0",
> + "output_netdev": "br0",
> + "plen": 120,
> + "priority": 184,
> + "src_addr": "2.2.2.2"},
> + {
> + "gw": "2.2.2.10",
> + "is_local": false,
> + "nw_addr": "1.1.1.0",
> + "output_netdev": "br0",
> + "plen": 120,
> + "priority": 152,
> + "src_addr": "2.2.2.2"},
> + {
> + "gw": "2.2.2.10",
> + "is_local": false,
> + "mark": 2,
> + "nw_addr": "1.1.2.0",
> + "output_netdev": "br0",
> + "plen": 120,
> + "priority": 152,
> + "src_addr": "2.2.2.2"},
> + {
> + "is_local": false,
> + "mark": 1,
> + "nw_addr": "2.2.2.3",
> + "output_netdev": "br0",
> + "plen": 128,
> + "priority": 160,
> + "src_addr": "2.2.2.2"}]]
> +])
sorry missed the update of the test. i'll send v3.
> OVS_VSWITCHD_STOP
> AT_CLEANUP
>
_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev