So far, if the filter was too large to fit in the allocated skb, the
kernel did not return any error and stopped dumping. Modify the dumper
so that it returns -EMSGSIZE when a filter fails to dump and it is the
first filter in the skb. If we are not first, we will get a next chance
with more room.

I understand this is pretty near to being an API change, but the
original design (silent truncation) can be considered a bug.

Note: The error case can happen pretty easily if you create a filter
with 32 actions and have 4kb pages. Also recent versions of iproute try
to be clever with their buffer allocation size, which in turn leads to

Signed-off-by: Roman Kapl <c...@rkapl.cz>
---
v1 -> v2: add the "progress" comment, fixed error name in commit message.

I've looked at other dumpers in rtnetnlink, there are various ways to handle
that. For example rtnl_stats_dump has:
    WARN_ON((err == -EMSGSIZE) && (skb->len == 0));
rtnl_dump_ifinfo has the same logic I am proposing:
    if (err < 0) 
        if (skb->len) goto out;
        goto out_err;
Other functions handle the error in the "wrong" way (= what we currently do).
Although it might be OK if there is no array in what they return. I have not
tested the behavior, since the only way I found was to have a device with many
VFs.

 net/sched/cls_api.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index f21610c5da1a..92e9308bb920 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -1399,13 +1399,18 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct 
netlink_callback *cb)
                    nla_get_u32(tca[TCA_CHAIN]) != chain->index)
                        continue;
                if (!tcf_chain_dump(chain, q, parent, skb, cb,
-                                   index_start, &index))
+                                   index_start, &index)) {
+                       err = -EMSGSIZE;
                        break;
+               }
        }
 
        cb->args[0] = index;
 
 out:
+       /* If we did no progress, the error (EMSGSIZE) is real */
+       if (skb->len == 0 && err)
+               return err;
        return skb->len;
 }
 
-- 
2.16.1

Reply via email to