The legacy ethtool prints an error message and returns 1 if no features
were changed as requested. Port this behavior to ethtool-netlink.
req_mask is compared to wanted_mask to detect if any feature was
changed. If these masks are equal, it means that the kernel hasn't
changed anything, and all bits got to wanted.

Signed-off-by: Maxim Mikityanskiy <maxi...@mellanox.com>
---
 netlink/features.c | 25 ++++++++++++++++++-------
 1 file changed, 18 insertions(+), 7 deletions(-)

diff --git a/netlink/features.c b/netlink/features.c
index 133529d..4f63fa2 100644
--- a/netlink/features.c
+++ b/netlink/features.c
@@ -378,7 +378,7 @@ err:
        return ret;
 }
 
-static void show_feature_changes(struct nl_context *nlctx,
+static bool show_feature_changes(struct nl_context *nlctx,
                                 const struct nlattr *const *tb)
 {
        struct sfeatures_context *sfctx = nlctx->cmd_private;
@@ -388,8 +388,8 @@ static void show_feature_changes(struct nl_context *nlctx,
        const uint32_t *wanted_val;
        const uint32_t *active_val;
        unsigned int count, words;
+       bool any_changed, diff;
        unsigned int i;
-       bool diff;
        int ret;
 
        feature_names = global_stringset(ETH_SS_FEATURES, nlctx->ethnl_socket);
@@ -411,12 +411,20 @@ static void show_feature_changes(struct nl_context *nlctx,
        if (!wanted_val || !wanted_mask || !active_val || !active_mask)
                goto err;
 
+       any_changed = false;
        diff = false;
-       for (i = 0; i < words; i++)
+       for (i = 0; i < words; i++) {
+               if (wanted_mask[i] != sfctx->req_mask[i])
+                       any_changed = true;
                if (wanted_mask[i] || (active_mask[i] & ~sfctx->req_mask[i]))
                        diff = true;
+       }
+       if (!any_changed) {
+               fprintf(stderr, "Could not change any device features\n");
+               nlctx->exit_code = 1;
+       }
        if (!diff)
-               return;
+               return any_changed;
 
        /* result is not exactly as requested, show differences */
        printf("Actual changes:\n");
@@ -442,9 +450,10 @@ static void show_feature_changes(struct nl_context *nlctx,
                fputc('\n', stdout);
        }
 
-       return;
+       return any_changed;
 err:
        fprintf(stderr, "malformed diff info from kernel\n");
+       return false;
 }
 
 int sfeatures_reply_cb(const struct nlmsghdr *nlhdr, void *data)
@@ -471,8 +480,10 @@ int sfeatures_reply_cb(const struct nlmsghdr *nlhdr, void 
*data)
                return MNL_CB_OK;
        }
 
-       show_feature_changes(nlctx, tb);
-       return MNL_CB_OK;
+       if (show_feature_changes(nlctx, tb))
+               return MNL_CB_OK;
+       else
+               return MNL_CB_ERROR;
 }
 
 int nl_sfeatures(struct cmd_context *ctx)
-- 
2.21.0

Reply via email to