On 21 Apr 2025, at 9:08, Roi Dayan wrote:

> On 17/04/2025 13:30, Eelco Chaudron wrote:
>>
>>
>> On 7 Apr 2025, at 12:23, Roi Dayan via dev 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. An example would be:
>>>
>>>   ovs-appctl --format json --pretty ovs/route/show
>>>   [
>>>     {
>>>       "is_local": false,
>>>       "nw_addr": "::1",
>>>       "output_netdev": "lo",
>>>       "plen": 128,
>>>       "priority": 128,
>>>       "src_addr": "::1"},
>>>     {
>>>       "is_local": true,
>>>       "nw_addr": "10.237.157.103",
>>>       "output_netdev": "eth1",
>>>       "plen": 128,
>>>       "priority": 192,
>>>       "src_addr": "10.237.157.103"},
>>>     {
>>>       "is_local": true,
>>>       "nw_addr": "fe80::42:67ff:fe28:188",
>>>       "output_netdev": "docker0",
>>>       "plen": 128,
>>>       "priority": 192,
>>>       "src_addr": "fe80::42:67ff:fe28:188"},
>>>     {
>>>       "gw": "192.168.121.1",
>>>       "is_local": false,
>>>       "nw_addr": "0.0.0.0",
>>>       "output_netdev": "eth0",
>>>       "plen": 96,
>>>       "priority": 96,
>>>       "src_addr": "192.168.121.203"}]
>>>
>>> Signed-off-by: Dima Chumak <dchu...@nvidia.com>
>>> Reviewed-by: Roi Dayan <r...@nvidia.com>
>>
>> Hi Dima, thanks for the patch. See some comments below.
>>
>> Cheers,
>>
>> Eelco
>>
>>> ---
>>>  lib/ovs-router.c    | 103 ++++++++++++++++++++++++++++++++++++--------
>>>  tests/ovs-router.at |  35 +++++++++++++++
>>>  2 files changed, 119 insertions(+), 19 deletions(-)
>>>
>>> diff --git a/lib/ovs-router.c b/lib/ovs-router.c
>>> index d955a3a543b8..eb04edece9cb 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,108 @@ 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;
>>> +    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) {
>>> +        struct json *json = json_object_create();
>>> +        struct ds ds;
>>> +
>>
>> In the text output, we show if it’s a user-configured entry; Maybe we should 
>> do the same for json? Not sure about the name, but something like:
>>
>> json_object_put(json, “user_configured”, json_boolean_create((rt->priority 
>> != rt->plen && !rt->local)));
>
> added "user".
>>
>>> +        json_object_put(json, "is_local", json_boolean_create(rt->local));
>
> ack.
>
>>
>> I would keep the name "local" as looking at the existing code, we don’t seem 
>> to add prefixes for booleans, just the variable name.
>>
>>> +        json_object_put(json, "priority", 
>>> json_integer_create(rt->priority));
>>> +        json_object_put(json, "plen", json_integer_create(rt->plen));
>>
>> In the text code the plen is normalized based on the network address type. 
>> Should we do the same here?
>> Also, the plen is the network mask, so should we add it to the nw_addr 
>> instead?
>>
>
> The purpose for json here is for scripts/sw and not user. so "raw" data will 
> be easier to handle
> instead of parsing the string of ip/mask in the script later.

Then I would at least export it as ‘mask’ so it’s clear what we’re talking 
about.

>>> +        json_object_put_string(json, "output_netdev", rt->output_netdev);
>>> +
>>> +        ds_init(&ds);
>>> +        ipv6_format_mapped(&rt->nw_addr, &ds);
>>> +        json_object_put_string(json, "nw_addr", ds_cstr_ro(&ds));
>>> +        ds_destroy(&ds);
>>> +
>>> +        ds_init(&ds);
>>> +        ipv6_format_mapped(&rt->src_addr, &ds);
>>> +        json_object_put_string(json, "src_addr", ds_cstr_ro(&ds));
>>> +        ds_destroy(&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_destroy(&ds);
>>> +        }
>>> +
>>
>> Rather than calling ds_destroy() each time, consider calling ds_clear() 
>> instead, and only call ds_destroy() once at the end. This avoids repeated 
>> malloc/free calls. Preferably move it outside the CLS_FOR_EACH() loop.
>>
>
> ack.
>
>>> +        json_entries[i++] = json;
>>> +    }
>>> +
>>> +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
>>> 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"},
>>
>> On json naming, should we align a bit more to the ‘ip [—6] -json’ route show 
>> output?
>>
>> nw_addr -> dst
>> src_addr -> prefsrc
>> output_netlink -> dev
>>
>> Maybe we should also be prepared for multiple next hops, so if a gw is 
>> present, we should do something like the below (for gateway and dev), so we 
>> do not have to change the format later;
>>
>>   {
>>     "dst": "default",
>>     "protocol": "ra",
>>     "metric": 100,
>>     "flags": [],
>>     "pref": "medium",
>>     "nexthops": [
>>       {
>>         "gateway": "fe80::4a5a:d01:9431:5120",
>>         "dev": "eno8303",
>>         "weight": 1,
>>         "flags": []
>>       },
>>       {
>>         "gateway": "fe80::4a5a:d01:942f:2b20",
>>         "dev": "eno8303",
>>         "weight": 1,
>>         "flags": []
>>       }
>>     ]
>>   },
>>
>>
>
> It's possible but the help string for ovs/route/add uses the attribute naming.
>
>   ovs/route/add           ip/plen output_netdev [gw] [pkt_mark=mark] 
> [src=src_ip]
>
> So this was done to be consistent. do you still prefer to update ?
> if so, do we need to udpate the help print? output_netdev to dev, ip to 
> nw_addr, src_ip to src_addr..

I guess it’s only two parameters that will change, which I think is fine. So it 
will become:

-ovs/route/add           ip/plen output_netdev [gw] [pkt_mark=mark] [src=src_ip]
+ovs/route/add           ip/mask dev           [gw] [pkt_mark=mark] [src=src_ip]

>>> +  {
>>> +    "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"}]]
>>> +])
>>>  OVS_VSWITCHD_STOP
>>>  AT_CLEANUP
>>>
>>> -- 
>>> 2.21.0
>>>
>>> _______________________________________________
>>> dev mailing list
>>> d...@openvswitch.org
>>> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>>

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

Reply via email to