netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH net-next 0/4] tools: ynl: add --dbg-small-recv for easier kernel testing
@ 2024-03-01 23:05 Jakub Kicinski
  2024-03-01 23:05 ` [PATCH net-next 1/4] tools: ynl: move the new line in NlMsg __repr__ Jakub Kicinski
                   ` (3 more replies)
  0 siblings, 4 replies; 14+ messages in thread
From: Jakub Kicinski @ 2024-03-01 23:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, donald.hunter, Jakub Kicinski

When testing netlink dumps I usually hack some user space up
to constrain its user space buffer size (iproute2, ethtool or ynl).
Netlink will try to fill the messages up, so since these apps use
large buffers by default, the dumps are rarely fragmented.

I was hoping to figure out a way to create a selftest for dump
testing, but so far I have no idea how to do that in a useful
and generic way.

Until someone does that, make manual dump testing easier with YNL.
Create a special option for limiting the buffer size, so I don't
have to make the same edits each time, and maybe others will benefit,
too :)

Example:

  $ ./cli.py [...] --dbg-small-recv >/dev/null
  Recv: read 3712 bytes, 29 messages
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
    [...]
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
  Recv: read 3968 bytes, 31 messages
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
    [...]
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
  Recv: read 532 bytes, 5 messages
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
    [...]
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
     nl_len = 20 (4) nl_flags = 0x2 nl_type = 3

Now let's make the DONE not fit in the last message:

  $ ./cli.py [...] --dbg-small-recv 4499 >/dev/null
  Recv: read 3712 bytes, 29 messages
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
    [...]
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
  Recv: read 4480 bytes, 35 messages
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
    [...]
     nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
  Recv: read 20 bytes, 1 messages
     nl_len = 20 (4) nl_flags = 0x2 nl_type = 3


A real test would also have to check the messages are complete
and not duplicated. That part has to be done manually right now.

Note that the first message is always conservatively sized by the kernel.
Still, I think this is good enough to be useful.

Jakub Kicinski (4):
  tools: ynl: move the new line in NlMsg __repr__
  tools: ynl: allow setting recv() size
  tools: ynl: support debug printing messages
  tools: ynl: add --dbg-small-recv for easier kernel testing

 tools/net/ynl/cli.py     |  7 ++++++-
 tools/net/ynl/lib/ynl.py | 42 ++++++++++++++++++++++++++++++++++------
 2 files changed, 42 insertions(+), 7 deletions(-)

-- 
2.44.0


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH net-next 1/4] tools: ynl: move the new line in NlMsg __repr__
  2024-03-01 23:05 [PATCH net-next 0/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
@ 2024-03-01 23:05 ` Jakub Kicinski
  2024-03-04 11:08   ` Donald Hunter
  2024-03-01 23:05 ` [PATCH net-next 2/4] tools: ynl: allow setting recv() size Jakub Kicinski
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 14+ messages in thread
From: Jakub Kicinski @ 2024-03-01 23:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, donald.hunter, Jakub Kicinski

We add the new line even if message has no error or extack,
which leads to print(nl_msg) ending with two new lines.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/lib/ynl.py | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index ac55aa5a3083..92ade9105f31 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -213,11 +213,11 @@ from .nlspec import SpecFamily
         return self.nl_type
 
     def __repr__(self):
-        msg = f"nl_len = {self.nl_len} ({len(self.raw)}) nl_flags = 0x{self.nl_flags:x} nl_type = {self.nl_type}\n"
+        msg = f"nl_len = {self.nl_len} ({len(self.raw)}) nl_flags = 0x{self.nl_flags:x} nl_type = {self.nl_type}"
         if self.error:
-            msg += '\terror: ' + str(self.error)
+            msg += '\n\terror: ' + str(self.error)
         if self.extack:
-            msg += '\textack: ' + repr(self.extack)
+            msg += '\n\textack: ' + repr(self.extack)
         return msg
 
 
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH net-next 2/4] tools: ynl: allow setting recv() size
  2024-03-01 23:05 [PATCH net-next 0/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
  2024-03-01 23:05 ` [PATCH net-next 1/4] tools: ynl: move the new line in NlMsg __repr__ Jakub Kicinski
@ 2024-03-01 23:05 ` Jakub Kicinski
  2024-03-04 11:38   ` Donald Hunter
  2024-03-04 13:38   ` Donald Hunter
  2024-03-01 23:05 ` [PATCH net-next 3/4] tools: ynl: support debug printing messages Jakub Kicinski
  2024-03-01 23:05 ` [PATCH net-next 4/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
  3 siblings, 2 replies; 14+ messages in thread
From: Jakub Kicinski @ 2024-03-01 23:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, donald.hunter, Jakub Kicinski

Make the size of the buffer we use for recv() configurable.
The details of the buffer sizing in netlink are somewhat
arcane, we could spend a lot of time polishing this API.
Let's just leave some hopefully helpful comments for now.
This is a for-developers-only feature, anyway.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/lib/ynl.py | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index 92ade9105f31..bc5a526dbb99 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -84,6 +84,10 @@ from .nlspec import SpecFamily
     return f"Netlink error: {os.strerror(-self.nl_msg.error)}\n{self.nl_msg}"
 
 
+class ConfigError(Exception):
+    pass
+
+
 class NlAttr:
     ScalarFormat = namedtuple('ScalarFormat', ['native', 'big', 'little'])
     type_formats = {
@@ -400,7 +404,8 @@ genl_family_name_to_id = None
 
 
 class YnlFamily(SpecFamily):
-    def __init__(self, def_path, schema=None, process_unknown=False):
+    def __init__(self, def_path, schema=None, process_unknown=False,
+                 recv_size=131072):
         super().__init__(def_path, schema)
 
         self.include_raw = False
@@ -423,6 +428,16 @@ genl_family_name_to_id = None
         self.async_msg_ids = set()
         self.async_msg_queue = []
 
+        # Note that netlink will use conservative (min) message size for
+        # the first dump recv() on the socket, our setting will only matter
+        # from the second recv() on.
+        self._recv_size = recv_size
+        # Netlink will always allocate at least PAGE_SIZE - sizeof(skb_shinfo)
+        # for a message, so smaller receive sizes will lead to truncation.
+        # Note that the min size for other families may be larger than 4k!
+        if self._recv_size < 4000:
+            raise ConfigError()
+
         for msg in self.msgs.values():
             if msg.is_async:
                 self.async_msg_ids.add(msg.rsp_value)
@@ -799,7 +814,7 @@ genl_family_name_to_id = None
     def check_ntf(self):
         while True:
             try:
-                reply = self.sock.recv(128 * 1024, socket.MSG_DONTWAIT)
+                reply = self.sock.recv(self._recv_size, socket.MSG_DONTWAIT)
             except BlockingIOError:
                 return
 
@@ -854,7 +869,7 @@ genl_family_name_to_id = None
         done = False
         rsp = []
         while not done:
-            reply = self.sock.recv(128 * 1024)
+            reply = self.sock.recv(self._recv_size)
             nms = NlMsgs(reply, attr_space=op.attr_set)
             for nl_msg in nms:
                 if nl_msg.extack:
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH net-next 3/4] tools: ynl: support debug printing messages
  2024-03-01 23:05 [PATCH net-next 0/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
  2024-03-01 23:05 ` [PATCH net-next 1/4] tools: ynl: move the new line in NlMsg __repr__ Jakub Kicinski
  2024-03-01 23:05 ` [PATCH net-next 2/4] tools: ynl: allow setting recv() size Jakub Kicinski
@ 2024-03-01 23:05 ` Jakub Kicinski
  2024-03-04 11:34   ` Donald Hunter
  2024-03-01 23:05 ` [PATCH net-next 4/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
  3 siblings, 1 reply; 14+ messages in thread
From: Jakub Kicinski @ 2024-03-01 23:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, donald.hunter, Jakub Kicinski

For manual debug, allow printing the netlink level messages
to stderr.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/lib/ynl.py | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
index bc5a526dbb99..2462228dacc1 100644
--- a/tools/net/ynl/lib/ynl.py
+++ b/tools/net/ynl/lib/ynl.py
@@ -7,6 +7,7 @@ import random
 import socket
 import struct
 from struct import Struct
+import sys
 import yaml
 import ipaddress
 import uuid
@@ -428,6 +429,7 @@ genl_family_name_to_id = None
         self.async_msg_ids = set()
         self.async_msg_queue = []
 
+        self._recv_dbg = False
         # Note that netlink will use conservative (min) message size for
         # the first dump recv() on the socket, our setting will only matter
         # from the second recv() on.
@@ -453,6 +455,17 @@ genl_family_name_to_id = None
         self.sock.setsockopt(Netlink.SOL_NETLINK, Netlink.NETLINK_ADD_MEMBERSHIP,
                              mcast_id)
 
+    def set_recv_dbg(self, enabled):
+        self._recv_dbg = enabled
+
+    def _recv_dbg_print(self, reply, nl_msgs):
+        if not self._recv_dbg:
+            return
+        print("Recv: read", len(reply), "bytes,",
+              len(nl_msgs.msgs), "messages", file=sys.stderr)
+        for nl_msg in nl_msgs:
+            print("  ", nl_msg, file=sys.stderr)
+
     def _encode_enum(self, attr_spec, value):
         enum = self.consts[attr_spec['enum']]
         if enum.type == 'flags' or attr_spec.get('enum-as-flags', False):
@@ -819,6 +832,7 @@ genl_family_name_to_id = None
                 return
 
             nms = NlMsgs(reply)
+            self._recv_dbg_print(reply, nms)
             for nl_msg in nms:
                 if nl_msg.error:
                     print("Netlink error in ntf!?", os.strerror(-nl_msg.error))
@@ -871,6 +885,7 @@ genl_family_name_to_id = None
         while not done:
             reply = self.sock.recv(self._recv_size)
             nms = NlMsgs(reply, attr_space=op.attr_set)
+            self._recv_dbg_print(reply, nms)
             for nl_msg in nms:
                 if nl_msg.extack:
                     self._decode_extack(msg, op, nl_msg.extack)
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH net-next 4/4] tools: ynl: add --dbg-small-recv for easier kernel testing
  2024-03-01 23:05 [PATCH net-next 0/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
                   ` (2 preceding siblings ...)
  2024-03-01 23:05 ` [PATCH net-next 3/4] tools: ynl: support debug printing messages Jakub Kicinski
@ 2024-03-01 23:05 ` Jakub Kicinski
  2024-03-04 11:26   ` Donald Hunter
  3 siblings, 1 reply; 14+ messages in thread
From: Jakub Kicinski @ 2024-03-01 23:05 UTC (permalink / raw)
  To: davem; +Cc: netdev, edumazet, pabeni, jiri, donald.hunter, Jakub Kicinski

Most "production" netlink clients use large buffers to
make dump efficient, which means that handling of dump
continuation in the kernel is not very well tested.

Add an option for debugging / testing handling of dumps.
It enables printing of extra netlink-level debug and
lowers the recv() buffer size in one go. When used
without any argument (--dbg-small-recv) it picks
a very small default (4000), explicit size can be set,
too (--dbg-small-recv 5000).

Example:

$ ./cli.py [...] --dbg-small-recv
Recv: read 3712 bytes, 29 messages
   nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
 [...]
   nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
Recv: read 3968 bytes, 31 messages
   nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
 [...]
   nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
Recv: read 532 bytes, 5 messages
   nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
 [...]
   nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
   nl_len = 20 (4) nl_flags = 0x2 nl_type = 3

(the [...] are edits to shorten the commit message).

Note that the first message of the dump is sized conservatively
by the kernel.

Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 tools/net/ynl/cli.py | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py
index 0f8239979670..e8a65fbc3698 100755
--- a/tools/net/ynl/cli.py
+++ b/tools/net/ynl/cli.py
@@ -38,6 +38,8 @@ from lib import YnlFamily, Netlink
                         const=Netlink.NLM_F_APPEND)
     parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction)
     parser.add_argument('--output-json', action='store_true')
+    parser.add_argument('--dbg-small-recv', default=0, const=4000,
+                        action='store', nargs='?', type=int)
     args = parser.parse_args()
 
     def output(msg):
@@ -53,7 +55,10 @@ from lib import YnlFamily, Netlink
     if args.json_text:
         attrs = json.loads(args.json_text)
 
-    ynl = YnlFamily(args.spec, args.schema, args.process_unknown)
+    ynl = YnlFamily(args.spec, args.schema, args.process_unknown,
+                    recv_size=args.dbg_small_recv)
+    if args.dbg_small_recv:
+        ynl.set_recv_dbg(True)
 
     if args.ntf:
         ynl.ntf_subscribe(args.ntf)
-- 
2.44.0


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 1/4] tools: ynl: move the new line in NlMsg __repr__
  2024-03-01 23:05 ` [PATCH net-next 1/4] tools: ynl: move the new line in NlMsg __repr__ Jakub Kicinski
@ 2024-03-04 11:08   ` Donald Hunter
  0 siblings, 0 replies; 14+ messages in thread
From: Donald Hunter @ 2024-03-04 11:08 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

Jakub Kicinski <kuba@kernel.org> writes:

> We add the new line even if message has no error or extack,
> which leads to print(nl_msg) ending with two new lines.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Reviewed-by: Donald Hunter <donald.hunter@gmail.com>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 4/4] tools: ynl: add --dbg-small-recv for easier kernel testing
  2024-03-01 23:05 ` [PATCH net-next 4/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
@ 2024-03-04 11:26   ` Donald Hunter
  2024-03-04 14:59     ` Jakub Kicinski
  0 siblings, 1 reply; 14+ messages in thread
From: Donald Hunter @ 2024-03-04 11:26 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

Jakub Kicinski <kuba@kernel.org> writes:

> Most "production" netlink clients use large buffers to
> make dump efficient, which means that handling of dump
> continuation in the kernel is not very well tested.
>
> Add an option for debugging / testing handling of dumps.
> It enables printing of extra netlink-level debug and
> lowers the recv() buffer size in one go. When used
> without any argument (--dbg-small-recv) it picks
> a very small default (4000), explicit size can be set,
> too (--dbg-small-recv 5000).
>
> Example:
>
> $ ./cli.py [...] --dbg-small-recv
> Recv: read 3712 bytes, 29 messages
>    nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
>  [...]
>    nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
> Recv: read 3968 bytes, 31 messages
>    nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
>  [...]
>    nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
> Recv: read 532 bytes, 5 messages
>    nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
>  [...]
>    nl_len = 128 (112) nl_flags = 0x0 nl_type = 19
>    nl_len = 20 (4) nl_flags = 0x2 nl_type = 3
>
> (the [...] are edits to shorten the commit message).
>
> Note that the first message of the dump is sized conservatively
> by the kernel.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  tools/net/ynl/cli.py | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/tools/net/ynl/cli.py b/tools/net/ynl/cli.py
> index 0f8239979670..e8a65fbc3698 100755
> --- a/tools/net/ynl/cli.py
> +++ b/tools/net/ynl/cli.py
> @@ -38,6 +38,8 @@ from lib import YnlFamily, Netlink
>                          const=Netlink.NLM_F_APPEND)
>      parser.add_argument('--process-unknown', action=argparse.BooleanOptionalAction)
>      parser.add_argument('--output-json', action='store_true')
> +    parser.add_argument('--dbg-small-recv', default=0, const=4000,
> +                        action='store', nargs='?', type=int)

This breaks ynl if you don't use '--dbg-small-recv', it passes 0 which
fails the _recv_size check.

>      args = parser.parse_args()
>  
>      def output(msg):
> @@ -53,7 +55,10 @@ from lib import YnlFamily, Netlink
>      if args.json_text:
>          attrs = json.loads(args.json_text)
>  
> -    ynl = YnlFamily(args.spec, args.schema, args.process_unknown)
> +    ynl = YnlFamily(args.spec, args.schema, args.process_unknown,
> +                    recv_size=args.dbg_small_recv)
> +    if args.dbg_small_recv:
> +        ynl.set_recv_dbg(True)
>  
>      if args.ntf:
>          ynl.ntf_subscribe(args.ntf)

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 3/4] tools: ynl: support debug printing messages
  2024-03-01 23:05 ` [PATCH net-next 3/4] tools: ynl: support debug printing messages Jakub Kicinski
@ 2024-03-04 11:34   ` Donald Hunter
  0 siblings, 0 replies; 14+ messages in thread
From: Donald Hunter @ 2024-03-04 11:34 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

Jakub Kicinski <kuba@kernel.org> writes:

> For manual debug, allow printing the netlink level messages
> to stderr.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>

Reviewed-by: Donald Hunter <donald.hunter@gmail.com>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 2/4] tools: ynl: allow setting recv() size
  2024-03-01 23:05 ` [PATCH net-next 2/4] tools: ynl: allow setting recv() size Jakub Kicinski
@ 2024-03-04 11:38   ` Donald Hunter
  2024-03-04 13:38   ` Donald Hunter
  1 sibling, 0 replies; 14+ messages in thread
From: Donald Hunter @ 2024-03-04 11:38 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

Jakub Kicinski <kuba@kernel.org> writes:

> Make the size of the buffer we use for recv() configurable.
> The details of the buffer sizing in netlink are somewhat
> arcane, we could spend a lot of time polishing this API.
> Let's just leave some hopefully helpful comments for now.
> This is a for-developers-only feature, anyway.
>
> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
> ---
>  tools/net/ynl/lib/ynl.py | 21 ++++++++++++++++++---
>  1 file changed, 18 insertions(+), 3 deletions(-)
>
> diff --git a/tools/net/ynl/lib/ynl.py b/tools/net/ynl/lib/ynl.py
> index 92ade9105f31..bc5a526dbb99 100644
> --- a/tools/net/ynl/lib/ynl.py
> +++ b/tools/net/ynl/lib/ynl.py
> @@ -84,6 +84,10 @@ from .nlspec import SpecFamily
>      return f"Netlink error: {os.strerror(-self.nl_msg.error)}\n{self.nl_msg}"
>  
>  
> +class ConfigError(Exception):
> +    pass
> +
> +
>  class NlAttr:
>      ScalarFormat = namedtuple('ScalarFormat', ['native', 'big', 'little'])
>      type_formats = {
> @@ -400,7 +404,8 @@ genl_family_name_to_id = None
>  
>  
>  class YnlFamily(SpecFamily):
> -    def __init__(self, def_path, schema=None, process_unknown=False):
> +    def __init__(self, def_path, schema=None, process_unknown=False,
> +                 recv_size=131072):
>          super().__init__(def_path, schema)
>  
>          self.include_raw = False
> @@ -423,6 +428,16 @@ genl_family_name_to_id = None
>          self.async_msg_ids = set()
>          self.async_msg_queue = []
>  
> +        # Note that netlink will use conservative (min) message size for
> +        # the first dump recv() on the socket, our setting will only matter
> +        # from the second recv() on.
> +        self._recv_size = recv_size
> +        # Netlink will always allocate at least PAGE_SIZE - sizeof(skb_shinfo)
> +        # for a message, so smaller receive sizes will lead to truncation.
> +        # Note that the min size for other families may be larger than 4k!
> +        if self._recv_size < 4000:
> +            raise ConfigError()

Nit: You've added this between the declaration of async_msg_ids and
where it gets populated. Otherwise LGTM.

> +
>          for msg in self.msgs.values():
>              if msg.is_async:
>                  self.async_msg_ids.add(msg.rsp_value)
> @@ -799,7 +814,7 @@ genl_family_name_to_id = None
>      def check_ntf(self):
>          while True:
>              try:
> -                reply = self.sock.recv(128 * 1024, socket.MSG_DONTWAIT)
> +                reply = self.sock.recv(self._recv_size, socket.MSG_DONTWAIT)
>              except BlockingIOError:
>                  return
>  
> @@ -854,7 +869,7 @@ genl_family_name_to_id = None
>          done = False
>          rsp = []
>          while not done:
> -            reply = self.sock.recv(128 * 1024)
> +            reply = self.sock.recv(self._recv_size)
>              nms = NlMsgs(reply, attr_space=op.attr_set)
>              for nl_msg in nms:
>                  if nl_msg.extack:

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 2/4] tools: ynl: allow setting recv() size
  2024-03-01 23:05 ` [PATCH net-next 2/4] tools: ynl: allow setting recv() size Jakub Kicinski
  2024-03-04 11:38   ` Donald Hunter
@ 2024-03-04 13:38   ` Donald Hunter
  2024-03-04 14:58     ` Jakub Kicinski
  1 sibling, 1 reply; 14+ messages in thread
From: Donald Hunter @ 2024-03-04 13:38 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

On Fri, 1 Mar 2024 at 23:05, Jakub Kicinski <kuba@kernel.org> wrote:
>
>  class YnlFamily(SpecFamily):
> -    def __init__(self, def_path, schema=None, process_unknown=False):
> +    def __init__(self, def_path, schema=None, process_unknown=False,
> +                 recv_size=131072):

An aside: what is the reason for choosing a 128k receive buffer? If I
remember correctly, netlink messages are capped at 32k.

>          super().__init__(def_path, schema)
>
>          self.include_raw = False
> @@ -423,6 +428,16 @@ genl_family_name_to_id = None
>          self.async_msg_ids = set()
>          self.async_msg_queue = []
>
> +        # Note that netlink will use conservative (min) message size for
> +        # the first dump recv() on the socket, our setting will only matter

I'm curious, why does it behave like this?

> +        # from the second recv() on.
> +        self._recv_size = recv_size

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 2/4] tools: ynl: allow setting recv() size
  2024-03-04 13:38   ` Donald Hunter
@ 2024-03-04 14:58     ` Jakub Kicinski
  2024-03-04 15:57       ` Donald Hunter
  0 siblings, 1 reply; 14+ messages in thread
From: Jakub Kicinski @ 2024-03-04 14:58 UTC (permalink / raw)
  To: Donald Hunter; +Cc: davem, netdev, edumazet, pabeni, jiri

On Mon, 4 Mar 2024 13:38:51 +0000 Donald Hunter wrote:
> >  class YnlFamily(SpecFamily):
> > -    def __init__(self, def_path, schema=None, process_unknown=False):
> > +    def __init__(self, def_path, schema=None, process_unknown=False,
> > +                 recv_size=131072):  
> 
> An aside: what is the reason for choosing a 128k receive buffer? If I
> remember correctly, netlink messages are capped at 32k.

Attributes, not messages, right? But large messages are relatively
rare, this is to make dump use fewer syscalls. Dump can give us multiple
message on each recv().

> >          super().__init__(def_path, schema)
> >
> >          self.include_raw = False
> > @@ -423,6 +428,16 @@ genl_family_name_to_id = None
> >          self.async_msg_ids = set()
> >          self.async_msg_queue = []
> >
> > +        # Note that netlink will use conservative (min) message size for
> > +        # the first dump recv() on the socket, our setting will only matter  
> 
> I'm curious, why does it behave like this?

Dump is initiated inside a send() system call, so that we can
validate arguments and return any init errors directly.
That means we don't know what buf size will be used by subsequent
recv()s when we produce the first message :(

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 4/4] tools: ynl: add --dbg-small-recv for easier kernel testing
  2024-03-04 11:26   ` Donald Hunter
@ 2024-03-04 14:59     ` Jakub Kicinski
  0 siblings, 0 replies; 14+ messages in thread
From: Jakub Kicinski @ 2024-03-04 14:59 UTC (permalink / raw)
  To: Donald Hunter; +Cc: davem, netdev, edumazet, pabeni, jiri

On Mon, 04 Mar 2024 11:26:52 +0000 Donald Hunter wrote:
> > +    parser.add_argument('--dbg-small-recv', default=0, const=4000,
> > +                        action='store', nargs='?', type=int)  
> 
> This breaks ynl if you don't use '--dbg-small-recv', it passes 0 which
> fails the _recv_size check.

Good catch, one too many refactorings..

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 2/4] tools: ynl: allow setting recv() size
  2024-03-04 14:58     ` Jakub Kicinski
@ 2024-03-04 15:57       ` Donald Hunter
  2024-03-04 16:20         ` Jakub Kicinski
  0 siblings, 1 reply; 14+ messages in thread
From: Donald Hunter @ 2024-03-04 15:57 UTC (permalink / raw)
  To: Jakub Kicinski; +Cc: davem, netdev, edumazet, pabeni, jiri

On Mon, 4 Mar 2024 at 14:58, Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Mon, 4 Mar 2024 13:38:51 +0000 Donald Hunter wrote:
> > >  class YnlFamily(SpecFamily):
> > > -    def __init__(self, def_path, schema=None, process_unknown=False):
> > > +    def __init__(self, def_path, schema=None, process_unknown=False,
> > > +                 recv_size=131072):
> >
> > An aside: what is the reason for choosing a 128k receive buffer? If I
> > remember correctly, netlink messages are capped at 32k.
>
> Attributes, not messages, right? But large messages are relatively
> rare, this is to make dump use fewer syscalls. Dump can give us multiple
> message on each recv().

I did mean messages:

https://elixir.bootlin.com/linux/latest/source/net/netlink/af_netlink.c#L1958

For rt_link I see ~21 messages per recv():

./tools/net/ynl/cli.py \
    --spec Documentation/netlink/specs/rt_link.yaml \
    --dump getlink --dbg-small-recv 131072 > /dev/null
Recv: read 3260 bytes, 2 messages
   nl_len = 1432 (1416) nl_flags = 0x2 nl_type = 16
   nl_len = 1828 (1812) nl_flags = 0x2 nl_type = 16
Recv: read 31180 bytes, 21 messages
...
Recv: read 31712 bytes, 22 messages
...

> > >          super().__init__(def_path, schema)
> > >
> > >          self.include_raw = False
> > > @@ -423,6 +428,16 @@ genl_family_name_to_id = None
> > >          self.async_msg_ids = set()
> > >          self.async_msg_queue = []
> > >
> > > +        # Note that netlink will use conservative (min) message size for
> > > +        # the first dump recv() on the socket, our setting will only matter
> >
> > I'm curious, why does it behave like this?
>
> Dump is initiated inside a send() system call, so that we can
> validate arguments and return any init errors directly.
> That means we don't know what buf size will be used by subsequent
> recv()s when we produce the first message :(

Ah, makes sense.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH net-next 2/4] tools: ynl: allow setting recv() size
  2024-03-04 15:57       ` Donald Hunter
@ 2024-03-04 16:20         ` Jakub Kicinski
  0 siblings, 0 replies; 14+ messages in thread
From: Jakub Kicinski @ 2024-03-04 16:20 UTC (permalink / raw)
  To: Donald Hunter; +Cc: davem, netdev, edumazet, pabeni, jiri

On Mon, 4 Mar 2024 15:57:57 +0000 Donald Hunter wrote:
> > Attributes, not messages, right? But large messages are relatively
> > rare, this is to make dump use fewer syscalls. Dump can give us multiple
> > message on each recv().  
> 
> I did mean messages:

That's kernel capping the allocations to 32kB, using larger allocations
is "costly" / likely to fail on production systems. Technically the
family can overrule that setting, and my recollection was that 128k or
64k was what iproute2 uses.. I could be wrong.

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2024-03-04 16:20 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-03-01 23:05 [PATCH net-next 0/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
2024-03-01 23:05 ` [PATCH net-next 1/4] tools: ynl: move the new line in NlMsg __repr__ Jakub Kicinski
2024-03-04 11:08   ` Donald Hunter
2024-03-01 23:05 ` [PATCH net-next 2/4] tools: ynl: allow setting recv() size Jakub Kicinski
2024-03-04 11:38   ` Donald Hunter
2024-03-04 13:38   ` Donald Hunter
2024-03-04 14:58     ` Jakub Kicinski
2024-03-04 15:57       ` Donald Hunter
2024-03-04 16:20         ` Jakub Kicinski
2024-03-01 23:05 ` [PATCH net-next 3/4] tools: ynl: support debug printing messages Jakub Kicinski
2024-03-04 11:34   ` Donald Hunter
2024-03-01 23:05 ` [PATCH net-next 4/4] tools: ynl: add --dbg-small-recv for easier kernel testing Jakub Kicinski
2024-03-04 11:26   ` Donald Hunter
2024-03-04 14:59     ` Jakub Kicinski

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).