On 16/05/2025 11:44, Eelco Chaudron wrote:
> 
> 
> On 5 May 2025, at 10:46, 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.
>>
>> An example json output would be:
>>
>>   ovs-appctl --format json --pretty ovs/route/show
>>   [
>>     {
>>       "dst": "::1",
>>       "local": false,
>>       "nexthops": [
>>         {
>>           "dev": "lo"}],
>>       "prefix": 128,
>>       "prefsrc": "::1",
>>       "priority": 128,
>>       "user": false},
>>     {
>>       "dst": "10.237.157.103",
>>       "local": true,
>>       "nexthops": [
>>         {
>>           "dev": "eth1"}],
>>       "prefix": 32,
>>       "prefsrc": "10.237.157.103",
>>       "priority": 192,
>>       "user": false},
>>     {
>>       "dst": "fe80::42:67ff:fe28:188",
>>       "local": true,
>>       "nexthops": [
>>         {
>>           "dev": "docker0"}],
>>       "prefix": 128,
>>       "prefsrc": "fe80::42:67ff:fe28:188",
>>       "priority": 192,
>>       "user": false},
>>     {
>>       "dst": "0.0.0.0",
>>       "local": false,
>>       "nexthops": [
>>         {
>>           "dev": "eth0",
>>           "gateway": "192.168.121.1"}],
>>       "prefix": 0,
>>       "prefsrc": "192.168.121.203",
>>       "priority": 96,
>>       "user": false}]
>>
>> Signed-off-by: Dima Chumak <dchu...@nvidia.com>
>> Reviewed-by: Roi Dayan <r...@nvidia.com>
> 
> Hi Roi/Dima,
> 
> I reviewed the changes, and they look good to me. However, when reviewing the 
> entire patch, I noticed that the route table is RCU-based, so the size could, 
> in theory, change while looping through it. To avoid writing too many entries 
> to the JSON array, we need to add some protection. This is the change I 
> suggest:
> 
> diff --git a/lib/ovs-router.c b/lib/ovs-router.c
> index 5e6949ef3..fabde1b3e 100644
> --- a/lib/ovs-router.c
> +++ b/lib/ovs-router.c
> @@ -512,16 +512,17 @@ ovs_router_del(struct unixctl_conn *conn, int argc 
> OVS_UNUSED,
>  static void
>  ovs_router_show_json(struct json **routes)
>  {
> +    int n_rules = classifier_count(&cls);
>      struct json **json_entries = NULL;
>      struct ovs_router_entry *rt;
>      struct ds ds;
>      int i = 0;
> 
> -    if (!cls.n_rules) {
> +    if (!n_rules) {
>          goto out;
>      }
> 
> -    json_entries = xmalloc(cls.n_rules * sizeof *json_entries);
> +    json_entries = xmalloc(n_rules * sizeof *json_entries);
>      ds_init(&ds);
> 
>      CLS_FOR_EACH (rt, cr, &cls) {
> @@ -530,6 +531,10 @@ ovs_router_show_json(struct json **routes)
>          struct json *nh = json_object_create();
>          uint8_t plen = rt->plen;
> 
> +        if (i >= n_rules) {
> +            break;
> +        }
> +
>          if (IN6_IS_ADDR_V4MAPPED(&rt->nw_addr)) {
>              plen -= 96;
>          }
> 
> Let me know what you think. If you agree, I can wrap this in when applying 
> the patch. I’ll probably do this by the end of next week to give others a 
> chance to review.
> 
> Cheers,
> 
> Eelco
> 

Hi, sure. this looks good. thanks.

>> ---
>>
>> Notes:
>>     v5
>>     - Rename 'prefix_length' to 'prefix'.
>>     - Normalize prefix for ipv4.
>>     - Add nexthops json object even though its a single entry.
>>
>>     v4
>>     - Fix memleak by moving ds_init() call to once outside the loop.
>>     - Update 'prefix_length' key.
>>     - Rename 'gw' to 'gateway' key.
>>
>>     v3
>>     - Update ovs-router.at test.
>>     - Update example output in the commit msg.
>>
>>     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    | 114 ++++++++++++++++++++++++++++++++++++--------
>>  tests/ovs-router.at |  47 ++++++++++++++++++
>>  2 files changed, 141 insertions(+), 20 deletions(-)
>>
>> diff --git a/lib/ovs-router.c b/lib/ovs-router.c
>> index d955a3a543b8..5e6949ef3acb 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"
>> @@ -509,44 +510,117 @@ 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);
>> +    ds_init(&ds);
>> +
>> +    CLS_FOR_EACH (rt, cr, &cls) {
>> +        bool user = rt->priority != rt->plen && !rt->local;
>> +        struct json *json = json_object_create();
>> +        struct json *nh = json_object_create();
>> +        uint8_t plen = rt->plen;
>> +
>> +        if (IN6_IS_ADDR_V4MAPPED(&rt->nw_addr)) {
>> +            plen -= 96;
>> +        }
>> +
>> +        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, "prefix", json_integer_create(plen));
>> +        json_object_put_string(nh, "dev", rt->output_netdev);
>> +
>> +        ipv6_format_mapped(&rt->nw_addr, &ds);
>> +        json_object_put_string(json, "dst", ds_cstr_ro(&ds));
>> +        ds_clear(&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)) {
>> +            ipv6_format_mapped(&rt->gw, &ds);
>> +            json_object_put_string(nh, "gateway", ds_cstr_ro(&ds));
>> +            ds_clear(&ds);
>> +        }
>> +
>> +        json_object_put(json, "nexthops", json_array_create_1(nh));
>> +        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,7 +693,7 @@ 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/plen dev [gw] "
>>                                   "[pkt_mark=mark] [src=src_ip]",
>>                                   2, 5, ovs_router_add, NULL);
>>          unixctl_command_register("ovs/route/show", "", 0, 0,
>> diff --git a/tests/ovs-router.at b/tests/ovs-router.at
>> index b3314b3dff0d..641b780a582a 100644
>> --- a/tests/ovs-router.at
>> +++ b/tests/ovs-router.at
>> @@ -28,6 +28,53 @@ 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
>> +[[
>> +  {
>> +    "dst": "2.2.2.0",
>> +    "local": true,
>> +    "nexthops": [
>> +      {
>> +        "dev": "br0"}],
>> +    "prefix": 24,
>> +    "prefsrc": "2.2.2.2",
>> +    "priority": 184,
>> +    "user": false},
>> +  {
>> +    "dst": "1.1.1.0",
>> +    "local": false,
>> +    "nexthops": [
>> +      {
>> +        "dev": "br0",
>> +        "gateway": "2.2.2.10"}],
>> +    "prefix": 24,
>> +    "prefsrc": "2.2.2.2",
>> +    "priority": 152,
>> +    "user": true},
>> +  {
>> +    "dst": "1.1.2.0",
>> +    "local": false,
>> +    "mark": 2,
>> +    "nexthops": [
>> +      {
>> +        "dev": "br0",
>> +        "gateway": "2.2.2.10"}],
>> +    "prefix": 24,
>> +    "prefsrc": "2.2.2.2",
>> +    "priority": 152,
>> +    "user": true},
>> +  {
>> +    "dst": "2.2.2.3",
>> +    "local": false,
>> +    "mark": 1,
>> +    "nexthops": [
>> +      {
>> +        "dev": "br0"}],
>> +    "prefix": 32,
>> +    "prefsrc": "2.2.2.2",
>> +    "priority": 160,
>> +    "user": true}]]
>> +])
>>  OVS_VSWITCHD_STOP
>>  AT_CLEANUP
>>
>> -- 
>> 2.21.0
> 

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to